diff --git a/AUTHORS b/AUTHORS index 2154e3babbb..758a74a9362 100644 --- a/AUTHORS +++ b/AUTHORS @@ -7,6 +7,7 @@ Aaron Coleman Abdeali JK Abdelrahman Elbehery Abhijeet Kasurde +ace2016 Adam Johnson Adam Stewart Adam Uhlir diff --git a/changelog/13354.improvement.rst b/changelog/13354.improvement.rst new file mode 100644 index 00000000000..9b90b284cd2 --- /dev/null +++ b/changelog/13354.improvement.rst @@ -0,0 +1,3 @@ +:meth:`Node.get_closest_marker <_pytest.nodes.Node.get_closest_marker>` now also accepts a :class:`~pytest.MarkDecorator` as its ``default``, for example ``item.get_closest_marker("foo", pytest.mark.foo(1))``, and returns the wrapped :class:`~pytest.Mark`. + +Previously the only way to build a ``default`` was to instantiate :class:`~pytest.Mark` directly, which is private and warns. diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index f0629c2daf7..c6d245de6c9 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -352,15 +352,22 @@ def iter_markers_with_node( def get_closest_marker(self, name: str) -> Mark | None: ... @overload - def get_closest_marker(self, name: str, default: Mark) -> Mark: ... + def get_closest_marker(self, name: str, default: Mark | MarkDecorator) -> Mark: ... - def get_closest_marker(self, name: str, default: Mark | None = None) -> Mark | None: + def get_closest_marker( + self, name: str, default: Mark | MarkDecorator | None = None + ) -> Mark | None: """Return the first marker matching the name, from closest (for example function) to farther level (for example module level). - :param default: Fallback return value if no marker was found. + :param default: + Fallback return value if no marker was found. A + :class:`~pytest.MarkDecorator` such as ``pytest.mark.foo(1)`` is + also accepted, in which case its :class:`~pytest.Mark` is returned. :param name: Name to filter by. """ + if isinstance(default, MarkDecorator): + default = default.mark return next(self.iter_markers(name=name), default) def listextrakeywords(self) -> set[str]: diff --git a/testing/test_mark.py b/testing/test_mark.py index c70376e7015..7cc63a240af 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -657,6 +657,18 @@ def test_has_inherited(self): assert has_inherited_marker.kwargs == {"location": "class"} assert has_own.get_closest_marker("missing") is None + def test_mark_closest_default_mark_decorator(self, pytester: Pytester) -> None: + p = pytester.makepyfile( + """ + def test_without_mark(): + pass + """ + ) + items, _rec = pytester.inline_genitems(p) + (item,) = items + default = pytest.mark.foo(location="default") + assert item.get_closest_marker("foo", default) is default.mark + def test_mark_with_wrong_marker(self, pytester: Pytester) -> None: reprec = pytester.inline_runsource( """