Skip to content

Commit 2de3b50

Browse files
authored
Merge pull request #29 from Enapter/copilot/implement-sites-api-client
HTTP API: Implement Sites API client.
2 parents 0a2aaab + 8de5e2f commit 2de3b50

16 files changed

+389
-6
lines changed

examples/http/list_sites.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import asyncio
2+
3+
import enapter
4+
5+
6+
async def main():
7+
config = enapter.http.api.Config.from_env()
8+
async with enapter.http.api.Client(config=config) as client:
9+
async for site in client.sites.list():
10+
print(site)
11+
12+
13+
if __name__ == "__main__":
14+
asyncio.run(main())

src/enapter/cli/http/api/command.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from enapter import cli
44

55
from .device_command import DeviceCommand
6+
from .site_command import SiteCommand
67

78

89
class Command(cli.Command):
@@ -15,6 +16,7 @@ def register(parent: cli.Subparsers) -> None:
1516
subparsers = parser.add_subparsers(dest="http_api_command", required=True)
1617
for command in [
1718
DeviceCommand,
19+
SiteCommand,
1820
]:
1921
command.register(subparsers)
2022

@@ -23,5 +25,7 @@ async def run(args: argparse.Namespace) -> None:
2325
match args.http_api_command:
2426
case "device":
2527
await DeviceCommand.run(args)
28+
case "site":
29+
await SiteCommand.run(args)
2630
case _:
2731
raise NotImplementedError(args.device_command)

