permit node to warn with any warning type, not just PytestWarning (#8052)

Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
This commit is contained in:
Simon K 2020-11-21 13:49:17 +00:00 committed by GitHub
parent afd53ede6f
commit 52fef811c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 11 deletions

View File

@ -0,0 +1 @@
:meth:`Node.warn <_pytest.nodes.Node.warn>` now permits any subclass of :class:`Warning`, not just :class:`PytestWarning <pytest.PytestWarning>`.

View File

@ -34,7 +34,6 @@ from _pytest.store import Store
if TYPE_CHECKING: if TYPE_CHECKING:
# Imported here due to circular import. # Imported here due to circular import.
from _pytest.main import Session from _pytest.main import Session
from _pytest.warning_types import PytestWarning
from _pytest._code.code import _TracebackStyle from _pytest._code.code import _TracebackStyle
@ -198,27 +197,31 @@ class Node(metaclass=NodeMeta):
def __repr__(self) -> str: def __repr__(self) -> str:
return "<{} {}>".format(self.__class__.__name__, getattr(self, "name", None)) return "<{} {}>".format(self.__class__.__name__, getattr(self, "name", None))
def warn(self, warning: "PytestWarning") -> None: def warn(self, warning: Warning) -> None:
"""Issue a warning for this Node. """Issue a warning for this Node.
Warnings will be displayed after the test session, unless explicitly suppressed. Warnings will be displayed after the test session, unless explicitly suppressed.
:param Warning warning: :param Warning warning:
The warning instance to issue. Must be a subclass of PytestWarning. The warning instance to issue.
:raises ValueError: If ``warning`` instance is not a subclass of PytestWarning. :raises ValueError: If ``warning`` instance is not a subclass of Warning.
Example usage: Example usage:
.. code-block:: python .. code-block:: python
node.warn(PytestWarning("some message")) node.warn(PytestWarning("some message"))
""" node.warn(UserWarning("some message"))
from _pytest.warning_types import PytestWarning
if not isinstance(warning, PytestWarning): .. versionchanged:: 6.2
Any subclass of :class:`Warning` is now accepted, rather than only
:class:`PytestWarning <pytest.PytestWarning>` subclasses.
"""
# enforce type checks here to avoid getting a generic type error later otherwise.
if not isinstance(warning, Warning):
raise ValueError( raise ValueError(
"warning must be an instance of PytestWarning or subclass, got {!r}".format( "warning must be an instance of Warning or subclass, got {!r}".format(
warning warning
) )
) )

View File

@ -1,10 +1,12 @@
from typing import List from typing import List
from typing import Type
import py import py
import pytest import pytest
from _pytest import nodes from _pytest import nodes
from _pytest.pytester import Pytester from _pytest.pytester import Pytester
from _pytest.warning_types import PytestWarning
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -35,15 +37,33 @@ def test_node_from_parent_disallowed_arguments() -> None:
nodes.Node.from_parent(None, config=None) # type: ignore[arg-type] nodes.Node.from_parent(None, config=None) # type: ignore[arg-type]
def test_std_warn_not_pytestwarning(pytester: Pytester) -> None: @pytest.mark.parametrize(
"warn_type, msg", [(DeprecationWarning, "deprecated"), (PytestWarning, "pytest")]
)
def test_node_warn_is_no_longer_only_pytest_warnings(
pytester: Pytester, warn_type: Type[Warning], msg: str
) -> None:
items = pytester.getitems( items = pytester.getitems(
""" """
def test(): def test():
pass pass
""" """
) )
with pytest.raises(ValueError, match=".*instance of PytestWarning.*"): with pytest.warns(warn_type, match=msg):
items[0].warn(UserWarning("some warning")) # type: ignore[arg-type] items[0].warn(warn_type(msg))
def test_node_warning_enforces_warning_types(pytester: Pytester) -> None:
items = pytester.getitems(
"""
def test():
pass
"""
)
with pytest.raises(
ValueError, match="warning must be an instance of Warning or subclass"
):
items[0].warn(Exception("ok")) # type: ignore[arg-type]
def test__check_initialpaths_for_relpath() -> None: def test__check_initialpaths_for_relpath() -> None: