diff --git a/pyproject.toml b/pyproject.toml index 3d6cbc975..3ca84a620 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -155,8 +155,10 @@ wheel_build_env = ".pkg" constrain_package_deps = true use_frozen_constraints = true dependency_groups = ["tests"] +set_env.PYTHONDEVMODE = "1" +set_env.PYTHONWARNINGS = "error::BytesWarning" commands = [[ - "pytest", "-v", "--tb=short", "--basetemp={env_tmp_dir}", + "python", "-bb", "-m", "pytest", "-v", "--tb=short", "--basetemp={env_tmp_dir}", {replace = "posargs", default = [], extend = true}, ]] diff --git a/src/click/parser.py b/src/click/parser.py index 1ea1f7166..fb8247d2d 100644 --- a/src/click/parser.py +++ b/src/click/parser.py @@ -325,8 +325,8 @@ def _process_args_for_options(self, state: _ParsingState) -> None: arg = state.rargs.pop(0) arglen = len(arg) # Double dashes always handled explicitly regardless of what - # prefixes are valid. - if arg == "--": + # prefixes are valid. Handle both bytes and string to avoid BytesWarning. + if arg == b"--" if isinstance(arg, bytes) else arg == "--": return elif arg[:1] in self._opt_prefixes and arglen > 1: self._process_opts(arg, state) diff --git a/src/click/types.py b/src/click/types.py index e71c1c21e..388959bc4 100644 --- a/src/click/types.py +++ b/src/click/types.py @@ -972,8 +972,11 @@ def convert( ctx: Context | None, ) -> str | bytes | os.PathLike[str]: rv = value - - is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + # Use simple string comparison instead of `rv in (b"-", "-")` to avoid + # BytesWarning when Python runs with -bb flag (which treats bytes/str + # comparison as an error). The input type is str | os.PathLike[str], + # so bytes are not expected here. + is_dash = self.file_okay and self.allow_dash and rv == "-" if not is_dash: if self.resolve_path: diff --git a/tests/test_types.py b/tests/test_types.py index 75434f104..507e686d7 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -251,6 +251,30 @@ def test_invalid_path_with_esc_sequence(): assert "my\\ndir" in exc_info.value.message +def test_path_allow_dash_no_bytes_warning(): + """Test that Path(allow_dash=True).convert() doesn't raise BytesWarning. + + This verifies the fix for issue #2877. The original code used + `rv in (b"-", "-")` which causes BytesWarning with python -bb flag. + Now we use simple `rv == "-"` comparison. + """ + import warnings + + path_type = click.Path(allow_dash=True) + + # Verify dash handling works without BytesWarning when -bb flag is used + with warnings.catch_warnings(): + warnings.simplefilter("error", BytesWarning) + result = path_type.convert("-", None, None) + assert result == "-" + + # Also verify regular paths work fine + with warnings.catch_warnings(): + warnings.simplefilter("error", BytesWarning) + result = path_type.convert("test.txt", None, None) + assert result == "test.txt" + + def test_choice_get_invalid_choice_message(): choice = click.Choice(["a", "b", "c"]) message = choice.get_invalid_choice_message("d", ctx=None)