From 890baa0026ed20a43d15ed99b3a719dc59e0ee4d Mon Sep 17 00:00:00 2001 From: Roboto Bot-o Date: Fri, 19 Jul 2024 08:42:09 -0700 Subject: [PATCH] Update SDK to version 0.5.6 --- src/roboto/cli/actions/create.py | 22 ++-- src/roboto/cli/actions/invoke.py | 19 ++-- src/roboto/cli/actions/search.py | 8 +- src/roboto/cli/actions/show.py | 2 +- src/roboto/cli/actions/update.py | 18 ++-- src/roboto/cli/collections/changes.py | 2 +- src/roboto/cli/collections/create.py | 2 +- src/roboto/cli/collections/list.py | 2 +- src/roboto/cli/collections/list_all.py | 2 +- src/roboto/cli/collections/shared_helpdoc.py | 6 +- src/roboto/cli/collections/show.py | 2 +- src/roboto/cli/collections/update.py | 2 +- src/roboto/cli/command/__init__.py | 5 +- src/roboto/cli/command/roboto_command.py | 106 +++++++++++++++++++ src/roboto/cli/common_args/actions.py | 16 +-- src/roboto/cli/datasets/create.py | 6 +- src/roboto/cli/datasets/list_files.py | 3 +- src/roboto/cli/datasets/search.py | 6 +- src/roboto/cli/datasets/show.py | 2 +- src/roboto/cli/datasets/update.py | 12 +-- src/roboto/cli/images/delete_image.py | 2 +- src/roboto/cli/images/pull.py | 2 +- src/roboto/cli/images/push.py | 6 +- src/roboto/cli/invocations/status.py | 4 +- src/roboto/cli/orgs/commands.py | 28 +++-- src/roboto/cli/tokens/commands.py | 15 +-- src/roboto/cli/triggers/commands.py | 65 +++++------- src/roboto/cli/users/commands.py | 13 +-- src/roboto/version.py | 2 +- 29 files changed, 233 insertions(+), 147 deletions(-) create mode 100644 src/roboto/cli/command/roboto_command.py diff --git a/src/roboto/cli/actions/create.py b/src/roboto/cli/actions/create.py index 41f3832..3cb9b62 100644 --- a/src/roboto/cli/actions/create.py +++ b/src/roboto/cli/actions/create.py @@ -216,7 +216,7 @@ def create( ) print(f"Successfully created action '{action.name}'. Record: ") - print(json.dumps(action.to_dict(), indent=4)) + print(json.dumps(action.to_dict(), indent=2)) except RobotoConflictException: action = actions.Action.from_name( name=config_with_overrides.name, @@ -237,10 +237,10 @@ def create( if updates: action.update(**updates) print(f"Successfully updated action '{action.name}'. Record: ") - print(json.dumps(action.to_dict(), indent=4)) + print(json.dumps(action.to_dict(), indent=2)) else: print(f"Action '{action.name}' is up-to-date. Record: ") - print(json.dumps(action.to_dict(), indent=4)) + print(json.dumps(action.to_dict(), indent=2)) def create_parser(parser: argparse.ArgumentParser): @@ -283,9 +283,9 @@ def create_parser(parser: argparse.ArgumentParser): arg_name="inherits_from", arg_help=( "Partially or fully qualified reference to action from which to inherit configuration. " - "Inheriting from another action is mutually exclusive with specifying a container image (--image), " - "entrypoint (--entrypoint), command (--command), working directory (--workdir), env vars (--env), " - "or parameter(s) (--parameter). " + "Inheriting from another action is mutually exclusive with specifying a container image (``--image``), " + "entrypoint (``--entrypoint``), command (``--command``), working directory (``--workdir``), " + "env vars (``--env``), or parameter(s) (``--parameter``). " ), positional=False, required=False, @@ -305,12 +305,12 @@ def create_parser(parser: argparse.ArgumentParser): action=ActionParameterArg, help=( "Zero or more parameters (space-separated) accepted by this action. " - "'name' is the only required attribute. " - "'default' values, if provided, are JSON parsed. " + "``name`` is the only required attribute. " + "``default`` values, if provided, are JSON parsed. " "This argument can be specified multiple times. " "Parameters can be modified after creation. " "Argument values must be wrapped in quotes. E.g.: " - "--put-parameter 'name=my_param|required=true|description=My description of my_param'" + "``--put-parameter 'name=my_param|required=true|description=My description of my_param'``" ), ) parser.add_argument( @@ -320,8 +320,8 @@ def create_parser(parser: argparse.ArgumentParser): nargs="*", action=KeyValuePairsAction, help=( - "Zero or more 'key=value' format key/value pairs which represent action metadata. " - "`value` is parsed as JSON. " + "Zero or more ``=`` format key/value pairs which represent action metadata. " + "``value`` is parsed as JSON. " "Metadata can be modified after creation." ), ) diff --git a/src/roboto/cli/actions/invoke.py b/src/roboto/cli/actions/invoke.py index 59eb1a7..21ca214 100644 --- a/src/roboto/cli/actions/invoke.py +++ b/src/roboto/cli/actions/invoke.py @@ -5,7 +5,6 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. import argparse -import textwrap from ...domain import actions from ..command import ( @@ -65,14 +64,12 @@ def invoke_parser(parser: argparse.ArgumentParser) -> None: type=str, nargs="+", action="extend", - # fmt: off - help=textwrap.dedent("""\ - One or many file patterns for data to download from the data source. Examples: - front camera images, "--input-data '**/cam_front/*.jpg'"; - front and rear camera images, "--input-data '**/cam_front/*.jpg' --input-data '**/cam_rear/*.jpg'"; - all data, "--input-data '**/*'" - """), - # fmt: on + help=( + "One or many file patterns for data to download from the data source. Examples: " + "front camera images, ``--input-data '**/cam_front/*.jpg'``; " + "front and rear camera images, ``--input-data '**/cam_front/*.jpg' --input-data '**/cam_rear/*.jpg'``; " + "all data, ``--input-data '**/*'``." + ), ) parser.add_argument( @@ -110,8 +107,8 @@ def invoke_parser(parser: argparse.ArgumentParser) -> None: nargs="*", action=KeyValuePairsAction, help=( - "Zero or more '=' pairs. " - "`parameter_value` is parsed as JSON. " + "Zero or more ``=`` pairs. " + "``parameter_value`` is parsed as JSON. " ), ) diff --git a/src/roboto/cli/actions/search.py b/src/roboto/cli/actions/search.py index c2ec6c2..21bd0b5 100644 --- a/src/roboto/cli/actions/search.py +++ b/src/roboto/cli/actions/search.py @@ -81,7 +81,7 @@ def search( owner_org_id=args.org, roboto_client=context.roboto_client, ) - print(json.dumps([action.to_dict() for action in matching_actions], indent=4)) + print(json.dumps([action.to_dict() for action in matching_actions], indent=2)) def search_parser(parser: argparse.ArgumentParser): @@ -104,8 +104,8 @@ def search_parser(parser: argparse.ArgumentParser): nargs="*", action=KeyValuePairsAction, help=( - "Zero or more 'key=value' pairs which represent action metadata. " - "`value` is parsed as JSON. E.g.: --metadata foo=bar --metadata baz.nested=200" + "Zero or more ``key=value`` pairs which represent action metadata. " + "``value`` is parsed as JSON. E.g.: ``--metadata foo=bar --metadata baz.nested=200``" ), ) parser.add_argument( @@ -113,7 +113,7 @@ def search_parser(parser: argparse.ArgumentParser): required=False, type=str, nargs="*", - help="One or more tags associated with this action. E.g.: --tag foo --tag bar", + help="One or more tags associated with this action. E.g.: ``--tag foo --tag bar``", action="extend", ) add_org_arg(parser=parser) diff --git a/src/roboto/cli/actions/show.py b/src/roboto/cli/actions/show.py index d87bcb9..dc5a5eb 100644 --- a/src/roboto/cli/actions/show.py +++ b/src/roboto/cli/actions/show.py @@ -26,7 +26,7 @@ def show( owner_org_id=owner_org_id, roboto_client=context.roboto_client, ) - print(json.dumps(action.to_dict(), indent=4)) + print(json.dumps(action.to_dict(), indent=2)) def show_parser(parser: argparse.ArgumentParser): diff --git a/src/roboto/cli/actions/update.py b/src/roboto/cli/actions/update.py index 95b813a..31afa40 100644 --- a/src/roboto/cli/actions/update.py +++ b/src/roboto/cli/actions/update.py @@ -96,7 +96,7 @@ def update( action.update(**updates) print(f"Successfully updated action '{action.name}'. Record: ") - print(json.dumps(action.to_dict(), indent=4)) + print(json.dumps(action.to_dict(), indent=2)) def update_parser(parser: argparse.ArgumentParser): @@ -111,7 +111,7 @@ def update_parser(parser: argparse.ArgumentParser): action="store", type=lambda s: s if s != "null" else null, default=NotSet, - help="Optional description of action. Specify 'null' to unset existing description.", + help="Optional description of action. Specify ``null`` to unset existing description.", ) parser.add_argument( "--short-description", @@ -119,7 +119,7 @@ def update_parser(parser: argparse.ArgumentParser): action="store", type=lambda s: s if s != "null" else null, default=NotSet, - help="Optional short description of an action. Specify 'null' to unset existing description.", + help="Optional short description of an action. Specify ``null`` to unset existing description.", ) parser.add_argument( "--image", @@ -148,7 +148,7 @@ def update_parser(parser: argparse.ArgumentParser): help=( "Add parameter(s) or overwrite existing parameter(s) with the same name. " "Argument values must be wrapped in quotes. E.g.: " - "--put-parameter 'name=my_param|required=true|description=My description of my_param'" + "``--put-parameter 'name=my_param|required=true|description=My description of my_param'``" ), ) parser.add_argument( @@ -178,12 +178,12 @@ def update_parser(parser: argparse.ArgumentParser): nargs="*", action=KeyValuePairsAction, help=( - "Zero or more 'key_path=value' formatted pairs. " - "An attempt is made to parse `value` as JSON; if this fails, `value` is stored as a string. " - "If `key_path` already exists, existing value will be overwritten. " + "Zero or more ``key_path=value`` formatted pairs. " + "An attempt is made to parse ``value`` as JSON; if this fails, ``value`` is stored as a string. " + "If ``key_path`` already exists, existing value will be overwritten. " "Dot notation is supported for nested keys. " "Examples: " - "--put-metadata 'key1=value1' 'key2.subkey1=value2' 'key3.sublist1=[\"a\",\"b\",\"c\"]'" # noqa: E501 + "``--put-metadata 'key1=value1' 'key2.subkey1=value2' 'key3.sublist1=[\"a\",\"b\",\"c\"]'``" # noqa: E501 ), ) @@ -194,7 +194,7 @@ def update_parser(parser: argparse.ArgumentParser): nargs="*", help=( "Remove each key from dataset metadata if it exists. " - "Dot notation is supported for nested keys. E.g.: --remove-metadata key1 key2.subkey3" + "Dot notation is supported for nested keys. E.g.: ``--remove-metadata key1 key2.subkey3``" ), ) add_org_arg(parser=parser) diff --git a/src/roboto/cli/collections/changes.py b/src/roboto/cli/collections/changes.py index 27afe83..6bd3fa9 100644 --- a/src/roboto/cli/collections/changes.py +++ b/src/roboto/cli/collections/changes.py @@ -20,7 +20,7 @@ def show(args, context: CLIContext, parser: argparse.ArgumentParser): for change in collection.changes( from_version=args.from_version, to_version=args.to_version ): - print(change.json()) + print(change.model_dump_json(indent=2)) def show_setup_parser(parser): diff --git a/src/roboto/cli/collections/create.py b/src/roboto/cli/collections/create.py index 07774a2..161173b 100644 --- a/src/roboto/cli/collections/create.py +++ b/src/roboto/cli/collections/create.py @@ -47,7 +47,7 @@ def create(args, context: CLIContext, parser: argparse.ArgumentParser): caller_org_id=args.org, roboto_client=context.roboto_client, ) - print(collection.record.json()) + print(collection.record.model_dump_json(indent=2)) def create_setup_parser(parser): diff --git a/src/roboto/cli/collections/list.py b/src/roboto/cli/collections/list.py index 7344dda..593f9a9 100644 --- a/src/roboto/cli/collections/list.py +++ b/src/roboto/cli/collections/list.py @@ -17,7 +17,7 @@ def list(args, context: CLIContext, parser: argparse.ArgumentParser): owner_org_id=args.org, roboto_client=context.roboto_client, ): - print(collection.record.json()) + print(collection.record.model_dump_json(indent=2)) list_command = RobotoCommand( diff --git a/src/roboto/cli/collections/list_all.py b/src/roboto/cli/collections/list_all.py index d96eee5..64cd231 100644 --- a/src/roboto/cli/collections/list_all.py +++ b/src/roboto/cli/collections/list_all.py @@ -22,7 +22,7 @@ def list_all(args, context: CLIContext, parser: argparse.ArgumentParser): roboto_client=context.roboto_client, content_mode=args.content_mode, ): - print(collection.record.json()) + print(collection.record.model_dump_json(indent=2)) def list_all_setup_parser(parser: argparse.ArgumentParser): diff --git a/src/roboto/cli/collections/shared_helpdoc.py b/src/roboto/cli/collections/shared_helpdoc.py index e01ece5..932f206 100644 --- a/src/roboto/cli/collections/shared_helpdoc.py +++ b/src/roboto/cli/collections/shared_helpdoc.py @@ -11,7 +11,7 @@ + " Allows caller to ensure that they're referencing an immutable representation of a given collection." ) CONTENT_MODE_HELP = ( - "The type of content to return for a collection or set of collections. 'summary_only' returns " - + "only metadata, 'references' will return each id in the collection, and 'full' will retrieve the full content " - + "of each resource in the collection." + "The type of content to return for a collection or set of collections. ``summary_only`` returns " + + "only metadata, ``references`` will return each id in the collection, " + + "and ``full`` will retrieve the full content of each resource in the collection." ) diff --git a/src/roboto/cli/collections/show.py b/src/roboto/cli/collections/show.py index c53158b..fdf9d3e 100644 --- a/src/roboto/cli/collections/show.py +++ b/src/roboto/cli/collections/show.py @@ -28,7 +28,7 @@ def show(args, context: CLIContext, parser: argparse.ArgumentParser): roboto_client=context.roboto_client, content_mode=content_mode, ) - print(collection.record.json()) + print(collection.record.model_dump_json(indent=2)) def show_setup_parser(parser): diff --git a/src/roboto/cli/collections/update.py b/src/roboto/cli/collections/update.py index 20d98e3..a19bd3f 100644 --- a/src/roboto/cli/collections/update.py +++ b/src/roboto/cli/collections/update.py @@ -78,7 +78,7 @@ def update(args, context: CLIContext, parser: argparse.ArgumentParser): remove_resources=NotSet if len(remove_resources) == 0 else remove_resources, ) - print(collection.record.json()) + print(collection.record.model_dump_json(indent=2)) def update_setup_parser(parser): diff --git a/src/roboto/cli/command/__init__.py b/src/roboto/cli/command/__init__.py index 56b1b57..84e3074 100644 --- a/src/roboto/cli/command/__init__.py +++ b/src/roboto/cli/command/__init__.py @@ -9,7 +9,10 @@ JsonFileOrStrType, KeyValuePairsAction, ) -from .model import RobotoCommand, RobotoCommandSet +from .roboto_command import ( + RobotoCommand, + RobotoCommandSet, +) __all__ = [ "ExistingPathlibPath", diff --git a/src/roboto/cli/command/roboto_command.py b/src/roboto/cli/command/roboto_command.py new file mode 100644 index 0000000..521dca9 --- /dev/null +++ b/src/roboto/cli/command/roboto_command.py @@ -0,0 +1,106 @@ +# Copyright (c) 2024 Roboto Technologies, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at https://mozilla.org/MPL/2.0/. + +import argparse +from typing import Any, Callable, Optional + +from ...exceptions import ( + RobotoDomainException, + RobotoNoOrgProvidedException, +) +from ..argparse import SortingHelpFormatter +from ..context import CLIContext +from ..terminal import print_error_and_exit + + +class RobotoCommand(object): + _name: str + _logic: Callable[ + [Any, CLIContext, argparse.ArgumentParser], None + ] # Args, CLIContext + _inner_setup_parser: Optional[Callable[[Any], None]] # Parser + _command_kwargs: Optional[dict[str, Any]] + + def __init__( + self, + name: str, + logic: Callable[[Any, CLIContext, argparse.ArgumentParser], None], + command_kwargs: Optional[dict], + setup_parser: Optional[Callable[[Any], None]] = None, + ): + self._name = name + self._logic = logic + self._inner_setup_parser = setup_parser + self._command_kwargs = command_kwargs + + @property + def name(self): + return self._name + + @property + def command_kwargs(self): + if self._command_kwargs is not None: + return self._command_kwargs + return {} + + def setup_parser( + self, parser: argparse.ArgumentParser, context: Optional[CLIContext] + ): + def context_aware_logic(args): + if not context: + raise ValueError( + "CLIContext is not set. " + "This is a programming error, and should be fixed by the Roboto development team." + ) + try: + return self._logic(args, context, parser) + except RobotoNoOrgProvidedException: + parser.error( + "User with 0 or 2+ orgs must explicitly provide --org to org-bound operations. " + + "This can also be achieved by setting a 'ROBOTO_ORG_ID' environment variable, " + + "whose value will be used by default." + ) + except RobotoDomainException as exc: + print_error_and_exit(f"{exc.__class__.__name__}: {exc}") + + parser.set_defaults(func=context_aware_logic) + if self._inner_setup_parser is not None: + self._inner_setup_parser(parser) + + +class RobotoCommandSet(object): + commands: list[RobotoCommand] + name: str + + __help: str + __context: Optional[CLIContext] + + def __init__(self, name, help, commands): + self.name = name + self.__help = help + self.commands = commands + + def add_to_subparsers( + self, + parent_subparsers: Any, + context: Optional[CLIContext], + ) -> None: + self.__context = context + + command_set_parser = parent_subparsers.add_parser(self.name, help=self.__help) + subparsers = command_set_parser.add_subparsers() + subparsers.required = True + + for command in self.commands: + command_parser = subparsers.add_parser( + command.name, + formatter_class=SortingHelpFormatter, + **command.command_kwargs, + ) + command.setup_parser(command_parser, context) + + def sort_commands(self): + self.commands.sort(key=lambda command: command.name) diff --git a/src/roboto/cli/common_args/actions.py b/src/roboto/cli/common_args/actions.py index 9a8a6b7..e1426d2 100644 --- a/src/roboto/cli/common_args/actions.py +++ b/src/roboto/cli/common_args/actions.py @@ -311,7 +311,7 @@ def add_container_parameters_args(parser: argparse.ArgumentParser) -> None: help=( "Container ENTRYPOINT override." ' Supports passing empty string ("") as an override, which unsets the ENTRYPOINT specified in the docker image.' # noqa: E501 - " If updating or invoking action which has existing ENTRYPOINT override, specify 'null' to remove the override." # noqa: E501 + " If updating or invoking action which has existing ENTRYPOINT override, specify ``null`` to remove the override." # noqa: E501 " Refer to docker documentation for more: " "https://docs.docker.com/engine/reference/builder/#entrypoint" " and https://docs.docker.com/engine/reference/run/#entrypoint-default-command-to-execute-at-runtime" @@ -325,7 +325,7 @@ def add_container_parameters_args(parser: argparse.ArgumentParser) -> None: dest="command", help=( "Container CMD override." - " If updating or invoking action which has existing CMD override, specify 'null' to remove the override." + " If updating or invoking action which has existing CMD override, specify ``null`` to remove the override." " Refer to docker documentation for more: " "https://docs.docker.com/engine/reference/builder/#cmd and" " https://docs.docker.com/engine/reference/run/#cmd-default-command-or-options" @@ -339,10 +339,10 @@ def add_container_parameters_args(parser: argparse.ArgumentParser) -> None: default=DockerInstructionForm.Exec.value, dest="command_form", help=( - "In 'exec' form, the provided '--command' str is split into a list of strings" - ' (e.g., \'--command "-c \'print(123)\'"\' is parsed as ["-c", "print(123)"]).' - " In 'shell' form, the provided '--command' str is not split" - " (e.g., '--command \"python -c 'print(123)'\"' is parsed as [\"python -c 'print(123)'\"])." + "In ``exec`` form, the provided ``--command`` str is split into a list of strings" + ' (e.g., ``--command "-c \'print(123)\'"`` is parsed as ``["-c", "print(123)"]``).' + " In ``shell`` form, the provided ``--command`` str is not split" + " (e.g., ``--command \"python -c 'print(123)'\"`` is parsed as ``[\"python -c 'print(123)'\"]``)." ), ) @@ -352,7 +352,7 @@ def add_container_parameters_args(parser: argparse.ArgumentParser) -> None: type=lambda s: s if s != "null" else null, dest="workdir", help=( - "If updating, specify 'null' to clear existing workdir." + "If updating, specify ``null`` to clear existing workdir." " Refer to docker documentation for more: https://docs.docker.com/engine/reference/run/#workdir" ), ) @@ -364,7 +364,7 @@ def add_container_parameters_args(parser: argparse.ArgumentParser) -> None: nargs="*", action=KeyValuePairsAction, help=( - "Zero or more 'key=value' formatted pairs to set as container ENV vars. " + "Zero or more ``=`` formatted pairs to set as container ENV vars. " "Do not use ENV vars for secrets (such as API keys). " "See documentation: https://docs.docker.com/engine/reference/run/#env-environment-variables" ), diff --git a/src/roboto/cli/datasets/create.py b/src/roboto/cli/datasets/create.py index fddd94c..454a02f 100644 --- a/src/roboto/cli/datasets/create.py +++ b/src/roboto/cli/datasets/create.py @@ -25,7 +25,7 @@ def create(args, context: CLIContext, parser: argparse.ArgumentParser): caller_org_id=args.org, ) - print(json.dumps(dataset.to_dict(), indent=4)) + print(json.dumps(dataset.to_dict(), indent=2)) def create_setup_parser(parser): @@ -35,8 +35,8 @@ def create_setup_parser(parser): metavar="KEY=VALUE", nargs="*", action=KeyValuePairsAction, - help="Zero or more 'key=value' format key/value pairs which represent dataset metadata. " - + "Metadata can be mutated after creation.", + help="Zero or more ``=`` pairs which represent dataset metadata. " + + "Metadata can be changed after creation.", ) parser.add_argument( "-t", diff --git a/src/roboto/cli/datasets/list_files.py b/src/roboto/cli/datasets/list_files.py index fa162fd..87b65d4 100644 --- a/src/roboto/cli/datasets/list_files.py +++ b/src/roboto/cli/datasets/list_files.py @@ -5,7 +5,6 @@ # file, You can obtain one at https://mozilla.org/MPL/2.0/. import argparse -import sys from ...domain.datasets import Dataset from ..command import RobotoCommand @@ -17,7 +16,7 @@ def list_files(args, context: CLIContext, parser: argparse.ArgumentParser): dataset = Dataset.from_id(args.dataset_id, context.roboto_client) for f in dataset.list_files(args.include, args.exclude): - sys.stdout.write(f"{f.relative_path}\n") + print(f"{f.relative_path}") def list_files_setup_parser(parser): diff --git a/src/roboto/cli/datasets/search.py b/src/roboto/cli/datasets/search.py index e087a56..2677169 100644 --- a/src/roboto/cli/datasets/search.py +++ b/src/roboto/cli/datasets/search.py @@ -64,7 +64,7 @@ def search(args, context: CLIContext, parser: argparse.ArgumentParser): roboto_client=context.roboto_client, owner_org_id=args.org, ) - print(json.dumps([result.to_dict() for result in results], indent=4)) + print(json.dumps([result.to_dict() for result in results], indent=2)) def search_setup_parser(parser): @@ -75,7 +75,7 @@ def search_setup_parser(parser): nargs="*", action=KeyValuePairsAction, help=( - "Zero or more 'key=value' pairs which represent dataset metadata. " + "Zero or more ``=`` pairs which represent dataset metadata. " "`value` is parsed as JSON. E.g.: --metadata foo=bar --metadata baz.nested=200" ), ) @@ -84,7 +84,7 @@ def search_setup_parser(parser): required=False, type=str, nargs="*", - help="One or more tags associated with this dataset. E.g.: --tag foo --tag bar", + help="One or more tags associated with this dataset. E.g.: ``--tag foo --tag bar``", action="extend", ) add_org_arg(parser=parser) diff --git a/src/roboto/cli/datasets/show.py b/src/roboto/cli/datasets/show.py index cc94140..645ed7f 100644 --- a/src/roboto/cli/datasets/show.py +++ b/src/roboto/cli/datasets/show.py @@ -15,7 +15,7 @@ def show(args, context: CLIContext, parser: argparse.ArgumentParser): record = Dataset.from_id(args.dataset_id, context.roboto_client) - print(json.dumps(record.to_dict(), indent=4)) + print(json.dumps(record.to_dict(), indent=2)) def show_setup_parser(parser): diff --git a/src/roboto/cli/datasets/update.py b/src/roboto/cli/datasets/update.py index 530b098..3dd130c 100644 --- a/src/roboto/cli/datasets/update.py +++ b/src/roboto/cli/datasets/update.py @@ -33,7 +33,7 @@ def update( dataset.update(metadata_changeset=metadata_changeset, description=args.description) print(f"Successfully updated dataset '{dataset.dataset_id}'. Record: ") - print(json.dumps(dataset.to_dict(), indent=4)) + print(json.dumps(dataset.to_dict(), indent=2)) def update_parser(parser: argparse.ArgumentParser): @@ -64,12 +64,12 @@ def update_parser(parser: argparse.ArgumentParser): nargs="*", action=KeyValuePairsAction, help=( - "Zero or more 'key_path=value' formatted pairs. " - "An attempt is made to parse `value` as JSON; if this fails, `value` is stored as a string. " - "If `key_path` already exists, existing value will be overwritten. " + "Zero or more ``=`` formatted pairs. " + "An attempt is made to parse ``value`` as JSON; if this fails, ``value`` is stored as a string. " + "If ``key`` already exists, existing value will be overwritten. " "Dot notation is supported for nested keys. " "Examples: " - "--put-metadata 'key1=value1' 'key2.subkey1=value2' 'key3.sublist1=[\"a\",\"b\",\"c\"]'" # noqa: E501 + "``--put-metadata 'key1=value1' 'key2.subkey1=value2' 'key3.sublist1=[\"a\",\"b\",\"c\"]'``" # noqa: E501 ), ) @@ -80,7 +80,7 @@ def update_parser(parser: argparse.ArgumentParser): nargs="*", help=( "Remove each key from dataset metadata if it exists. " - "Dot notation is supported for nested keys. E.g.: --remove-metadata key1 key2.subkey3" + "Dot notation is supported for nested keys. E.g.: ``--remove-metadata key1 key2.subkey3``" ), ) diff --git a/src/roboto/cli/images/delete_image.py b/src/roboto/cli/images/delete_image.py index 60948c1..e742556 100644 --- a/src/roboto/cli/images/delete_image.py +++ b/src/roboto/cli/images/delete_image.py @@ -25,7 +25,7 @@ def delete_image_parser(parser: argparse.ArgumentParser) -> None: parser.add_argument( "remote_image", action="store", - help="Specify the remote image to delete, in the format ':'.", + help="Specify the remote image to delete, in the format ``:``.", ) diff --git a/src/roboto/cli/images/pull.py b/src/roboto/cli/images/pull.py index 1a3326c..9971e88 100644 --- a/src/roboto/cli/images/pull.py +++ b/src/roboto/cli/images/pull.py @@ -69,7 +69,7 @@ def pull_parser(parser: argparse.ArgumentParser) -> None: parser.add_argument( "remote_image", action="store", - help="Specify the remote image to pull, in the format ':'.", + help="Specify the remote image to pull, in the format ``:``.", ) diff --git a/src/roboto/cli/images/push.py b/src/roboto/cli/images/push.py index 7d5d4d9..90c4e98 100644 --- a/src/roboto/cli/images/push.py +++ b/src/roboto/cli/images/push.py @@ -139,9 +139,9 @@ def push_parser(parser: argparse.ArgumentParser) -> None: "local_image", action="store", help=( - "Specify the local image to push, in the format ':'. " - "If no tag is specified, 'latest' is assumed. " - "Image must exist locally (i.e. 'docker images' must list it)." + "Specify the local image to push, in the format ``:``. " + "If no tag is specified, ``latest`` is assumed. " + "Image must exist locally (i.e. ``docker images`` must list it)." ), ) diff --git a/src/roboto/cli/invocations/status.py b/src/roboto/cli/invocations/status.py index 854ccf5..c6545db 100644 --- a/src/roboto/cli/invocations/status.py +++ b/src/roboto/cli/invocations/status.py @@ -27,7 +27,7 @@ def status( status_record.to_presentable_dict() for status_record in invocation.status_log ], - indent=4, + indent=2, ) ) return @@ -47,7 +47,7 @@ def status( if status_records_to_print: for status_record in status_records_to_print: printed.add(status_record.status) - print(json.dumps(status_record.to_presentable_dict(), indent=4)) + print(json.dumps(status_record.to_presentable_dict(), indent=2)) if invocation.reached_terminal_status: break diff --git a/src/roboto/cli/orgs/commands.py b/src/roboto/cli/orgs/commands.py index caebb54..87531c8 100644 --- a/src/roboto/cli/orgs/commands.py +++ b/src/roboto/cli/orgs/commands.py @@ -6,7 +6,6 @@ import argparse import json -import sys from ...domain.orgs import ( Org, @@ -53,7 +52,7 @@ def create(args, context: CLIContext, parser: argparse.ArgumentParser): bind_email_domain=args.bind_email_domain, roboto_client=context.roboto_client, ) - sys.stdout.write(json.dumps(org.to_dict()) + "\n") + print(json.dumps(org.to_dict(), indent=2)) def create_setup_parser(parser): @@ -71,14 +70,14 @@ def delete(args, context: CLIContext, parser: argparse.ArgumentParser): org = Org.from_id(org_id=args.org, roboto_client=context.roboto_client) if not args.ignore_prompt: - sys.stdout.write("Are you absolutely sure you want to delete your org? [y/n]: ") + print("Are you absolutely sure you want to delete your org? [y/n]: ") choice = input().lower() if choice not in ["y", "yes"]: return org.delete() - sys.stdout.write("Successfully deleted!\n") + print("Successfully deleted!") def delete_setup_parser(parser): @@ -98,7 +97,7 @@ def delete_setup_parser(parser): def show(args, context: CLIContext, parser: argparse.ArgumentParser): record = Org.from_id(org_id=args.org, roboto_client=context.roboto_client) - sys.stdout.write(json.dumps(record.to_dict()) + "\n") + print(json.dumps(record.to_dict(), indent=2)) def show_setup_parser(parser): @@ -138,7 +137,7 @@ def list_org_members_setup_parser(parser): def remove_user(args, context: CLIContext, parser: argparse.ArgumentParser): org = Org.from_id(org_id=args.org, roboto_client=context.roboto_client) org.remove_user(user_id=args.user) - sys.stdout.write("Successfully removed!\n") + print("Successfully removed!") def remove_user_setup_parser(parser): @@ -162,7 +161,7 @@ def invite_user(args, context: CLIContext, parser: argparse.ArgumentParser): org_id=args.org, roboto_client=context.roboto_client, ) - sys.stdout.write("Invite sent!\n") + print("Invite sent!") def invite_user_setup_parser(parser): @@ -182,7 +181,7 @@ def invite_user_setup_parser(parser): def list_invites(args, context: CLIContext, parser: argparse.ArgumentParser): invites = OrgInvite.for_org(org_id=args.org, roboto_client=context.roboto_client) for invite in invites: - sys.stdout.write(json.dumps(invite.to_dict()) + "\n") + print(json.dumps(invite.to_dict(), indent=2)) def list_invites_setup_parser(parser): @@ -197,7 +196,7 @@ def add_role(args, context: CLIContext, parser: argparse.ArgumentParser): Org.from_id(org_id=args.org, roboto_client=context.roboto_client).add_role_for_user( user_id=args.user, role=args.role ) - sys.stdout.write("Added!\n") + print("Added!") def add_role_setup_parser(parser): @@ -225,7 +224,7 @@ def remove_role(args, context: CLIContext, parser: argparse.ArgumentParser): Org.from_id( org_id=args.org, roboto_client=context.roboto_client ).remove_role_from_user(user_id=args.user, role=args.role) - sys.stdout.write("Removed!\n") + print("Removed!") def remove_role_setup_parser(parser): @@ -254,7 +253,7 @@ def bind_email_domain(args, context: CLIContext, parser: argparse.ArgumentParser Org.from_id(org_id=args.org, roboto_client=context.roboto_client).bind_email_domain( args.email_domain ) - sys.stderr.write(f"Successfully bound domain {args.email_domain}\n") + print(f"Successfully bound domain {args.email_domain}") def bind_email_domain_setup_parser(parser): @@ -271,7 +270,7 @@ def unbind_email_domain(args, context: CLIContext, parser: argparse.ArgumentPars Org.from_id( org_id=args.org, roboto_client=context.roboto_client ).unbind_email_domain(args.email_domain) - sys.stderr.write(f"Successfully unbound domain {args.email_domain}\n") + print(f"Successfully unbound domain {args.email_domain}") def unbind_email_domain_setup_parser(parser): @@ -288,7 +287,7 @@ def list_email_domains(args, context: CLIContext, parser: argparse.ArgumentParse for domain in Org.from_id( org_id=args.org, roboto_client=context.roboto_client ).email_domains(): - sys.stdout.write(domain + "\n") + print(domain) def register_bucket( @@ -304,8 +303,7 @@ def register_bucket( ) print( - "Bucket registered successfully! It will be used to store files for all new datasets.", - file=sys.stderr, + "Bucket registered successfully! It will be used to store files for all new datasets." ) diff --git a/src/roboto/cli/tokens/commands.py b/src/roboto/cli/tokens/commands.py index 8026383..390726c 100644 --- a/src/roboto/cli/tokens/commands.py +++ b/src/roboto/cli/tokens/commands.py @@ -6,7 +6,6 @@ import argparse import json -import sys from ...domain.tokens import Token from ..command import ( @@ -24,12 +23,14 @@ def create(args, context: CLIContext, parser: argparse.ArgumentParser): roboto_client=context.roboto_client, ) - creds_example_json = json.dumps({"username": "", "token": secret}) + creds_example_json = json.dumps( + {"username": "", "token": secret}, indent=2 + ) - sys.stderr.write( + print( "This secret will only be available to you once, so store it somewhere safe!\n" + "To use this personal access token, create a file at ~/.roboto/config.json, and populate it with " - + f"{creds_example_json}.\n" + + f"{creds_example_json}." ) @@ -59,12 +60,12 @@ def create_setup_parser(parser): def list(args, context: CLIContext, parser: argparse.ArgumentParser): tokens = Token.for_self(roboto_client=context.roboto_client) for token in tokens: - sys.stdout.write(json.dumps(token.to_dict()) + "\n") + print(json.dumps(token.to_dict(), indent=2)) def show(args, context: CLIContext, parser: argparse.ArgumentParser): token = Token.from_id(token_id=args.id, roboto_client=context.roboto_client) - sys.stdout.write(json.dumps(token.to_dict()) + "\n") + print(json.dumps(token.to_dict(), indent=2)) def show_setup_parser(parser): @@ -78,7 +79,7 @@ def show_setup_parser(parser): def delete(args, context: CLIContext, parser: argparse.ArgumentParser): Token.from_id(token_id=args.id, roboto_client=context.roboto_client).delete() - sys.stdout.write(f"Successfully deleted token '{args.id}'!\n") + print(f"Successfully deleted token '{args.id}'!") def delete_setup_parser(parser): diff --git a/src/roboto/cli/triggers/commands.py b/src/roboto/cli/triggers/commands.py index 4f45554..89a5aae 100644 --- a/src/roboto/cli/triggers/commands.py +++ b/src/roboto/cli/triggers/commands.py @@ -6,7 +6,6 @@ import argparse import json -import textwrap from typing import Any, Optional from ...domain import actions @@ -155,14 +154,12 @@ def create_setup_parser(parser): type=str, nargs="+", action="extend", - # fmt: off - help=textwrap.dedent("""\ - One or many file patterns for data to download from the data source. Examples: - front camera images, "--input-data '**/cam_front/*.jpg'"; - front and rear camera images, "--input-data '**/cam_front/*.jpg' --input-data '**/cam_rear/*.jpg'"; - all data, "--input-data '**/*'" - """), - # fmt: on + help="""\ + One or many file patterns for data to download from the data source. Examples: + front camera images, ``--required-inputs '**/cam_front/*.jpg'``; + front and rear camera images, ``--required-inputs'**/cam_front/*.jpg' --required-inputs '**/cam_rear/*.jpg'``; + all data, ``--required-inputs '**/*'``. + """, ) parser.add_argument( "--additional-inputs", @@ -170,14 +167,9 @@ def create_setup_parser(parser): type=str, nargs="+", action="extend", - # fmt: off - help=textwrap.dedent("""\ - One or many file patterns for data to download from the data source which is NOT considered as part of - trigger evaluation. Examples: - front and rear camera images, "--input-data '**/cam_front/*.jpg' --input-data '**/cam_rear/*.jpg'"; - all data, "--input-data '**/*'" - """), - # fmt: on + help="""\ + One or many file patterns for data to download from the data source which is NOT considered as part of + trigger evaluation. Example: front camera images, ``--additional-inputs '**/cam_front/*.jpg'``.""", ) parser.add_argument( "--parameter-value", @@ -186,8 +178,8 @@ def create_setup_parser(parser): nargs="*", action=KeyValuePairsAction, help=( - "Zero or more '=' pairs to pass to the invocation. " - "`parameter_value` is parsed as JSON. " + "Zero or more ``=`` pairs to pass to the invocation. " + "``parameter_value`` is parsed as JSON." ), ) parser.add_argument( @@ -227,9 +219,9 @@ def create_setup_parser(parser): nargs="*", action=KeyValuePairsAction, help="Dataset metadata " - + "key=value conditions which all must be met for this trigger to run against a given dataset. " + + "``key=value`` conditions which all must be met for this trigger to run against a given dataset. " + "If provided, these are used to construct a trigger condition, and as such they cannot be " - + "used if 'condition-json' is specified.", + + "used if ``condition-json`` is specified.", ) @@ -305,14 +297,12 @@ def update_setup_parser(parser): type=str, nargs="+", action="extend", - # fmt: off - help=textwrap.dedent("""\ - One or many file patterns for data to download from the data source. Examples: - front camera images, "--input-data '**/cam_front/*.jpg'"; - front and rear camera images, "--input-data '**/cam_front/*.jpg' --input-data '**/cam_rear/*.jpg'"; - all data, "--input-data '**/*'" - """), - # fmt: on + help="""\ + One or many file patterns for data to download from the data source. Examples: + front camera images, ``--required-inputs '**/cam_front/*.jpg'``; + front and rear camera images, ``--required-inputs '**/cam_front/*.jpg' --required-inputs '**/cam_rear/*.jpg'``; + all data, ``--required-inputs '**/*'``. + """, ) parser.add_argument( "--additional-inputs", @@ -320,15 +310,10 @@ def update_setup_parser(parser): type=str, nargs="+", action="extend", - # fmt: off - help=textwrap.dedent("""\ - One or many file patterns for data to download from the data source which is NOT considered as part of - trigger evaluation. Examples: - front camera images, "--input-data '**/cam_front/*.jpg'"; - front and rear camera images, "--input-data '**/cam_front/*.jpg' --input-data '**/cam_rear/*.jpg'"; - all data, "--input-data '**/*'" - """), - # fmt: on + help="""\ + One or many file patterns for data to download from the data source which is NOT considered as part of + trigger evaluation. Example: + front camera images, ``--additional-inputs '**/cam_front/*.jpg'``.""", ) parser.add_argument( @@ -385,8 +370,8 @@ def update_setup_parser(parser): nargs="*", action=KeyValuePairsAction, help=( - "Zero or more '=' pairs to pass to the invocation. " - "`parameter_value` is parsed as JSON. " + "Zero or more ``=`` pairs to pass to the invocation. " + "``parameter_value`` is parsed as JSON. " ), ) diff --git a/src/roboto/cli/users/commands.py b/src/roboto/cli/users/commands.py index 367d290..0ab57b6 100644 --- a/src/roboto/cli/users/commands.py +++ b/src/roboto/cli/users/commands.py @@ -6,7 +6,6 @@ import argparse import json -import sys from ...domain.orgs import Org from ...domain.users import User @@ -20,7 +19,7 @@ def show(args, context: CLIContext, parser: argparse.ArgumentParser): user = User.from_id(user_id=args.id, roboto_client=context.roboto_client).to_dict() - sys.stdout.write(json.dumps(user) + "\n") + print(json.dumps(user, indent=2)) def show_setup_parser(parser): @@ -33,16 +32,14 @@ def show_setup_parser(parser): def delete(args, context: CLIContext, parser: argparse.ArgumentParser): if not args.ignore_prompt: - sys.stdout.write( - "Are you absolutely sure you want to delete your user? [y/n]: " - ) + print("Are you absolutely sure you want to delete your user? [y/n]:", end=" ") choice = input().lower() if choice not in ["y", "yes"]: return user = User.from_id(user_id=args.id, roboto_client=context.roboto_client) user.delete() - sys.stdout.write(f"Successfully deleted user '{args.id}'\n") + print(f"Successfully deleted user '{args.id}'") def delete_setup_parser(parser): @@ -61,7 +58,7 @@ def delete_setup_parser(parser): def orgs(args, context: CLIContext, parser: argparse.ArgumentParser): records = Org.for_self(roboto_client=context.roboto_client) for record in records: - sys.stdout.write(json.dumps(record.to_dict()) + "\n") + print(json.dumps(record.to_dict(), indent=2)) def whoami(args, context: CLIContext, parser: argparse.ArgumentParser): @@ -69,7 +66,7 @@ def whoami(args, context: CLIContext, parser: argparse.ArgumentParser): contents = context.http_client.get( context.http_client.url("v1/users/whoami") ).to_dict(json_path=["data"]) - sys.stdout.write(json.dumps(contents) + "\n") + print(json.dumps(contents, indent=2)) delete_command = RobotoCommand( diff --git a/src/roboto/version.py b/src/roboto/version.py index a38929e..aa0f251 100644 --- a/src/roboto/version.py +++ b/src/roboto/version.py @@ -1,4 +1,4 @@ -__version__ = "0.5.5" +__version__ = "0.5.6" __all__= ("__version__",) \ No newline at end of file