diff --git a/changelog/9036.bugfix.rst b/changelog/9036.bugfix.rst new file mode 100644 index 000000000..4f25f82e2 --- /dev/null +++ b/changelog/9036.bugfix.rst @@ -0,0 +1 @@ +``pytest.warns`` and similar functions now capture warnings when an exception is raised inside a ``with`` block. diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index 127a7a856..ff8e70820 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -298,11 +298,6 @@ class WarningsChecker(WarningsRecorder): # nothing to do in this deprecated case, see WARNS_NONE_ARG above return - if not (exc_type is None and exc_val is None and exc_tb is None): - # We currently ignore missing warnings if an exception is active. - # TODO: fix this, because it means things are surprisingly order-sensitive. - return - def found_str(): return pformat([record.message for record in self], indent=2) diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index 6b3856bd9..16b8d5443 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -172,22 +172,6 @@ class TestDeprecatedCall: with pytest.deprecated_call(): assert f() == 10 - @pytest.mark.parametrize("mode", ["context_manager", "call"]) - def test_deprecated_call_exception_is_raised(self, mode) -> None: - """If the block of the code being tested by deprecated_call() raises an exception, - it must raise the exception undisturbed. - """ - - def f(): - raise ValueError("some exception") - - with pytest.raises(ValueError, match="some exception"): - if mode == "call": - pytest.deprecated_call(f) - else: - with pytest.deprecated_call(): - f() - def test_deprecated_call_specificity(self) -> None: other_warnings = [ Warning, @@ -446,3 +430,15 @@ class TestWarns: with pytest.warns(UserWarning, match="v1 warning"): warnings.warn("v1 warning", UserWarning) warnings.warn("non-matching v2 warning", UserWarning) + + def test_catch_warning_within_raise(self) -> None: + # warns-in-raises works since https://github.com/pytest-dev/pytest/pull/11129 + with pytest.raises(ValueError, match="some exception"): + with pytest.warns(FutureWarning, match="some warning"): + warnings.warn("some warning", category=FutureWarning) + raise ValueError("some exception") + # and raises-in-warns has always worked but we'll check for symmetry. + with pytest.warns(FutureWarning, match="some warning"): + with pytest.raises(ValueError, match="some exception"): + warnings.warn("some warning", category=FutureWarning) + raise ValueError("some exception")