From b273f6d13a39ca72c5437b419f81e354ced32468 Mon Sep 17 00:00:00 2001 From: Olzhas Arystanov Date: Mon, 12 Jan 2026 18:10:53 +0500 Subject: [PATCH 1/2] Address flaky bucket name autocomplete integration test The test was failing occasionally when there were too many buckets at the time of sending the `b2://\t\t` sequence. The shell required a user action asking if it's fine to show all N possibilities. This change addresses the issue by prepending a bucket prefix to narrow the search results. --- .../+autocomplete-integration-flaky.infrastructure.md | 1 + test/integration/test_autocomplete.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changelog.d/+autocomplete-integration-flaky.infrastructure.md diff --git a/changelog.d/+autocomplete-integration-flaky.infrastructure.md b/changelog.d/+autocomplete-integration-flaky.infrastructure.md new file mode 100644 index 000000000..0441bcb53 --- /dev/null +++ b/changelog.d/+autocomplete-integration-flaky.infrastructure.md @@ -0,0 +1 @@ +Fix flaky autocomplete integration test. \ No newline at end of file diff --git a/test/integration/test_autocomplete.py b/test/integration/test_autocomplete.py index a48cfd936..8a9dcddb3 100644 --- a/test/integration/test_autocomplete.py +++ b/test/integration/test_autocomplete.py @@ -14,6 +14,7 @@ import pytest from test.helpers import patched_spawn, skip_on_windows +from test.integration.conftest import GENERAL_BUCKET_NAME_PREFIX TIMEOUT = 120 # CI can be slow at times when parallelization is extreme @@ -100,7 +101,11 @@ def test_autocomplete_b2__download_file__b2uri( pytest.skip('Not supported on Docker') shell.send(f'{cli_version} file download \t\t') shell.expect_exact('b2://', timeout=TIMEOUT) - shell.send('b2://\t\t') + + prefix_len = len(GENERAL_BUCKET_NAME_PREFIX) + 4 + prefix = bucket_name[:prefix_len] + shell.send(f'b2://{prefix}\t\t') shell.expect_exact(bucket_name, timeout=TIMEOUT) + shell.send(f'{bucket_name}/\t\t') shell.expect_exact(file_name, timeout=TIMEOUT) From 4c3ac4c8a8615dce19979384e4035a15eb3e449c Mon Sep 17 00:00:00 2001 From: Olzhas Arystanov Date: Thu, 15 Jan 2026 00:01:59 +0500 Subject: [PATCH 2/2] Avoid eager calculation of command help during parser construction --- b2/_internal/arg_parser.py | 31 ++++++++++------------ changelog.d/+arg_parse_help_eager.fixed.md | 1 + 2 files changed, 15 insertions(+), 17 deletions(-) create mode 100644 changelog.d/+arg_parse_help_eager.fixed.md diff --git a/b2/_internal/arg_parser.py b/b2/_internal/arg_parser.py index 89cb046ae..52a27245a 100644 --- a/b2/_internal/arg_parser.py +++ b/b2/_internal/arg_parser.py @@ -97,13 +97,10 @@ def __init__( :param for_docs: is this parser used for generating docs :param custom_deprecated: is this command deprecated? """ - self._raw_description = None - self._description = None + self._raw_description: str | None = None + self._description: str | None = None self._for_docs = for_docs self.deprecated = custom_deprecated - self._short_description = self._make_short_description( - kwargs.get('usage', ''), kwargs.get('description', '') - ) kwargs.setdefault('formatter_class', B2RawTextHelpFormatter) super().__init__(*args, **kwargs) @@ -139,17 +136,13 @@ def _encode_description(self, value: str): # TODO-REMOVE-BY: When rst2ansi is updated or replaced return textwrap.dedent(value) - def _make_short_description(self, usage: str, raw_description: str) -> str: - if usage: - return usage - - if not raw_description: + def _get_short_description(self) -> str: + if not self._raw_description: return '' - - for line in raw_description.splitlines(): - if line.strip(): - return self._encode_description(line.strip()) - + for line in str(self._raw_description).splitlines(): + cleaned_line = line.strip() + if cleaned_line: + return self._encode_description(cleaned_line) return '' def error(self, message): @@ -217,11 +210,15 @@ def _hide_duplicated_action_choices(self, action): action.choices = original_choices def format_usage(self, use_short_description: bool = False, col_length: int = 16): - if not use_short_description or not self._short_description: + if not use_short_description: + return super().format_usage() + + short_description = self._get_short_description() + if not short_description: return super().format_usage() formatter = self._get_formatter() - formatter.add_text(f'{self.prog:{col_length + 2}} {self._short_description}') + formatter.add_text(f'{self.prog:{col_length + 2}} {short_description}') return formatter.format_help() diff --git a/changelog.d/+arg_parse_help_eager.fixed.md b/changelog.d/+arg_parse_help_eager.fixed.md new file mode 100644 index 000000000..77c23b680 --- /dev/null +++ b/changelog.d/+arg_parse_help_eager.fixed.md @@ -0,0 +1 @@ +Avoid eager calculation of command help during parser construction. \ No newline at end of file