diff --git a/changelog/8096.improvement.rst b/changelog/8096.improvement.rst new file mode 100644 index 00000000000..9b66794b093 --- /dev/null +++ b/changelog/8096.improvement.rst @@ -0,0 +1 @@ +Clearer error message for invalid ``-W`` filters, listing valid actions and the ``-Wait`` pitfall. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index c7bd3e1afab..f28a61a4d4f 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -2367,7 +2367,16 @@ def parse_warning_filter( try: action: warnings._ActionKind = warnings._getaction(action_) # type: ignore[attr-defined] except warnings._OptionError as e: - raise UsageError(error_template.format(error=str(e))) from None + hint = ( + " (choose from: default, error, ignore, always, module, once)." + " See https://docs.python.org/3/library/warnings.html#describing-warning-filters" + ) + if action_ == "ait": + hint = ( + " Note that '-W' takes a value, so '-Wait' is parsed as '-W ait'." + + hint + ) + raise UsageError(error_template.format(error=f"{e}{hint}")) from None try: category: type[Warning] = _resolve_warning_category(category_) except ImportError: diff --git a/testing/test_config.py b/testing/test_config.py index dad1653e299..ee53571851c 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -3112,6 +3112,19 @@ def test_parse_warning_filter_failure(arg: str) -> None: parse_warning_filter(arg, escape=True) +@pytest.mark.parametrize("arg", ["ait", "FOO"]) +def test_parse_warning_filter_invalid_action_hint(arg: str) -> None: + """Invalid -W actions show valid choices; the -Wait pitfall hint is scoped to that case.""" + with pytest.raises( + pytest.UsageError, match=r"invalid action.*choose from" + ) as exc_info: + parse_warning_filter(arg, escape=True) + if arg == "ait": + assert "-Wait" in str(exc_info.value) + else: + assert "-Wait" not in str(exc_info.value) + + class TestDebugOptions: def test_without_debug_does_not_write_log(self, pytester: Pytester) -> None: result = pytester.runpytest() diff --git a/testing/test_warnings.py b/testing/test_warnings.py index 0344cb453d8..3728bb844d5 100644 --- a/testing/test_warnings.py +++ b/testing/test_warnings.py @@ -563,6 +563,23 @@ def test_invalid_regex_in_filterwarning(self, pytester: Pytester) -> None: ) +def test_dash_w_shows_wait_hint_on_usage_error(pytester: Pytester) -> None: + """`-Wait` is parsed as `-W ait`; the hint should point at this.""" + result = pytester.runpytest("-Wait") + assert result.ret == pytest.ExitCode.USAGE_ERROR + result.stderr.fnmatch_lines( + [ + "ERROR: while parsing the following warning configuration:", + "", + " ait", + "", + "This error occurred:", + "", + "invalid action: 'ait'*-Wait*choose from*", + ] + ) + + @pytest.mark.skip("not relevant until pytest 10.0") @pytest.mark.parametrize("change_default", [None, "ini", "cmdline"]) def test_removed_in_x_warning_as_error(pytester: Pytester, change_default) -> None: