From fde190d669e3fab732eb63fae048ee02a171c294 Mon Sep 17 00:00:00 2001 From: Maciej Urbanski Date: Tue, 21 Nov 2023 19:13:23 +0100 Subject: [PATCH] deprecate commands replaced by B2 URI using equivalents --- b2/arg_parser.py | 20 +++-- b2/console_tool.py | 90 ++++++++++++++------ changelog.d/+b2_uri_cmds.deprecated.md | 3 + test/integration/test_autocomplete.py | 21 +---- test/integration/test_b2_command_line.py | 56 ++++++------ test/unit/console_tool/test_download_file.py | 15 +++- test/unit/console_tool/test_file_info.py | 1 + test/unit/console_tool/test_get_url.py | 2 + test/unit/test_arg_parser.py | 4 +- test/unit/test_console_tool.py | 30 +++---- 10 files changed, 144 insertions(+), 98 deletions(-) create mode 100644 changelog.d/+b2_uri_cmds.deprecated.md diff --git a/b2/arg_parser.py b/b2/arg_parser.py index 9a0e0d4e4..9420ac51e 100644 --- a/b2/arg_parser.py +++ b/b2/arg_parser.py @@ -7,6 +7,7 @@ # License https://www.backblaze.com/using_b2_code.html # ###################################################################### +from __future__ import annotations import argparse import functools @@ -22,11 +23,11 @@ _arrow_version = tuple(int(p) for p in arrow.__version__.split(".")) -class RawTextHelpFormatter(argparse.RawTextHelpFormatter): +class B2RawTextHelpFormatter(argparse.RawTextHelpFormatter): """ CLI custom formatter. - It removes default "usage: " text and prints usage for all subcommands. + It removes default "usage: " text and prints usage for all (non-hidden) subcommands. """ def add_usage(self, usage, actions, groups, prefix=None): @@ -38,7 +39,8 @@ def add_argument(self, action): if isinstance(action, argparse._SubParsersAction) and action.help is not argparse.SUPPRESS: usages = [] for choice in self._unique_choice_values(action): - usages.append(choice.format_usage()) + if not getattr(choice, 'hidden', False): + usages.append(choice.format_usage()) self.add_text(''.join(usages)) else: super().add_argument(action) @@ -52,7 +54,7 @@ def _unique_choice_values(cls, action): yield value -class ArgumentParser(argparse.ArgumentParser): +class B2ArgumentParser(argparse.ArgumentParser): """ CLI custom parser. @@ -60,11 +62,17 @@ class ArgumentParser(argparse.ArgumentParser): and use help message in case of error. """ - def __init__(self, *args, for_docs=False, **kwargs): + def __init__(self, *args, for_docs: bool = False, hidden: bool = False, **kwargs): + """ + + :param for_docs: is this parser used for generating docs + :param hidden: should this parser be hidden from `--help` + """ self._raw_description = None self._description = None self._for_docs = for_docs - kwargs.setdefault('formatter_class', RawTextHelpFormatter) + self.hidden = hidden + kwargs.setdefault('formatter_class', B2RawTextHelpFormatter) super().__init__(*args, **kwargs) @property diff --git a/b2/console_tool.py b/b2/console_tool.py index 97efc8e90..2e79d4410 100644 --- a/b2/console_tool.py +++ b/b2/console_tool.py @@ -126,7 +126,7 @@ from b2._cli.shell import detect_shell from b2._utils.uri import B2URI, B2FileIdURI, B2URIAdapter, B2URIBase from b2.arg_parser import ( - ArgumentParser, + B2ArgumentParser, parse_comma_separated_list, parse_default_retention_period, parse_millis_from_float_timestamp, @@ -623,6 +623,8 @@ class Command(Described): # Set to True for commands that receive sensitive information in arguments FORBID_LOGGING_ARGUMENTS = False + hide_from_help = False + # The registry for the subcommands, should be reinitialized in subclass subcommands_registry = None @@ -652,28 +654,38 @@ def register_subcommand(cls, command_class): return decorator @classmethod - def get_parser(cls, subparsers=None, parents=None, for_docs=False): + def create_parser( + cls, subparsers: "argparse._SubParsersAction | None" = None, parents=None, for_docs=False + ) -> argparse.ArgumentParser: + """ + Creates a parser for the command. + + :param subparsers: subparsers object to which add new parser + :param parents: created ArgumentParser `parents`, see `argparse.ArgumentParser` + :param for_docs: if parser is to be used for documentation generation + :return: created parser + """ if parents is None: parents = [] description = cls._get_description() + name, alias = cls.name_and_alias() + parser_kwargs = dict( + prog=name, + description=description, + parents=parents, + for_docs=for_docs, + hidden=cls.hide_from_help, + ) + if subparsers is None: - name, _ = cls.name_and_alias() - parser = ArgumentParser( - prog=name, - description=description, - parents=parents, - for_docs=for_docs, - ) + parser = B2ArgumentParser(**parser_kwargs,) else: - name, alias = cls.name_and_alias() parser = subparsers.add_parser( - name, - description=description, - parents=parents, + parser_kwargs.pop('prog'), + **parser_kwargs, aliases=[alias] if alias is not None and not for_docs else (), - for_docs=for_docs, ) # Register class that will handle this particular command, for both name and alias. parser.set_defaults(command_class=cls) @@ -682,7 +694,7 @@ def get_parser(cls, subparsers=None, parents=None, for_docs=False): if cls.subcommands_registry: if not parents: - common_parser = ArgumentParser(add_help=False) + common_parser = B2ArgumentParser(add_help=False) common_parser.add_argument( '--debugLogs', action='store_true', help=argparse.SUPPRESS ) @@ -694,10 +706,15 @@ def get_parser(cls, subparsers=None, parents=None, for_docs=False): ) parents = [common_parser] - subparsers = parser.add_subparsers(prog=parser.prog, title='usages', dest='command') + subparsers = parser.add_subparsers( + prog=parser.prog, + title='usages', + dest='command', + parser_class=B2ArgumentParser, + ) subparsers.required = True for subcommand in cls.subcommands_registry.values(): - subcommand.get_parser(subparsers=subparsers, parents=parents, for_docs=for_docs) + subcommand.create_parser(subparsers=subparsers, parents=parents, for_docs=for_docs) return parser @@ -781,6 +798,26 @@ def __str__(self): return f'{self.__class__.__module__}.{self.__class__.__name__}' +class CmdReplacedByMixin: + hide_from_help = True + replaced_by_cmd: "type[Command]" + + def run(self, args): + self._print_stderr( + f'WARNING: {self.__class__.name_and_alias()[0]} command is deprecated. ' + f'Use {self.replaced_by_cmd.name_and_alias()[0]} instead.' + ) + return super().run(args) + + @classmethod + def _get_description(cls): + return ( + f'{super()._get_description()}\n\n' + f'.. warning::\n' + f' This command is deprecated. Use ``{cls.replaced_by_cmd.name_and_alias()[0]}`` instead.\n' + ) + + class B2(Command): """ This program provides command-line access to the B2 service. @@ -1509,8 +1546,9 @@ def get_b2_uri_from_arg(self, args: argparse.Namespace) -> B2URIBase: @B2.register_subcommand -class DownloadFileById(B2URIFileIDArgMixin, DownloadFileBase): +class DownloadFileById(CmdReplacedByMixin, B2URIFileIDArgMixin, DownloadFileBase): __doc__ = DownloadFileBase.__doc__ + replaced_by_cmd = DownloadFile @classmethod def _setup_parser(cls, parser): @@ -1519,8 +1557,9 @@ def _setup_parser(cls, parser): @B2.register_subcommand -class DownloadFileByName(B2URIBucketNFilenameArgMixin, DownloadFileBase): +class DownloadFileByName(CmdReplacedByMixin, B2URIBucketNFilenameArgMixin, DownloadFileBase): __doc__ = DownloadFileBase.__doc__ + replaced_by_cmd = DownloadFile @classmethod def _setup_parser(cls, parser): @@ -1671,8 +1710,9 @@ class FileInfo(B2URIFileArgMixin, FileInfoBase): @B2.register_subcommand -class GetFileInfo(B2URIFileIDArgMixin, FileInfoBase): +class GetFileInfo(CmdReplacedByMixin, B2URIFileIDArgMixin, FileInfoBase): __doc__ = FileInfoBase.__doc__ + replaced_by_cmd = FileInfo @B2.register_subcommand @@ -2347,13 +2387,15 @@ class GetUrl(B2URIFileArgMixin, GetUrlBase): @B2.register_subcommand -class MakeUrl(B2URIFileIDArgMixin, GetUrlBase): +class MakeUrl(CmdReplacedByMixin, B2URIFileIDArgMixin, GetUrlBase): __doc__ = GetUrlBase.__doc__ + replaced_by_cmd = GetUrl @B2.register_subcommand -class MakeFriendlyUrl(B2URIBucketNFilenameArgMixin, GetUrlBase): +class MakeFriendlyUrl(CmdReplacedByMixin, B2URIBucketNFilenameArgMixin, GetUrlBase): __doc__ = GetUrlBase.__doc__ + replaced_by_cmd = GetUrl @B2.register_subcommand @@ -3821,7 +3863,7 @@ def __init__(self, b2_api: Optional[B2Api], stdout, stderr): def run_command(self, argv): signal.signal(signal.SIGINT, keyboard_interrupt_handler) - parser = B2.get_parser() + parser = B2.create_parser() argcomplete.autocomplete(parser, default_completer=None) args = parser.parse_args(argv[1:]) self._setup_logging(args, argv) @@ -3959,7 +4001,7 @@ def _setup_logging(cls, args, argv): # used by Sphinx -get_parser = functools.partial(B2.get_parser, for_docs=True) +get_parser = functools.partial(B2.create_parser, for_docs=True) # TODO: import from b2sdk as soon as we rely on 1.0.0 diff --git a/changelog.d/+b2_uri_cmds.deprecated.md b/changelog.d/+b2_uri_cmds.deprecated.md new file mode 100644 index 000000000..98aeead6b --- /dev/null +++ b/changelog.d/+b2_uri_cmds.deprecated.md @@ -0,0 +1,3 @@ +Deprecated `download-file-by-id` and `download-file-by-name`, use `download-file` instead. +Deprecated `get-file-info`, use `file-info` instead. +Deprecated `make-url` and `make-friendly-url`, use `get-url` instead. diff --git a/test/integration/test_autocomplete.py b/test/integration/test_autocomplete.py index d798ba859..6e5b0bd38 100644 --- a/test/integration/test_autocomplete.py +++ b/test/integration/test_autocomplete.py @@ -60,7 +60,7 @@ def test_autocomplete_b2_commands(autocomplete_installed, is_running_on_docker, if is_running_on_docker: pytest.skip('Not supported on Docker') shell.send('b2 \t\t') - shell.expect_exact(["authorize-account", "download-file-by-id", "get-bucket"], timeout=TIMEOUT) + shell.expect_exact(["authorize-account", "download-file", "get-bucket"], timeout=TIMEOUT) @skip_on_windows @@ -69,28 +69,13 @@ def test_autocomplete_b2_only_matching_commands( ): if is_running_on_docker: pytest.skip('Not supported on Docker') - shell.send('b2 download-\t\t') + shell.send('b2 delete-\t\t') - shell.expect_exact( - "file-by-", timeout=TIMEOUT - ) # common part of remaining cmds is autocompleted + shell.expect_exact("file", timeout=TIMEOUT) # common part of remaining cmds is autocompleted with pytest.raises(pexpect.exceptions.TIMEOUT): # no other commands are suggested shell.expect_exact("get-bucket", timeout=0.5) -@skip_on_windows -def test_autocomplete_b2_bucket_n_file_name( - autocomplete_installed, shell, b2_tool, bucket_name, file_name, is_running_on_docker -): - """Test that autocomplete suggests bucket names and file names.""" - if is_running_on_docker: - pytest.skip('Not supported on Docker') - shell.send('b2 download_file_by_name \t\t') - shell.expect_exact(bucket_name, timeout=TIMEOUT) - shell.send(f'{bucket_name} \t\t') - shell.expect_exact(file_name, timeout=TIMEOUT) - - @skip_on_windows def test_autocomplete_b2__download_file__b2uri( autocomplete_installed, shell, b2_tool, bucket_name, file_name, is_running_on_docker diff --git a/test/integration/test_b2_command_line.py b/test/integration/test_b2_command_line.py index 3c8269a0b..5bb44f184 100755 --- a/test/integration/test_b2_command_line.py +++ b/test/integration/test_b2_command_line.py @@ -67,7 +67,7 @@ def test_download(b2_tool, bucket_name, sample_filepath, uploaded_sample_file, t output_a = tmp_path / 'a' b2_tool.should_succeed( [ - 'download-file-by-name', '--quiet', bucket_name, uploaded_sample_file['fileName'], + 'download-file', '--quiet', f"b2://{bucket_name}/{uploaded_sample_file['fileName']}", str(output_a) ] ) @@ -75,7 +75,7 @@ def test_download(b2_tool, bucket_name, sample_filepath, uploaded_sample_file, t output_b = tmp_path / 'b' b2_tool.should_succeed( - ['download-file-by-id', '--quiet', uploaded_sample_file['fileId'], + ['download-file', '--quiet', f"b2id://{uploaded_sample_file['fileId']}", str(output_b)] ) assert output_b.read_text() == sample_filepath.read_text() @@ -127,9 +127,7 @@ def test_basic(b2_tool, bucket_name, sample_file, tmp_path): should_equal(['rm1'], [f['fileName'] for f in list_of_files]) b2_tool.should_succeed(['rm', '--recursive', '--withWildcard', bucket_name, 'rm1']) - b2_tool.should_succeed( - ['download-file-by-name', '--noProgress', '--quiet', bucket_name, 'b/1', tmp_path / 'a'] - ) + b2_tool.should_succeed(['download-file', '--quiet', f'b2://{bucket_name}/b/1', tmp_path / 'a']) b2_tool.should_succeed(['hide-file', bucket_name, 'c']) @@ -597,7 +595,7 @@ def sync_up_helper(b2_tool, bucket_name, dir_, encryption=None): return # that's enough, we've checked that encryption works, no need to repeat the whole sync suite c_id = find_file_id(file_versions, prefix + 'c') - file_info = b2_tool.should_succeed_json(['get-file-info', c_id])['fileInfo'] + file_info = b2_tool.should_succeed_json(['file-info', f"b2id://{c_id}"])['fileInfo'] should_equal( file_mod_time_millis(dir_path / 'c'), int(file_info['src_last_modified_millis']) ) @@ -1151,12 +1149,12 @@ def test_sse_b2(b2_tool, bucket_name, sample_file, tmp_path): b2_tool.should_succeed(['upload-file', '--quiet', bucket_name, sample_file, 'not_encrypted']) b2_tool.should_succeed( - ['download-file-by-name', '--quiet', bucket_name, 'encrypted', tmp_path / 'encrypted'] + ['download-file', '--quiet', f'b2://{bucket_name}/encrypted', tmp_path / 'encrypted'] ) b2_tool.should_succeed( [ - 'download-file-by-name', '--quiet', bucket_name, 'not_encrypted', - tmp_path / 'not_encypted' + 'download-file', '--quiet', f'b2://{bucket_name}/not_encrypted', + tmp_path / 'not_encrypted' ] ) @@ -1171,10 +1169,12 @@ def test_sse_b2(b2_tool, bucket_name, sample_file, tmp_path): ) encrypted_version = list_of_files[0] - file_info = b2_tool.should_succeed_json(['get-file-info', encrypted_version['fileId']]) + file_info = b2_tool.should_succeed_json(['file-info', f"b2id://{encrypted_version['fileId']}"]) should_equal({'algorithm': 'AES256', 'mode': 'SSE-B2'}, file_info['serverSideEncryption']) not_encrypted_version = list_of_files[1] - file_info = b2_tool.should_succeed_json(['get-file-info', not_encrypted_version['fileId']]) + file_info = b2_tool.should_succeed_json( + ['file-info', f"b2id://{not_encrypted_version['fileId']}"] + ) should_equal({'mode': 'none'}, file_info['serverSideEncryption']) b2_tool.should_succeed( @@ -1198,12 +1198,14 @@ def test_sse_b2(b2_tool, bucket_name, sample_file, tmp_path): ) copied_encrypted_version = list_of_files[2] - file_info = b2_tool.should_succeed_json(['get-file-info', copied_encrypted_version['fileId']]) + file_info = b2_tool.should_succeed_json( + ['file-info', f"b2id://{copied_encrypted_version['fileId']}"] + ) should_equal({'algorithm': 'AES256', 'mode': 'SSE-B2'}, file_info['serverSideEncryption']) copied_not_encrypted_version = list_of_files[3] file_info = b2_tool.should_succeed_json( - ['get-file-info', copied_not_encrypted_version['fileId']] + ['file-info', f"b2id://{copied_not_encrypted_version['fileId']}"] ) should_equal({'mode': 'none'}, file_info['serverSideEncryption']) @@ -1245,25 +1247,22 @@ def test_sse_c(b2_tool, bucket_name, is_running_on_docker, sample_file, tmp_path should_equal(sse_c_key_id, file_version_info['fileInfo'][SSE_C_KEY_ID_FILE_INFO_KEY_NAME]) b2_tool.should_fail( - [ - 'download-file-by-name', '--quiet', bucket_name, 'uploaded_encrypted', - 'gonna_fail_anyway' - ], + ['download-file', '--quiet', f'b2://{bucket_name}/uploaded_encrypted', 'gonna_fail_anyway'], expected_pattern='ERROR: The object was stored using a form of Server Side Encryption. The ' r'correct parameters must be provided to retrieve the object. \(bad_request\)' ) b2_tool.should_fail( [ - 'download-file-by-name', '--quiet', '--sourceServerSideEncryption', 'SSE-C', - bucket_name, 'uploaded_encrypted', 'gonna_fail_anyway' + 'download-file', '--quiet', '--sourceServerSideEncryption', 'SSE-C', + f'b2://{bucket_name}/uploaded_encrypted', 'gonna_fail_anyway' ], expected_pattern='ValueError: Using SSE-C requires providing an encryption key via ' 'B2_SOURCE_SSE_C_KEY_B64 env var' ) b2_tool.should_fail( [ - 'download-file-by-name', '--quiet', '--sourceServerSideEncryption', 'SSE-C', - bucket_name, 'uploaded_encrypted', 'gonna_fail_anyway' + 'download-file', '--quiet', '--sourceServerSideEncryption', 'SSE-C', + f'b2://{bucket_name}/uploaded_encrypted', 'gonna_fail_anyway' ], expected_pattern='ERROR: Wrong or no SSE-C key provided when reading a file.', additional_env={'B2_SOURCE_SSE_C_KEY_B64': base64.b64encode(os.urandom(32)).decode()} @@ -1271,13 +1270,12 @@ def test_sse_c(b2_tool, bucket_name, is_running_on_docker, sample_file, tmp_path with contextlib.nullcontext(tmp_path) as dir_path: b2_tool.should_succeed( [ - 'download-file-by-name', + 'download-file', '--noProgress', '--quiet', '--sourceServerSideEncryption', 'SSE-C', - bucket_name, - 'uploaded_encrypted', + f'b2://{bucket_name}/uploaded_encrypted', dir_path / 'a', ], additional_env={'B2_SOURCE_SSE_C_KEY_B64': base64.b64encode(secret).decode()} @@ -1285,12 +1283,12 @@ def test_sse_c(b2_tool, bucket_name, is_running_on_docker, sample_file, tmp_path assert read_file(dir_path / 'a') == read_file(sample_file) b2_tool.should_succeed( [ - 'download-file-by-id', + 'download-file', '--noProgress', '--quiet', '--sourceServerSideEncryption', 'SSE-C', - file_version_info['fileId'], + f"b2id://{file_version_info['fileId']}", dir_path / 'b', ], additional_env={'B2_SOURCE_SSE_C_KEY_B64': base64.b64encode(secret).decode()} @@ -2595,7 +2593,7 @@ def _assert_file_lock_configuration( legal_hold: LegalHold | None = None ): - file_version = b2_tool.should_succeed_json(['get-file-info', file_id]) + file_version = b2_tool.should_succeed_json(['file-info', f"b2id://{file_id}"]) if retention_mode is not None: if file_version['fileRetention']['mode'] == 'unknown': actual_file_retention = UNKNOWN_FILE_RETENTION_SETTING @@ -2677,10 +2675,10 @@ def test_download_file_stdout( b2_tool, bucket_name, sample_filepath, tmp_path, uploaded_sample_file ): assert b2_tool.should_succeed( - ['download-file-by-name', '--quiet', bucket_name, uploaded_sample_file['fileName'], '-'], + ['download-file', '--quiet', f"b2://{bucket_name}/{uploaded_sample_file['fileName']}", '-'], ).replace("\r", "") == sample_filepath.read_text() assert b2_tool.should_succeed( - ['download-file-by-id', '--quiet', uploaded_sample_file['fileId'], '-'], + ['download-file', '--quiet', f"b2id://{uploaded_sample_file['fileId']}", '-'], ).replace("\r", "") == sample_filepath.read_text() diff --git a/test/unit/console_tool/test_download_file.py b/test/unit/console_tool/test_download_file.py index 13ae320f9..a7a942cff 100644 --- a/test/unit/console_tool/test_download_file.py +++ b/test/unit/console_tool/test_download_file.py @@ -73,7 +73,9 @@ def test_download_file_by_name(b2_cli, local_file, uploaded_file, tmp_path, flag 'download-file-by-name', uploaded_file['bucket'], uploaded_file['fileName'], str(output_path) ], - expected_stdout=EXPECTED_STDOUT_DOWNLOAD + expected_stdout=EXPECTED_STDOUT_DOWNLOAD, + expected_stderr= + 'WARNING: download-file-by-name command is deprecated. Use download-file instead.\n', ) assert output_path.read_text() == uploaded_file['content'] @@ -89,7 +91,10 @@ def test_download_file_by_id(b2_cli, uploaded_file, tmp_path, flag, expected_std output_path = tmp_path / 'output.txt' b2_cli.run( - ['download-file-by-id', flag, '9999', str(output_path)], expected_stdout=expected_stdout + ['download-file-by-id', flag, '9999', str(output_path)], + expected_stdout=expected_stdout, + expected_stderr= + 'WARNING: download-file-by-id command is deprecated. Use download-file instead.\n', ) assert output_path.read_text() == uploaded_file['content'] @@ -115,7 +120,9 @@ def reader(): uploaded_file['fileName'], str(output_path) ], - expected_stdout=EXPECTED_STDOUT_DOWNLOAD + expected_stdout=EXPECTED_STDOUT_DOWNLOAD, + expected_stderr= + 'WARNING: download-file-by-name command is deprecated. Use download-file instead.\n', ) reader_future.result(timeout=1) assert output_string == uploaded_file['content'] @@ -138,6 +145,8 @@ def test_download_file_by_name__to_stdout_by_alias( """Test download_file_by_name stdout alias support""" b2_cli.run( ['download-file-by-name', '--noProgress', bucket, uploaded_stdout_txt['fileName'], '-'], + expected_stderr= + 'WARNING: download-file-by-name command is deprecated. Use download-file instead.\n', ) assert capfd.readouterr().out == uploaded_stdout_txt['content'] assert not pathlib.Path('-').exists() diff --git a/test/unit/console_tool/test_file_info.py b/test/unit/console_tool/test_file_info.py index 4cfb7e84a..e3fed5325 100644 --- a/test/unit/console_tool/test_file_info.py +++ b/test/unit/console_tool/test_file_info.py @@ -42,6 +42,7 @@ def test_get_file_info(b2_cli, uploaded_file_version): b2_cli.run( ["get-file-info", uploaded_file_version["fileId"]], expected_json_in_stdout=uploaded_file_version, + expected_stderr='WARNING: get-file-info command is deprecated. Use file-info instead.\n', ) diff --git a/test/unit/console_tool/test_get_url.py b/test/unit/console_tool/test_get_url.py index 9c4ebf98b..740d773fb 100644 --- a/test/unit/console_tool/test_get_url.py +++ b/test/unit/console_tool/test_get_url.py @@ -24,6 +24,7 @@ def test_make_url(b2_cli, uploaded_file, uploaded_file_url_by_id): b2_cli.run( ["make-url", uploaded_file["fileId"]], expected_stdout=f"{uploaded_file_url_by_id}\n", + expected_stderr='WARNING: make-url command is deprecated. Use get-url instead.\n', ) @@ -31,6 +32,7 @@ def test_make_friendly_url(b2_cli, bucket, uploaded_file, uploaded_file_url): b2_cli.run( ["make-friendly-url", bucket, uploaded_file["fileName"]], expected_stdout=f"{uploaded_file_url}\n", + expected_stderr='WARNING: make-friendly-url command is deprecated. Use get-url instead.\n', ) diff --git a/test/unit/test_arg_parser.py b/test/unit/test_arg_parser.py index a615f82b1..127551e8d 100644 --- a/test/unit/test_arg_parser.py +++ b/test/unit/test_arg_parser.py @@ -12,7 +12,7 @@ import sys from b2.arg_parser import ( - ArgumentParser, + B2ArgumentParser, parse_comma_separated_list, parse_millis_from_float_timestamp, parse_range, @@ -61,7 +61,7 @@ def check_help_string(self, command_class, command_name): help_string = command_class.__doc__ # create a parser with a help message that is based on the command_class.__doc__ string - parser = ArgumentParser(description=help_string) + parser = B2ArgumentParser(description=help_string) try: old_stdout = sys.stdout diff --git a/test/unit/test_console_tool.py b/test/unit/test_console_tool.py index 0e969c362..dd58ac162 100644 --- a/test/unit/test_console_tool.py +++ b/test/unit/test_console_tool.py @@ -927,7 +927,7 @@ def test_files(self): } self._run_command( - ['get-file-info', '9999'], + ['file-info', 'b2id://9999'], expected_json_in_stdout=expected_json, ) @@ -1074,7 +1074,7 @@ def test_files_encrypted(self): } self._run_command( - ['get-file-info', '9999'], + ['file-info', 'b2id://9999'], expected_json_in_stdout=expected_json, ) @@ -1095,10 +1095,8 @@ def test_files_encrypted(self): ''' self._run_command( - [ - 'download-file-by-name', '--noProgress', 'my-bucket', 'file1.txt', - local_download1 - ], expected_stdout, '', 0 + ['download-file', '--noProgress', 'b2://my-bucket/file1.txt', local_download1], + expected_stdout, '', 0 ) self.assertEqual(b'hello world', self._read_file(local_download1)) self.assertEqual(mod_time, int(round(os.path.getmtime(local_download1)))) @@ -1106,7 +1104,7 @@ def test_files_encrypted(self): # Download file by ID. (Same expected output as downloading by name) local_download2 = os.path.join(temp_dir, 'download2.txt') self._run_command( - ['download-file-by-id', '--noProgress', '9999', local_download2], expected_stdout, + ['download-file', '--noProgress', 'b2id://9999', local_download2], expected_stdout, '', 0 ) self.assertEqual(b'hello world', self._read_file(local_download2)) @@ -1207,7 +1205,11 @@ def _test_download_threads(self, download_by, num_threads): command += ['9999'] if download_by == 'id' else ['my-bucket', 'file.txt'] local_download = os.path.join(temp_dir, 'download.txt') command += [local_download] - self._run_command(command) + self._run_command( + command, + expected_stderr= + f'WARNING: download-file-by-{download_by} command is deprecated. Use download-file instead.\n' + ) self.assertEqual(b'hello world', self._read_file(local_download)) def test_download_by_id_1_thread(self): @@ -1309,10 +1311,7 @@ def test_copy_file_by_id(self): local_download1 = os.path.join(temp_dir, 'file1_copy.txt') self._run_command( - [ - 'download-file-by-name', '--noProgress', 'my-bucket', 'file1_copy.txt', - local_download1 - ] + ['download-file', '-q', 'b2://my-bucket/file1_copy.txt', local_download1] ) self.assertEqual(b'lo wo', self._read_file(local_download1)) @@ -1568,10 +1567,9 @@ def test_upload_incremental(self): downloaded_path = pathlib.Path(temp_dir) / 'out.txt' self._run_command( [ - 'download-file-by-name', - '--noProgress', - 'my-bucket', - 'test.txt', + 'download-file', + '-q', + 'b2://my-bucket/test.txt', str(downloaded_path), ] )