From 3def7c25bee647a5b2f9ad83865ac797373c7e3e Mon Sep 17 00:00:00 2001 From: lavafreak Date: Fri, 17 Apr 2026 17:02:04 -0600 Subject: [PATCH 1/2] Use direct cause for raises match failures --- AUTHORS | 1 + changelog/14389.bugfix.rst | 1 + src/_pytest/raises.py | 2 +- testing/python/raises.py | 25 +++++++++++++++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 changelog/14389.bugfix.rst diff --git a/AUTHORS b/AUTHORS index c33cf5fafbd..d6d2737a4bf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -180,6 +180,7 @@ Fraser Stark Freya Bruhin Gabriel Landau Gabriel Reis +Garion Milazzo Garvit Shubham Gene Wood George Kussumoto diff --git a/changelog/14389.bugfix.rst b/changelog/14389.bugfix.rst new file mode 100644 index 00000000000..15bccc5bbce --- /dev/null +++ b/changelog/14389.bugfix.rst @@ -0,0 +1 @@ +Improved ``pytest.raises(..., match=...)`` failures to report the mismatched exception as the direct cause of the resulting ``AssertionError``. diff --git a/src/_pytest/raises.py b/src/_pytest/raises.py index 82fe2c41c96..d24eddb014a 100644 --- a/src/_pytest/raises.py +++ b/src/_pytest/raises.py @@ -698,7 +698,7 @@ def __exit__( if not self.matches(exc_val): if self._just_propagate: return False - raise AssertionError(self._fail_reason) + raise AssertionError(self._fail_reason) from exc_val # Cast to narrow the exception type now that it's verified.... # even though the TypeGuard in self.matches should be narrowing diff --git a/testing/python/raises.py b/testing/python/raises.py index f74d747c0df..5802671bbcc 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -179,6 +179,31 @@ def test_invalid_regex(): result.stdout.no_fnmatch_line("*File*") result.stdout.no_fnmatch_line("*line*") + def test_raises_match_failure_uses_direct_cause( + self, pytester: Pytester + ) -> None: + pytester.makepyfile( + """ + import pytest + + def test_raises_match_failure(): + with pytest.raises(ValueError, match="expected"): + raise ValueError("actual") + """ + ) + result = pytester.runpytest("--tb=short") + assert result.ret == 1 + result.stdout.fnmatch_lines( + [ + "*ValueError: actual", + "*The above exception was the direct cause of the following exception:*", + "*E*AssertionError: Regex pattern did not match.*", + ] + ) + result.stdout.no_fnmatch_line( + "*During handling of the above exception, another exception occurred:*" + ) + def test_noclass(self) -> None: with pytest.raises(TypeError): with pytest.raises("wrong"): # type: ignore[call-overload] From 80ac165abc209a511c2879f9f52a2d30fe63f5f4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:55:49 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- testing/python/raises.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/testing/python/raises.py b/testing/python/raises.py index 5802671bbcc..70234ddcfb6 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -179,9 +179,7 @@ def test_invalid_regex(): result.stdout.no_fnmatch_line("*File*") result.stdout.no_fnmatch_line("*line*") - def test_raises_match_failure_uses_direct_cause( - self, pytester: Pytester - ) -> None: + def test_raises_match_failure_uses_direct_cause(self, pytester: Pytester) -> None: pytester.makepyfile( """ import pytest