diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index eed79c3fd..13622e95d 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -9,6 +9,7 @@ from typing import List from typing import Optional from typing import Pattern from typing import Tuple +from typing import TypeVar from typing import Union from _pytest.compat import overload @@ -20,6 +21,9 @@ if TYPE_CHECKING: from typing import Type +T = TypeVar("T") + + @fixture def recwarn(): """Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions. @@ -67,11 +71,10 @@ def warns( @overload # noqa: F811 def warns( # noqa: F811 expected_warning: Optional[Union["Type[Warning]", Tuple["Type[Warning]", ...]]], - func: Callable, + func: Callable[..., T], *args: Any, - match: Optional[Union[str, "Pattern"]] = ..., **kwargs: Any -) -> Union[Any]: +) -> T: raise NotImplementedError() @@ -97,7 +100,7 @@ def warns( # noqa: F811 ... warnings.warn("my warning", RuntimeWarning) In the context manager form you may use the keyword argument ``match`` to assert - that the exception matches a text or regex:: + that the warning matches a text or regex:: >>> with warns(UserWarning, match='must be 0 or None'): ... warnings.warn("value must be 0 or None", UserWarning) diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index 1d445d1bf..f61f8586f 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -370,13 +370,14 @@ class TestWarns: @pytest.mark.filterwarnings("ignore") def test_can_capture_previously_warned(self) -> None: - def f(): + def f() -> int: warnings.warn(UserWarning("ohai")) return 10 assert f() == 10 assert pytest.warns(UserWarning, f) == 10 assert pytest.warns(UserWarning, f) == 10 + assert pytest.warns(UserWarning, f) != "10" # type: ignore[comparison-overlap] def test_warns_context_manager_with_kwargs(self) -> None: with pytest.raises(TypeError) as excinfo: