diff --git a/changelog/13031.improvement.rst b/changelog/13031.improvement.rst new file mode 100644 index 0000000000..30ae4f7085 --- /dev/null +++ b/changelog/13031.improvement.rst @@ -0,0 +1,2 @@ +``pytest.mark.parametrize([], idfunc=...)`` will no longer trigger a call to ``idfunc`` with internal objects. +instead the concrete id ``NOTSET`` is used. diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 624b37cab9..1a0b3c5b5b 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -47,18 +47,18 @@ def get_empty_parameterset_mark( ) -> MarkDecorator: from ..nodes import Collector + argslisting = ", ".join(argnames) + fs, lineno = getfslineno(func) - reason = f"got empty parameter set {argnames!r}, function {func.__name__} at {fs}:{lineno}" + reason = f"got empty parameter set for ({argslisting})" requested_mark = config.getini(EMPTY_PARAMETERSET_OPTION) if requested_mark in ("", None, "skip"): mark = MARK_GEN.skip(reason=reason) elif requested_mark == "xfail": mark = MARK_GEN.xfail(reason=reason, run=False) elif requested_mark == "fail_at_collect": - f_name = func.__name__ - _, lineno = getfslineno(func) raise Collector.CollectError( - f"Empty parameter set in '{f_name}' at line {lineno + 1}" + f"Empty parameter set in '{func.__name__}' at line {lineno + 1}" ) else: raise LookupError(requested_mark) @@ -181,7 +181,9 @@ def _for_parametrize( # parameter set with NOTSET values, with the "empty parameter set" mark applied to it. mark = get_empty_parameterset_mark(config, argnames, func) parameters.append( - ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None) + ParameterSet( + values=(NOTSET,) * len(argnames), marks=[mark], id="NOTSET" + ) ) return argnames, parameters diff --git a/testing/test_mark.py b/testing/test_mark.py index 60ee795cf4..a9ba416d12 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -1048,6 +1048,31 @@ def test(): assert result.ret == ExitCode.INTERRUPTED +def test_paramset_empty_no_idfunc( + pytester: Pytester, monkeypatch: pytest.MonkeyPatch +) -> None: + p1 = pytester.makepyfile( + """ + import pytest + + def idfunc(value): + raise ValueError() + @pytest.mark.parametrize("param", [], ids=idfunc) + def test(param): + pass + """ + ) + result = pytester.runpytest(p1, "-v", "-rs") + result.stdout.fnmatch_lines( + [ + "* collected 1 item", + "test_paramset_empty_no_idfunc* SKIPPED *", + "SKIPPED [1] test_paramset_empty_no_idfunc.py:5: got empty parameter set for (param)", + "*= 1 skipped in *", + ] + ) + + def test_parameterset_for_parametrize_bad_markname(pytester: Pytester) -> None: with pytest.raises(pytest.UsageError): test_parameterset_for_parametrize_marks(pytester, "bad")