From 5ee778c213b342efd12edf9ec9fdc17a73354eb7 Mon Sep 17 00:00:00 2001 From: Cheukting Date: Thu, 22 Jun 2023 16:48:20 +0100 Subject: [PATCH] capture warning when exception is raised (fix #9036) --- changelog/9036.bugfix.rst | 1 + src/_pytest/recwarn.py | 35 +++++++++++++++++------------------ testing/test_recwarn.py | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 changelog/9036.bugfix.rst diff --git a/changelog/9036.bugfix.rst b/changelog/9036.bugfix.rst new file mode 100644 index 00000000000..4f25f82e292 --- /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 d76ea020f19..627bced43da 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -291,23 +291,22 @@ def found_str(): return pformat([record.message for record in self], indent=2) # only check if we're not currently handling an exception - if exc_type is None and exc_val is None and exc_tb is None: - if self.expected_warning is not None: - if not any(issubclass(r.category, self.expected_warning) for r in self): - __tracebackhide__ = True + if self.expected_warning is not None: + if not any(issubclass(r.category, self.expected_warning) for r in self): + __tracebackhide__ = True + fail( + f"DID NOT WARN. No warnings of type {self.expected_warning} were emitted.\n" + f"The list of emitted warnings is: {found_str()}." + ) + elif self.match_expr is not None: + for r in self: + if issubclass(r.category, self.expected_warning): + if re.compile(self.match_expr).search(str(r.message)): + break + else: fail( - f"DID NOT WARN. No warnings of type {self.expected_warning} were emitted.\n" - f"The list of emitted warnings is: {found_str()}." - ) - elif self.match_expr is not None: - for r in self: - if issubclass(r.category, self.expected_warning): - if re.compile(self.match_expr).search(str(r.message)): - break - else: - fail( - f"""\ + f"""\ DID NOT WARN. No warnings of type {self.expected_warning} matching the regex were emitted. - Regex: {self.match_expr} - Emitted warnings: {found_str()}""" - ) +Regex: {self.match_expr} +Emitted warnings: {found_str()}""" + ) diff --git a/testing/test_recwarn.py b/testing/test_recwarn.py index 7e0f836a634..c6dd6b7f314 100644 --- a/testing/test_recwarn.py +++ b/testing/test_recwarn.py @@ -403,3 +403,24 @@ def test_warns_context_manager_with_kwargs(self) -> None: with pytest.warns(UserWarning, foo="bar"): # type: ignore pass assert "Unexpected keyword arguments" in str(excinfo.value) + + def test_catch_warning_within_raise(self) -> None: + def f(): + warnings.warn("some warning", category=FutureWarning) + raise ValueError("some exception") + + with pytest.raises(pytest.fail.Exception): + with pytest.warns(SyntaxWarning, match="some warning"): + with pytest.raises(ValueError, match="some exception"): + f() + + with pytest.raises(pytest.fail.Exception): + with pytest.raises(ValueError, match="some exception"): + with pytest.warns(SyntaxWarning, match="some warning"): + f() + + with pytest.raises(pytest.fail.Exception): + with pytest.raises(ValueError, match="some exception"), pytest.warns( + SyntaxWarning, match="some warning" + ): + f()