src/enapter/cli/http/api/device_create_standalone_command.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ def register(parent: cli.Subparsers) -> None:
1111
parser = parent.add_parser(
1212
"create-standalone", formatter_class=argparse.ArgumentDefaultsHelpFormatter
1313
)
14-
parser.add_argument(
15-
"name", help="ID or slug of the device to get information about"
16-
)
14+
parser.add_argument("name", help="Name of the standalone device to create")
1715
parser.add_argument(
1816
"-s", "--site-id", help="Site ID to create device in", default=None
1917
)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import argparse
2+
3+
from enapter import cli
4+
5+
from .site_create_command import SiteCreateCommand
6+
from .site_delete_command import SiteDeleteCommand
7+
from .site_get_command import SiteGetCommand
8+
from .site_list_command import SiteListCommand
9+
from .site_update_command import SiteUpdateCommand
10+
11+
12+
class SiteCommand(cli.Command):
13+
14+
@staticmethod
15+
def register(parent: cli.Subparsers) -> None:
16+
parser = parent.add_parser(
17+
"site", formatter_class=argparse.ArgumentDefaultsHelpFormatter
18+
)
19+
subparsers = parser.add_subparsers(dest="http_api_site_command", required=True)
20+
for command in [
21+
SiteCreateCommand,
22+
SiteDeleteCommand,
23+
SiteGetCommand,
24+
SiteListCommand,
25+
SiteUpdateCommand,
26+
]:
27+
command.register(subparsers)
28+
29+
@staticmethod
30+
async def run(args: argparse.Namespace) -> None:
31+
match args.http_api_site_command:
32+
case "create":
33+
await SiteCreateCommand.run(args)
34+
case "delete":
35+
await SiteDeleteCommand.run(args)
36+
case "get":
37+
await SiteGetCommand.run(args)
38+
case "list":
39+
await SiteListCommand.run(args)
40+
case "update":
41+
await SiteUpdateCommand.run(args)
42+
case _:
43+
raise NotImplementedError(args.device_command)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import argparse
2+
import json
3+
4+
from enapter import cli, http
5+
6+
from .site_location import parse_site_location
7+
8+
9+
class SiteCreateCommand(cli.Command):
10+
11+
@staticmethod
12+
def register(parent: cli.Subparsers) -> None:
13+
parser = parent.add_parser(
14+
"create", formatter_class=argparse.ArgumentDefaultsHelpFormatter
15+
)
16+
parser.add_argument("name", help="Name of the site to create")
17+
parser.add_argument(
18+
"-t", "--timezone", help="Timezone of the site to create", default="UTC"
19+
)
20+
parser.add_argument(
21+
"-l",
22+
"--location",
23+
type=parse_site_location,
24+
help="Site location in the format NAME,LATITUDE,LONGITUDE",
25+
)
26+
27+
@staticmethod
28+
async def run(args: argparse.Namespace) -> None:
29+
async with http.api.Client(http.api.Config.from_env()) as client:
30+
site = await client.sites.create(
31+
name=args.name,
32+
timezone=args.timezone,
33+
location=(
34+
http.api.sites.Location(
35+
name=args.location[0],
36+
latitude=args.location[1],
37+
longitude=args.location[2],
38+
)
39+
if args.location is not None
40+
else None
41+
),
42+
)
43+
print(json.dumps(site.to_dto()))
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import argparse
2+
3+
from enapter import cli, http
4+
5+
6+
class SiteDeleteCommand(cli.Command):
7+
8+
@staticmethod
9+
def register(parent: cli.Subparsers) -> None:
10+
parser = parent.add_parser(
11+
"delete", formatter_class=argparse.ArgumentDefaultsHelpFormatter
12+
)
13+
parser.add_argument("id", type=str, help="ID of the site to delete")
14+
15+
@staticmethod
16+
async def run(args: argparse.Namespace) -> None:
17+
async with http.api.Client(http.api.Config.from_env()) as client:
18+
await client.sites.delete(args.id)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import argparse
2+
import json
3+
4+
from enapter import cli, http
5+
6+
7+
class SiteGetCommand(cli.Command):
8+
9+
@staticmethod
10+
def register(parent: cli.Subparsers) -> None:
11+
parser = parent.add_parser(
12+
"get", formatter_class=argparse.ArgumentDefaultsHelpFormatter
13+
)
14+
parser.add_argument(
15+
"id", nargs="?", type=str, help="ID of the site to retrieve"
16+
)
17+
18+
@staticmethod
19+
async def run(args: argparse.Namespace) -> None:
20+
async with http.api.Client(http.api.Config.from_env()) as client:
21+
site = await client.sites.get(args.id)
22+
print(json.dumps(site.to_dto()))
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import argparse
2+
import json
3+
4+
from enapter import cli, http
5+
6+
7+
class SiteListCommand(cli.Command):
8+
9+
@staticmethod
10+
def register(parent: cli.Subparsers) -> None:
11+
parser = parent.add_parser(
12+
"list", formatter_class=argparse.ArgumentDefaultsHelpFormatter
13+
)
14+
parser.add_argument(
15+
"-l",
16+
"--limit",
17+
type=int,
18+
help="Maximum number of sites to list",
19+
default=-1,
20+
)
21+
22+
@staticmethod
23+
async def run(args: argparse.Namespace) -> None:
24+
if args.limit == 0:
25+
return
26+
async with http.api.Client(http.api.Config.from_env()) as client:
27+
async with client.sites.list() as stream:
28+
count = 0
29+
async for site in stream:
30+
print(json.dumps(site.to_dto()))
31+
count += 1
32+
if args.limit > 0 and count == args.limit:
33+
break
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import argparse
2+
3+
4+
def parse_site_location(location_str: str) -> tuple[str, float, float]:
5+
try:
6+
name, lat_str, lon_str = location_str.split(",")
7+
return name, float(lat_str), float(lon_str)
8+
except ValueError:
9+
raise argparse.ArgumentTypeError(
10+
"Location must be in the format NAME,LATITUDE,LONGITUDE"
11+
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import argparse
2+
import json
3+
4+
from enapter import cli, http
5+
6+
from .site_location import parse_site_location
7+
8+
9+
class SiteUpdateCommand(cli.Command):
10+
11+
@staticmethod
12+
def register(parent: cli.Subparsers) -> None:
13+
parser = parent.add_parser(
14+
"update", formatter_class=argparse.ArgumentDefaultsHelpFormatter
15+
)
16+
parser.add_argument("id", nargs="?", type=str, help="ID of the site to update")
17+
parser.add_argument("-n", "--name", type=str, help="New name for the site")
18+
parser.add_argument(
19+
"-t", "--timezone", type=str, help="New timezone for the site"
20+
)
21+
parser.add_argument(
22+
"-l",
23+
"--location",
24+
type=parse_site_location,
25+
help="New location for the site",
26+
)
27+
28+
@staticmethod
29+
async def run(args: argparse.Namespace) -> None:
30+
async with http.api.Client(http.api.Config.from_env()) as client:
31+
site = await client.sites.update(
32+
site_id=args.id,
33+
name=args.name,
34+
timezone=args.timezone,
35+
location=(
36+
http.api.sites.Location(
37+
name=args.location[0],
38+
latitude=args.location[1],
39+
longitude=args.location[2],
40+
)
41+
if args.location is not None
42+
else None
43+
),
44+
)
45+
print(json.dumps(site.to_dto()))

0 commit comments

Comments
 (0)