Skip to content
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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},
]]

Expand Down
4 changes: 2 additions & 2 deletions src/click/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 5 additions & 2 deletions src/click/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
24 changes: 24 additions & 0 deletions tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading