From e7ff9f60204c5119314ca19bb9f2d2975064ac71 Mon Sep 17 00:00:00 2001 From: Adal Chiriliuc Date: Thu, 25 Apr 2024 19:12:47 +0300 Subject: [PATCH] use file download subcommand --- b2/_internal/console_tool.py | 40 ++++++++++--------- test/integration/test_autocomplete.py | 2 +- test/integration/test_b2_command_line.py | 42 +++++++++++++------- test/unit/_cli/test_autocomplete_cache.py | 2 +- test/unit/console_tool/test_download_file.py | 18 ++++----- test/unit/console_tool/test_help.py | 4 +- test/unit/test_console_tool.py | 14 ++++--- 7 files changed, 69 insertions(+), 53 deletions(-) diff --git a/b2/_internal/console_tool.py b/b2/_internal/console_tool.py index c164c4318..149aae175 100644 --- a/b2/_internal/console_tool.py +++ b/b2/_internal/console_tool.py @@ -1881,7 +1881,7 @@ def get_local_output_filepath( return pathlib.Path(output_filepath_str) -class DownloadFileBase( +class FileDownloadBase( ThreadsMixin, MaxDownloadStreamsMixin, DownloadCommand, @@ -1928,23 +1928,6 @@ def _run(self, args): return 0 -class DownloadFile(B2URIFileArgMixin, DownloadFileBase): - __doc__ = DownloadFileBase.__doc__ - - def get_b2_uri_from_arg(self, args: argparse.Namespace) -> B2URIBase: - return args.B2_URI - - -class DownloadFileById(CmdReplacedByMixin, B2URIFileIDArgMixin, DownloadFileBase): - __doc__ = DownloadFileBase.__doc__ - replaced_by_cmd = DownloadFile - - -class DownloadFileByName(CmdReplacedByMixin, B2URIBucketNFilenameArgMixin, DownloadFileBase): - __doc__ = DownloadFileBase.__doc__ - replaced_by_cmd = DownloadFile - - class FileCatBase(B2URIFileArgMixin, DownloadCommand): """ Download content of a file-like object identified by B2 URI directly to stdout. @@ -4929,6 +4912,12 @@ class FileUpload(FileUploadBase): COMMAND_NAME = 'upload' +@File.subcommands_registry.register +class FileDownload(B2URIFileArgMixin, FileDownloadBase): + __doc__ = FileDownloadBase.__doc__ + COMMAND_NAME = 'download' + + class FileInfo2(CmdReplacedByMixin, B2URIFileArgMixin, FileInfoBase): __doc__ = FileInfoBase.__doc__ replaced_by_cmd = (File, FileInfo) @@ -4966,6 +4955,21 @@ class UploadFile(CmdReplacedByMixin, FileUploadBase): replaced_by_cmd = (File, FileUpload) +class DownloadFile(CmdReplacedByMixin, B2URIFileArgMixin, FileDownloadBase): + __doc__ = FileDownloadBase.__doc__ + replaced_by_cmd = (File, FileDownload) + + +class DownloadFileById(CmdReplacedByMixin, B2URIFileIDArgMixin, FileDownloadBase): + __doc__ = FileDownloadBase.__doc__ + replaced_by_cmd = (File, FileDownload) + + +class DownloadFileByName(CmdReplacedByMixin, B2URIBucketNFilenameArgMixin, FileDownloadBase): + __doc__ = FileDownloadBase.__doc__ + replaced_by_cmd = (File, FileDownload) + + class ConsoleTool: """ Implements the commands available in the B2 command-line tool diff --git a/test/integration/test_autocomplete.py b/test/integration/test_autocomplete.py index cd8cf73df..82420aba8 100644 --- a/test/integration/test_autocomplete.py +++ b/test/integration/test_autocomplete.py @@ -97,7 +97,7 @@ def test_autocomplete_b2__download_file__b2uri( """Test that autocomplete suggests bucket names and file names.""" if is_running_on_docker: pytest.skip('Not supported on Docker') - shell.send(f'{cli_version} download_file \t\t') + shell.send(f'{cli_version} file download \t\t') shell.expect_exact("b2://", timeout=TIMEOUT) shell.send('b2://\t\t') shell.expect_exact(bucket_name, timeout=TIMEOUT) diff --git a/test/integration/test_b2_command_line.py b/test/integration/test_b2_command_line.py index 24079701b..7516d81c5 100755 --- a/test/integration/test_b2_command_line.py +++ b/test/integration/test_b2_command_line.py @@ -282,7 +282,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', '--quiet', f"b2://{bucket_name}/{uploaded_sample_file['fileName']}", + 'file', 'download', '--quiet', f"b2://{bucket_name}/{uploaded_sample_file['fileName']}", str(output_a) ] ) @@ -290,7 +290,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', '--quiet', f"b2id://{uploaded_sample_file['fileId']}", + ['file', 'download', '--quiet', f"b2id://{uploaded_sample_file['fileId']}", str(output_b)] ) assert output_b.read_text() == sample_filepath.read_text() @@ -346,7 +346,9 @@ def test_basic(b2_tool, bucket_name, sample_file, tmp_path, b2_uri_args): ['rm', '--recursive', '--with-wildcard', *b2_uri_args(bucket_name, 'rm1')] ) - b2_tool.should_succeed(['download-file', '--quiet', f'b2://{bucket_name}/b/1', tmp_path / 'a']) + b2_tool.should_succeed( + ['file', 'download', '--quiet', f'b2://{bucket_name}/b/1', tmp_path / 'a'] + ) b2_tool.should_succeed(['hide-file', bucket_name, 'c']) @@ -1457,11 +1459,11 @@ def test_sse_b2(b2_tool, bucket_name, sample_file, tmp_path, b2_uri_args): b2_tool.should_succeed(['file', 'upload', '--quiet', bucket_name, sample_file, 'not_encrypted']) b2_tool.should_succeed( - ['download-file', '--quiet', f'b2://{bucket_name}/encrypted', tmp_path / 'encrypted'] + ['file', 'download', '--quiet', f'b2://{bucket_name}/encrypted', tmp_path / 'encrypted'] ) b2_tool.should_succeed( [ - 'download-file', '--quiet', f'b2://{bucket_name}/not_encrypted', + 'file', 'download', '--quiet', f'b2://{bucket_name}/not_encrypted', tmp_path / 'not_encrypted' ] ) @@ -1561,13 +1563,16 @@ 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', '--quiet', f'b2://{bucket_name}/uploaded_encrypted', 'gonna_fail_anyway'], + [ + 'file', 'download', '--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', '--quiet', '--source-server-side-encryption', 'SSE-C', + 'file', 'download', '--quiet', '--source-server-side-encryption', 'SSE-C', f'b2://{bucket_name}/uploaded_encrypted', 'gonna_fail_anyway' ], expected_pattern='ValueError: Using SSE-C requires providing an encryption key via ' @@ -1575,7 +1580,7 @@ def test_sse_c(b2_tool, bucket_name, is_running_on_docker, sample_file, tmp_path ) b2_tool.should_fail( [ - 'download-file', '--quiet', '--source-server-side-encryption', 'SSE-C', + 'file', 'download', '--quiet', '--source-server-side-encryption', '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.', @@ -1584,7 +1589,8 @@ 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', + 'file', + 'download', '--no-progress', '--quiet', '--source-server-side-encryption', @@ -1597,7 +1603,8 @@ 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', + 'file', + 'download', '--no-progress', '--quiet', '--source-server-side-encryption', @@ -3061,10 +3068,13 @@ def test_download_file_stdout( b2_tool, bucket_name, sample_filepath, tmp_path, uploaded_sample_file ): assert b2_tool.should_succeed( - ['download-file', '--quiet', f"b2://{bucket_name}/{uploaded_sample_file['fileName']}", '-'], + [ + 'file', 'download', '--quiet', f"b2://{bucket_name}/{uploaded_sample_file['fileName']}", + '-' + ], ) == sample_filepath.read_text() assert b2_tool.should_succeed( - ['download-file', '--quiet', f"b2id://{uploaded_sample_file['fileId']}", '-'], + ['file', 'download', '--quiet', f"b2id://{uploaded_sample_file['fileId']}", '-'], ) == sample_filepath.read_text() @@ -3079,7 +3089,8 @@ def test_download_file_to_directory( sample_file_content = sample_filepath.read_text() b2_tool.should_succeed( [ - 'download-file', + 'file', + 'download', '--quiet', f"b2://{bucket_name}/{uploaded_sample_file['fileName']}", str(target_directory), @@ -3091,7 +3102,8 @@ def test_download_file_to_directory( b2_tool.should_succeed( [ - 'download-file', + 'file', + 'download', '--quiet', f"b2id://{uploaded_sample_file['fileId']}", str(target_directory), @@ -3169,7 +3181,7 @@ def assert_expected(file_info, expected=expected_file_info): assert_expected(copied_version['fileInfo']) download_output = b2_tool.should_succeed( - ['download-file', f"b2id://{file_version['fileId']}", tmp_path / 'downloaded_file'] + ['file', 'download', f"b2id://{file_version['fileId']}", tmp_path / 'downloaded_file'] ) assert re.search(r'CacheControl: *max-age=3600', download_output) assert re.search(r'ContentDisposition: *attachment', download_output) diff --git a/test/unit/_cli/test_autocomplete_cache.py b/test/unit/_cli/test_autocomplete_cache.py index 4ce1ad738..41e0c7364 100644 --- a/test/unit/_cli/test_autocomplete_cache.py +++ b/test/unit/_cli/test_autocomplete_cache.py @@ -227,7 +227,7 @@ def test_complete_with_file_uri_suggestions( tracker=autocomplete_cache.VersionTracker(), store=autocomplete_cache.HomeCachePickleStore(tmp_path), ) - with autocomplete_runner(f'b2 download-file b2://{bucket}/'): + with autocomplete_runner(f'b2 file download b2://{bucket}/'): exit, argcomplete_output = argcomplete_result() assert exit == 0 assert file_name in argcomplete_output diff --git a/test/unit/console_tool/test_download_file.py b/test/unit/console_tool/test_download_file.py index 7a5d0d871..6ff3c7bf5 100644 --- a/test/unit/console_tool/test_download_file.py +++ b/test/unit/console_tool/test_download_file.py @@ -40,7 +40,7 @@ def test_download_file_by_uri__flag_support(b2_cli, uploaded_file, tmp_path, fla output_path = tmp_path / 'output.txt' b2_cli.run( - ['download-file', flag, 'b2id://9999', + ['file', 'download', flag, 'b2id://9999', str(output_path)], expected_stdout=expected_stdout.format(output_path=pathlib.Path(output_path).resolve()) ) @@ -55,7 +55,7 @@ def test_download_file_by_uri__b2_uri_support(b2_cli, uploaded_file, tmp_path, b output_path = tmp_path / 'output.txt' b2_cli.run( - ['download-file', b2_uri, str(output_path)], + ['file', 'download', b2_uri, str(output_path)], expected_stdout=EXPECTED_STDOUT_DOWNLOAD.format( output_path=pathlib.Path(output_path).resolve() ) @@ -82,7 +82,7 @@ def test_download_file_by_name(b2_cli, local_file, uploaded_file, tmp_path, flag output_path=pathlib.Path(output_path).resolve() ), expected_stderr= - 'WARNING: `download-file-by-name` command is deprecated. Use `download-file` instead.\n', + 'WARNING: `download-file-by-name` command is deprecated. Use `file download` instead.\n', ) assert output_path.read_text() == uploaded_file['content'] @@ -101,7 +101,7 @@ def test_download_file_by_id(b2_cli, uploaded_file, tmp_path, flag, expected_std ['download-file-by-id', flag, '9999', str(output_path)], expected_stdout=expected_stdout.format(output_path=pathlib.Path(output_path).resolve()), expected_stderr= - 'WARNING: `download-file-by-id` command is deprecated. Use `download-file` instead.\n', + 'WARNING: `download-file-by-id` command is deprecated. Use `file download` instead.\n', ) assert output_path.read_text() == uploaded_file['content'] @@ -131,7 +131,7 @@ def reader(): output_path=pathlib.Path(output_path).resolve() ), expected_stderr= - 'WARNING: `download-file-by-name` command is deprecated. Use `download-file` instead.\n', + 'WARNING: `download-file-by-name` command is deprecated. Use `file download` instead.\n', ) reader_future.result(timeout=1) assert output_string == uploaded_file['content'] @@ -151,18 +151,17 @@ def uploaded_stdout_txt(b2_cli, bucket, local_file, tmp_path): def test_download_file_by_name__to_stdout_by_alias( b2_cli, bucket, uploaded_stdout_txt, tmp_path, capfd ): - """Test download_file_by_name stdout alias support""" + """Test download-file-by-name stdout alias support""" b2_cli.run( ['download-file-by-name', '--no-progress', bucket, uploaded_stdout_txt['fileName'], '-'], expected_stderr= - 'WARNING: `download-file-by-name` command is deprecated. Use `download-file` instead.\n', + 'WARNING: `download-file-by-name` command is deprecated. Use `file download` instead.\n', ) assert capfd.readouterr().out == uploaded_stdout_txt['content'] assert not pathlib.Path('-').exists() def test_cat__b2_uri(b2_cli, bucket, uploaded_stdout_txt, tmp_path, capfd): - """Test download_file_by_name stdout alias support""" b2_cli.run( ['file', 'cat', '--no-progress', f"b2://{bucket}/{uploaded_stdout_txt['fileName']}"], ) @@ -189,7 +188,6 @@ def test_cat__b2_uri__not_a_file(b2_cli, bucket, capfd): def test_cat__b2id_uri(b2_cli, bucket, uploaded_stdout_txt, tmp_path, capfd): - """Test download_file_by_name stdout alias support""" b2_cli.run(['file', 'cat', '--no-progress', "b2id://9999"],) assert capfd.readouterr().out == uploaded_stdout_txt['content'] @@ -200,7 +198,7 @@ def test__download_file__threads(b2_cli, local_file, uploaded_file, tmp_path): b2_cli.run( [ - 'download-file', '--no-progress', '--threads', + 'file', 'download', '--no-progress', '--threads', str(num_threads), 'b2://my-bucket/file1.txt', str(output_path) ] diff --git a/test/unit/console_tool/test_help.py b/test/unit/console_tool/test_help.py index 4dfca6c61..d908c1e3f 100644 --- a/test/unit/console_tool/test_help.py +++ b/test/unit/console_tool/test_help.py @@ -16,8 +16,8 @@ # --help shouldn't show deprecated commands ( "--help", - [" b2 download-file ", "-h", "--help-all"], - [" download-file-by-name ", "(DEPRECATED)"], + [" b2 file ", "-h", "--help-all"], + [" b2 download-file-by-name ", "(DEPRECATED)"], ), # --help-all should show deprecated commands, but marked as deprecated ( diff --git a/test/unit/test_console_tool.py b/test/unit/test_console_tool.py index dab5293e4..3a1a1454a 100644 --- a/test/unit/test_console_tool.py +++ b/test/unit/test_console_tool.py @@ -1237,7 +1237,7 @@ def test_files_encrypted(self): ) self._run_command( - ['download-file', '--no-progress', 'b2://my-bucket/file1.txt', local_download1], + ['file', 'download', '--no-progress', 'b2://my-bucket/file1.txt', local_download1], expected_stdout, '', 0 ) self.assertEqual(b'hello world', self._read_file(local_download1)) @@ -1249,8 +1249,8 @@ def test_files_encrypted(self): output_path=pathlib.Path(local_download2).resolve() ) self._run_command( - ['download-file', '--no-progress', 'b2id://9999', local_download2], expected_stdout, - '', 0 + ['file', 'download', '--no-progress', 'b2id://9999', local_download2], + expected_stdout, '', 0 ) self.assertEqual(b'hello world', self._read_file(local_download2)) @@ -1353,7 +1353,8 @@ def _test_download_to_directory(self, download_by: str): b2uri = f'b2://my-bucket/{source_filename}' if download_by == 'name' else 'b2id://9999' command = [ - 'download-file', + 'file', + 'download', '--no-progress', b2uri, ] @@ -1471,7 +1472,7 @@ def test_copy_file_by_id(self): local_download1 = os.path.join(temp_dir, 'file1_copy.txt') self._run_command( - ['download-file', '-q', 'b2://my-bucket/file1_copy.txt', local_download1] + ['file', 'download', '-q', 'b2://my-bucket/file1_copy.txt', local_download1] ) self.assertEqual(b'lo wo', self._read_file(local_download1)) @@ -1732,7 +1733,8 @@ def test_upload_incremental(self): downloaded_path = pathlib.Path(temp_dir) / 'out.txt' self._run_command( [ - 'download-file', + 'file', + 'download', '-q', 'b2://my-bucket/test.txt', str(downloaded_path),