diff --git a/b2/_internal/arg_parser.py b/b2/_internal/arg_parser.py index c13dc5ba..ed907a47 100644 --- a/b2/_internal/arg_parser.py +++ b/b2/_internal/arg_parser.py @@ -54,7 +54,7 @@ def add_argument(self, action): def _unique_choice_values(cls, action): seen = set() seen_add = seen.add - for value in action.choices.values(): + for _, value in sorted(action.choices.items()): if not (value in seen or seen_add(value)): yield value @@ -150,6 +150,11 @@ def print_help(self, *args, show_all: bool = False, **kwargs): super().print_help(*args, **kwargs) def format_usage(self): + """ + Format usage message. + + Deduplicate subcommands aliases if they only differ by underscores. + """ # TODO We don't want to list underscore aliases subcommands in the usage. # Unfortunately the only way found was to temporarily remove the aliases, # print the usage and then restore the aliases since the formatting is deep @@ -163,10 +168,13 @@ def format_usage(self): if isinstance(action, argparse._SubParsersAction): subparsers_action = action original_choices = action.choices - action.choices = { - key: choice - for key, choice in action.choices.items() if "_" not in key - } + action.choices = {} + choice_values = set() + # sort alphabetically; this also makes `-` come before `_` + for key, choice in sorted(original_choices.items()): + if choice not in choice_values: + action.choices[key] = choice + choice_values.add(choice) # only one subparser supported break usage = super().format_usage() diff --git a/b2/_internal/console_tool.py b/b2/_internal/console_tool.py index 2d0238c6..e011ebe3 100644 --- a/b2/_internal/console_tool.py +++ b/b2/_internal/console_tool.py @@ -3487,7 +3487,7 @@ def execute_operation(self, local_file, bucket, threads, **kwargs): return file_version -class UploadUnboundStream(UploadFileMixin, Command): +class UploadUnboundStreamBase(UploadFileMixin, Command): """ Uploads an unbound stream to the given bucket. @@ -5085,6 +5085,11 @@ class UploadFile(CmdReplacedByMixin, FileUploadBase): replaced_by_cmd = (File, FileUpload) +class UploadUnboundStream(CmdReplacedByMixin, UploadUnboundStreamBase): + __doc__ = UploadUnboundStreamBase.__doc__ + replaced_by_cmd = (File, FileUpload) + + class DownloadFile(CmdReplacedByMixin, B2URIFileArgMixin, FileDownloadBase): __doc__ = FileDownloadBase.__doc__ replaced_by_cmd = (File, FileDownload) diff --git a/changelog.d/+sort_help.doc.md b/changelog.d/+sort_help.doc.md new file mode 100644 index 00000000..d48da79d --- /dev/null +++ b/changelog.d/+sort_help.doc.md @@ -0,0 +1 @@ +Sort subcommands in `--help` alphabetically for better readability. diff --git a/test/unit/console_tool/test_upload_unbound_stream.py b/test/unit/console_tool/test_upload_unbound_stream.py index fc00f9ed..ebc6899c 100644 --- a/test/unit/console_tool/test_upload_unbound_stream.py +++ b/test/unit/console_tool/test_upload_unbound_stream.py @@ -12,6 +12,8 @@ from b2sdk.v2 import DEFAULT_MIN_PART_SIZE +UUS_DEPRECATION_WARNING = 'WARNING: `upload-unbound-stream` command is deprecated. Use `file upload` instead.\n' + @skip_on_windows def test_upload_unbound_stream__named_pipe(b2_cli, bucket, tmpdir, bg_executor): @@ -35,6 +37,7 @@ def test_upload_unbound_stream__named_pipe(b2_cli, bucket, tmpdir, bg_executor): expected_json_in_stdout=expected_json, remove_version=True, expected_part_of_stdout=expected_stdout, + expected_stderr=UUS_DEPRECATION_WARNING, ) writer.result(timeout=1) @@ -59,6 +62,7 @@ def test_upload_unbound_stream__stdin(b2_cli, bucket, tmpdir, mock_stdin): expected_json_in_stdout=expected_json, remove_version=True, expected_part_of_stdout=expected_stdout, + expected_stderr=UUS_DEPRECATION_WARNING, ) @@ -99,6 +103,7 @@ def test_upload_unbound_stream__with_part_size_options( expected_json_in_stdout=expected_json, remove_version=True, expected_part_of_stdout=expected_stdout, + expected_stderr=UUS_DEPRECATION_WARNING, ) writer.result(timeout=1) @@ -124,6 +129,6 @@ def test_upload_unbound_stream__regular_file(b2_cli, bucket, tmpdir): expected_json_in_stdout=expected_json, remove_version=True, expected_part_of_stdout=expected_stdout, - expected_stderr= + expected_stderr=f"{UUS_DEPRECATION_WARNING}" "WARNING: You are using a stream upload command to upload a regular file. While it will work, it is inefficient. Use of `file upload` command is recommended.\n", )