diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py index 639bf143e53..465e100b2af 100644 --- a/src/_pytest/skipping.py +++ b/src/_pytest/skipping.py @@ -204,12 +204,13 @@ def evaluate_skip_marks(item: Item) -> Skip | None: return Skip(reason) for mark in item.iter_markers(name="skip"): - reason = mark.args[0] if mark.args else mark.kwargs.get("reason") # Marks applied to a module or class are seen by each of their items, # so only warn once per reason. warned_reasons = item.config.stash.setdefault(warned_skip_reasons_key, set()) if ( - isinstance(reason, str) + "reason" not in mark.kwargs + and mark.args + and isinstance(reason := mark.args[0], str) and _looks_like_condition(reason) and reason not in warned_reasons ): @@ -217,7 +218,9 @@ def evaluate_skip_marks(item: Item) -> Skip | None: item.warn( PytestWarning( f"The reason {reason!r} of pytest.mark.skip looks like a condition. " - "Did you mean pytest.mark.skipif?" + "Did you mean pytest.mark.skipif ?\n" + "If intentional, pass reason as a keyword argument to disable " + "this warning." ) ) try: diff --git a/testing/test_skipping.py b/testing/test_skipping.py index 0118aed7c88..a8e29fbbd9d 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -1569,16 +1569,17 @@ def test_exit_reason_only(): result.stdout.fnmatch_lines("*_pytest.outcomes.Exit: foo*") -@pytest.mark.parametrize( - "reason", - [ - "sys.version_info < (3, 6)", - "sys.platform.startswith('win')", - "os.name == 'nt'", - ], -) +SUSPECT_REASONS = [ + "sys.version_info < (3, 6)", + "sys.platform.startswith('win')", + "os.name == 'nt'", +] + + +@pytest.mark.parametrize("reason", SUSPECT_REASONS) def test_skip_reason_looks_like_condition_warns( - pytester: Pytester, reason: str + pytester: Pytester, + reason: str, ) -> None: pytester.makepyfile( f""" @@ -1591,11 +1592,32 @@ def test_func(): ) result = pytester.runpytest("-W", "default::pytest.PytestWarning") result.stdout.fnmatch_lines( - ["*looks like a condition*Did you mean pytest.mark.skipif?"] + [ + "*looks like a condition*Did you mean pytest.mark.skipif ?", + "*If intentional, pass reason as a keyword argument to disable this warning.", + ] ) result.assert_outcomes(skipped=1, warnings=1) +@pytest.mark.parametrize("reason", SUSPECT_REASONS) +def test_skip_reason_looks_like_condition_kwarg( + pytester: Pytester, + reason: str, +) -> None: + pytester.makepyfile( + f""" + import pytest + + @pytest.mark.skip({reason=!r}) + def test_func(): + pass + """ + ) + result = pytester.runpytest("-W", "default::pytest.PytestWarning") + result.assert_outcomes(skipped=1, warnings=0) + + @pytest.mark.parametrize( "reason", [