diff --git a/src/client/qcc/cli/__init__.py b/src/client/qcc/cli/__init__.py index b3520f78..b76a27b2 100644 --- a/src/client/qcc/cli/__init__.py +++ b/src/client/qcc/cli/__init__.py @@ -7,12 +7,13 @@ from ..client import QCC from ..conf import settings -from . import auth, static, status +from . import auth, session, static, status app = typer.Typer(name="qcc", no_args_is_help=True) app.add_typer(auth.app) app.add_typer(static.app) app.add_typer(status.app) +app.add_typer(session.app) @app.callback() diff --git a/src/client/qcc/cli/session.py b/src/client/qcc/cli/session.py new file mode 100644 index 00000000..821b9256 --- /dev/null +++ b/src/client/qcc/cli/session.py @@ -0,0 +1,59 @@ +"""QualiCharge API client CLI: statuc.""" + +from typing import Annotated, Optional + +import click +import typer +from rich import print + +from ..client import QCC +from .api import async_run_api_query +from .utils import parse_input_json_lines, parse_json_parameter + +app = typer.Typer(name="session", no_args_is_help=True) + + +@app.command() +def create( + ctx: typer.Context, + session: Optional[str] = None, + interactive: Annotated[ + bool, typer.Option(help="Read session from standard input (JSON string)") + ] = True, +): + """Create a charging point session. + + You can submit your session entry to create as a JSON string argument for + the `--status` option. Without `--status` option (but with `--interactive`) + the command will read and parse the standard input as a JSON string. + + Note that when using the `--interactive` option (active by default), the command + expects your JSON string on a single row. + """ + client: QCC = ctx.obj + data = parse_json_parameter("session", session, interactive) + created = async_run_api_query(client.session.create, data) + print("[green]Created session successfully.[/green]") + print(created) + + +@app.command() +def bulk( + ctx: typer.Context, + chunk_size: int = 10, + ignore_errors: bool = False, +): + """Bulk create new sessions. + + Sessions will be read from the standard input (one JSON per line). + """ + client: QCC = ctx.obj + + n_created = async_run_api_query( + client.session.bulk, + parse_input_json_lines(click.get_text_stream("stdin"), ignore_errors), + chunk_size, + ignore_errors, + ) + + print(f"[green]Created {n_created} sessions successfully.[/green]") diff --git a/src/client/qcc/cli/static.py b/src/client/qcc/cli/static.py index 0c26cea5..533db79a 100644 --- a/src/client/qcc/cli/static.py +++ b/src/client/qcc/cli/static.py @@ -18,7 +18,7 @@ @app.command() def list(ctx: typer.Context): - """Get all static entries.""" + """Get all statique entries.""" client: QCC = ctx.obj async def statiques(): @@ -54,7 +54,7 @@ def create( @app.command() def read(ctx: typer.Context, id_pdc_itinerance: str): - """Get all static entries.""" + """Read a statique entry.""" client: QCC = ctx.obj read = async_run_api_query(client.static.read, id_pdc_itinerance) diff --git a/src/client/qcc/cli/status.py b/src/client/qcc/cli/status.py index 2b1eb753..cecb7cfd 100644 --- a/src/client/qcc/cli/status.py +++ b/src/client/qcc/cli/status.py @@ -1,15 +1,16 @@ -"""QualiCharge API client CLI: statuc.""" +"""QualiCharge API client CLI: status.""" import json from datetime import datetime from typing import Annotated, List, Optional +import click import typer from rich import print from ..client import QCC from .api import async_run_api_query -from .utils import parse_json_parameter +from .utils import parse_input_json_lines, parse_json_parameter app = typer.Typer(name="status", no_args_is_help=True) @@ -21,7 +22,7 @@ def list( pdc: Optional[List[str]] = None, station: Optional[List[str]] = None, ): - """List charge points last known status.""" + """List charging points last known status.""" client: QCC = ctx.obj async def statuses(): @@ -39,7 +40,7 @@ def create( bool, typer.Option(help="Read status from standard input (JSON string)") ] = True, ): - """Create a charge point status. + """Create a charging point status. You can submit your status entry to create as a JSON string argument for the `--status` option. Without `--status` option (but with `--interactive`) @@ -51,5 +52,52 @@ def create( client: QCC = ctx.obj data = parse_json_parameter("status", status, interactive) created = async_run_api_query(client.static.create, data) - print("[green]Created statique successfully.[/green]") + print("[green]Created status successfully.[/green]") print(created) + + +@app.command() +def read(ctx: typer.Context, id_pdc_itinerance: str): + """Get charging point status.""" + client: QCC = ctx.obj + + read = async_run_api_query(client.status.read, id_pdc_itinerance) + typer.echo(json.dumps(read)) + + +@app.command() +def history( + ctx: typer.Context, + id_pdc_itinerance: str, + from_: Annotated[Optional[datetime], typer.Option("--from")] = None, +): + """Get charging point history.""" + client: QCC = ctx.obj + + async def statuses(): + async for status in client.status.history(id_pdc_itinerance, from_=from_): + typer.echo(json.dumps(status)) + + async_run_api_query(statuses) + + +@app.command() +def bulk( + ctx: typer.Context, + chunk_size: int = 10, + ignore_errors: bool = False, +): + """Bulk create new statuses. + + Statuses will be read from the standard input (one JSON per line). + """ + client: QCC = ctx.obj + + n_created = async_run_api_query( + client.status.bulk, + parse_input_json_lines(click.get_text_stream("stdin"), ignore_errors), + chunk_size, + ignore_errors, + ) + + print(f"[green]Created {n_created} statuses successfully.[/green]") diff --git a/src/client/qcc/endpoints/base.py b/src/client/qcc/endpoints/base.py index 28d25e53..09c0da6c 100644 --- a/src/client/qcc/endpoints/base.py +++ b/src/client/qcc/endpoints/base.py @@ -2,7 +2,7 @@ import logging from abc import ABC, abstractmethod -from typing import AsyncIterator, Sequence, overload +from typing import AsyncIterator, Sequence import httpx diff --git a/src/client/qcc/endpoints/dynamic.py b/src/client/qcc/endpoints/dynamic.py index 8a68a33d..f3426701 100644 --- a/src/client/qcc/endpoints/dynamic.py +++ b/src/client/qcc/endpoints/dynamic.py @@ -45,9 +45,14 @@ async def list( for status in response.json(): yield status - async def history(self, id_: str) -> AsyncIterator[dict]: + async def history( + self, id_: str, from_: Optional[datetime] = None + ) -> AsyncIterator[dict]: """Query the /{endpoint}/{id_}/history endpoint (GET).""" - response = await self.client.get(f"{self.endpoint}/{id_}/history") + params = {"from_": from_} if from_ else {} + response = await self.client.get( + f"{self.endpoint}/{id_}/history", params=params + ) try: response.raise_for_status() except httpx.HTTPStatusError as err: