diff --git a/src/binarylane/console/printers/__init__.py b/src/binarylane/console/printers/__init__.py index e843a5f..2d3360d 100644 --- a/src/binarylane/console/printers/__init__.py +++ b/src/binarylane/console/printers/__init__.py @@ -5,6 +5,7 @@ from enum import Enum from binarylane.console.printers.json_printer import JsonPrinter +from binarylane.console.printers.none_printer import NonePrinter from binarylane.console.printers.plain_printer import PlainPrinter from binarylane.console.printers.printer import Printer from binarylane.console.printers.table_printer import TablePrinter @@ -23,6 +24,7 @@ class PrinterType(Enum): TABLE = TablePrinter TSV = TsvPrinter JSON = JsonPrinter + NONE = NonePrinter def create_printer(name: str) -> Printer: diff --git a/src/binarylane/console/printers/none_printer.py b/src/binarylane/console/printers/none_printer.py new file mode 100644 index 0000000..0dd629b --- /dev/null +++ b/src/binarylane/console/printers/none_printer.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +from typing import Any, List, Optional + +from binarylane.console.printers.printer import Printer + + +class NonePrinter(Printer): + def print(self, response: Any, fields: Optional[List[str]] = None) -> None: + pass diff --git a/src/binarylane/console/runners/action.py b/src/binarylane/console/runners/action.py index b985392..8090788 100644 --- a/src/binarylane/console/runners/action.py +++ b/src/binarylane/console/runners/action.py @@ -4,7 +4,7 @@ import shutil import sys import time -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Tuple from binarylane.console.runners.command import CommandRunner @@ -21,6 +21,10 @@ class ActionRunner(CommandRunner): _async: bool = False _quiet: bool = False + @property + def _default_output(self) -> str: + return "none" + def configure(self, parser: Parser) -> None: super().configure(parser) @@ -51,17 +55,14 @@ def _progress(self, progress: str) -> None: blanks = " " * (shutil.get_terminal_size().columns - 1) print(f"\r{blanks}\r{progress}", end="", file=sys.stderr) - def response(self, status_code: int, received: Any) -> None: - # If async is requested, use standard handler - if self._async: - super().response(status_code, received) - return + def wait_for_action(self, status_code: int, received: Any) -> Tuple[int, Any]: + """While received is an ActionResponse, show progress and wait for the action to complete""" from binarylane.api.actions.get_v2_actions_action_id import sync_detailed from binarylane.models.action_response import ActionResponse # FIXME: Extract _get_action(id: int) -> Tuple[int, Any] method so that derived class can call that instead - # Derived class may provide an Action ID directly: + # Caller may provide an Action ID directly: if isinstance(received, int): response = sync_detailed(received, client=self._client) status_code, received = response.status_code, response.parsed @@ -72,14 +73,25 @@ def response(self, status_code: int, received: Any) -> None: status = f"{received.action.type}: {step} ({received.action.progress.percent_complete}%) ... " self._progress(status) - # If action has completed, provide final status and return to caller + # Check if action has completed if received.action.completed_at: - self._progress(f"{received.action.status}.\n") - return + self._progress(f"{received.action.type}: {received.action.result_data or received.action.status}\n") + break + # Wait and then refresh action response time.sleep(5) response = sync_detailed(received.action.id, client=self._client) status_code, received = response.status_code, response.parsed - # Action did not complete so something went wrong - use standard error handling routine: + return status_code, received + + def response(self, status_code: int, received: Any) -> None: + # If async is requested, use standard handler + if self._async: + super().response(status_code, received) + return + + status_code, received = self.wait_for_action(status_code, received) + + # Action has now completed (or errored), process final response super().response(status_code, received) diff --git a/src/binarylane/console/runners/actionlink.py b/src/binarylane/console/runners/actionlink.py index 2e40991..09587e3 100644 --- a/src/binarylane/console/runners/actionlink.py +++ b/src/binarylane/console/runners/actionlink.py @@ -8,6 +8,10 @@ class ActionLinkRunner(ActionRunner): """ActionLinkRunner handles command responses with an optional action ID attached""" + @property + def _default_output(self) -> str: + return "table" + def response(self, status_code: int, received: Any) -> None: from binarylane.models.actions_links import ActionsLinks @@ -19,7 +23,7 @@ def response(self, status_code: int, received: Any) -> None: # Show action progress on stdout if not self._async: action_id = links.actions[0].id - super().response(status_code, action_id) + self.wait_for_action(status_code, action_id) # Print the 'other' object (e.g. server) from the response self._printer.print(received) diff --git a/src/binarylane/console/runners/command.py b/src/binarylane/console/runners/command.py index e1ce72b..c03dad6 100644 --- a/src/binarylane/console/runners/command.py +++ b/src/binarylane/console/runners/command.py @@ -8,7 +8,7 @@ from binarylane.models.validation_problem_details import ValidationProblemDetails from binarylane.console.printers import Printer, PrinterType, create_printer -from binarylane.console.runners import ExitCode, Runner +from binarylane.console.runners import Context, ExitCode, Runner from binarylane.console.runners.httpx_wrapper import CurlCommand from binarylane.console.util import create_client @@ -32,9 +32,17 @@ class CommandRunner(Runner): _client: AuthenticatedClient _print_curl: Optional[bool] - _output: str = _DEFAULT_OUTPUT + _output: str _header: bool = _DEFAULT_HEADER + def __init__(self, context: Context) -> None: + super().__init__(context) + self._output = self._default_output + + @property + def _default_output(self) -> str: + return _DEFAULT_OUTPUT + @abstractmethod def create_mapping(self) -> Mapping: """Add supported CLI arguments""" @@ -57,7 +65,7 @@ def configure(self, parser: Parser) -> None: parser.add_argument( "--output", dest="runner_output", - default=_DEFAULT_OUTPUT, + default=self._default_output, metavar="OUTPUT", choices=printers, help='Desired output format [%(choices)s] (default: "%(default)s")',