From b030c3fcc80aa2ecfb852624dbc35b0048303481 Mon Sep 17 00:00:00 2001 From: dariomesic Date: Wed, 29 Oct 2025 22:59:57 +0100 Subject: [PATCH 1/3] Refactor: Improve clarity of 'expected exception' error messages --- changelog/13861.improvement.rst | 2 ++ src/_pytest/raises.py | 6 +++--- testing/python/raises.py | 6 +++--- testing/python/raises_group.py | 11 +++++------ 4 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 changelog/13861.improvement.rst diff --git a/changelog/13861.improvement.rst b/changelog/13861.improvement.rst new file mode 100644 index 00000000000..8106ba74c01 --- /dev/null +++ b/changelog/13861.improvement.rst @@ -0,0 +1,2 @@ +Better sentence structure in a test's expected error message. Previously, the error message would be "expected exception must be , but got ". Now, it is "Expected , but got ". +This PR addresses the TODO comment in `testing/python/raises_group.py:49` and widens the scope to all expected error messages in both `testing/python/raises.py` and `testing/python/raises_group.py`. diff --git a/src/_pytest/raises.py b/src/_pytest/raises.py index ad56a8c14d2..7c246fde280 100644 --- a/src/_pytest/raises.py +++ b/src/_pytest/raises.py @@ -464,11 +464,11 @@ def _parse_exc( f"with `RaisesGroup`." ) # unclear if the Type/ValueError distinction is even helpful here - msg = f"expected exception must be {expected}, not " + msg = f"Expected {expected}, but got " if isinstance(exc, type): # type: ignore[unreachable] raise ValueError(msg + f"{exc.__name__!r}") if isinstance(exc, BaseException): # type: ignore[unreachable] - raise TypeError(msg + f"an exception instance ({type(exc).__name__})") + raise TypeError(msg + f"an exception instance: {type(exc).__name__}") raise TypeError(msg + repr(type(exc).__name__)) @property @@ -1036,7 +1036,7 @@ def _parse_excgroup( return exc elif isinstance(exc, tuple): raise TypeError( - f"expected exception must be {expected}, not {type(exc).__name__!r}.\n" + f"Expected {expected}, but got {type(exc).__name__!r}.\n" "RaisesGroup does not support tuples of exception types when expecting one of " "several possible exception types like RaisesExc.\n" "If you meant to expect a group with multiple exceptions, list them as separate arguments." diff --git a/testing/python/raises.py b/testing/python/raises.py index 0bf02a8063f..ec8d6bf3a91 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -368,7 +368,7 @@ def test_expected_exception_is_not_a_baseexception(self) -> None: with pytest.raises( TypeError, match=wrap_escape( - "expected exception must be a BaseException type, not 'str'" + "Expected a BaseException type, but got 'str'" ), ): with pytest.raises("hello"): # type: ignore[call-overload] @@ -380,7 +380,7 @@ class NotAnException: with pytest.raises( ValueError, match=wrap_escape( - "expected exception must be a BaseException type, not 'NotAnException'" + "Expected a BaseException type, but got 'NotAnException'" ), ): with pytest.raises(NotAnException): # type: ignore[type-var] @@ -389,7 +389,7 @@ class NotAnException: with pytest.raises( TypeError, match=wrap_escape( - "expected exception must be a BaseException type, not 'str'" + "Expected a BaseException type, but got 'str'" ), ): with pytest.raises(("hello", NotAnException)): # type: ignore[arg-type] diff --git a/testing/python/raises_group.py b/testing/python/raises_group.py index 0247b118c58..935654f1815 100644 --- a/testing/python/raises_group.py +++ b/testing/python/raises_group.py @@ -36,19 +36,18 @@ def fails_raises_group(msg: str, add_prefix: bool = True) -> RaisesExc[Failed]: def test_raises_group() -> None: with pytest.raises( TypeError, - match=wrap_escape("expected exception must be a BaseException type, not 'int'"), + match=wrap_escape("Expected a BaseException type, but got 'int'"), ): RaisesExc(5) # type: ignore[call-overload] with pytest.raises( ValueError, - match=wrap_escape("expected exception must be a BaseException type, not 'int'"), + match=wrap_escape("Expected a BaseException type, but got 'int'"), ): RaisesExc(int) # type: ignore[type-var] with pytest.raises( TypeError, - # TODO: bad sentence structure match=wrap_escape( - "expected exception must be a BaseException type, RaisesExc, or RaisesGroup, not an exception instance (ValueError)", + "Expected a BaseException type, RaisesExc, or RaisesGroup, but got an exception instance: ValueError", ), ): RaisesGroup(ValueError()) # type: ignore[call-overload] @@ -1079,7 +1078,7 @@ def test_raisesexc() -> None: with pytest.raises( ValueError, match=wrap_escape( - "expected exception must be a BaseException type, not 'object'" + "Expected a BaseException type, but got 'object'" ), ): RaisesExc(object) # type: ignore[type-var] @@ -1351,7 +1350,7 @@ def test_tuples() -> None: with pytest.raises( TypeError, match=wrap_escape( - "expected exception must be a BaseException type, RaisesExc, or RaisesGroup, not 'tuple'.\n" + "Expected a BaseException type, RaisesExc, or RaisesGroup, but got 'tuple'.\n" "RaisesGroup does not support tuples of exception types when expecting one of " "several possible exception types like RaisesExc.\n" "If you meant to expect a group with multiple exceptions, list them as separate arguments." From 944bc1ff36ba930a1de816f832fe1852601050b8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 22:32:13 +0000 Subject: [PATCH 2/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- testing/python/raises.py | 8 ++------ testing/python/raises_group.py | 4 +--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/testing/python/raises.py b/testing/python/raises.py index ec8d6bf3a91..c9d57918a83 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -367,9 +367,7 @@ def test_raises_context_manager_with_kwargs(self): def test_expected_exception_is_not_a_baseexception(self) -> None: with pytest.raises( TypeError, - match=wrap_escape( - "Expected a BaseException type, but got 'str'" - ), + match=wrap_escape("Expected a BaseException type, but got 'str'"), ): with pytest.raises("hello"): # type: ignore[call-overload] pass # pragma: no cover @@ -388,9 +386,7 @@ class NotAnException: with pytest.raises( TypeError, - match=wrap_escape( - "Expected a BaseException type, but got 'str'" - ), + match=wrap_escape("Expected a BaseException type, but got 'str'"), ): with pytest.raises(("hello", NotAnException)): # type: ignore[arg-type] pass # pragma: no cover diff --git a/testing/python/raises_group.py b/testing/python/raises_group.py index 935654f1815..e5e3b5cd2dc 100644 --- a/testing/python/raises_group.py +++ b/testing/python/raises_group.py @@ -1077,9 +1077,7 @@ def test_raisesexc() -> None: RaisesExc() # type: ignore[call-overload] with pytest.raises( ValueError, - match=wrap_escape( - "Expected a BaseException type, but got 'object'" - ), + match=wrap_escape("Expected a BaseException type, but got 'object'"), ): RaisesExc(object) # type: ignore[type-var] From 24b6a98c78523d8af5d216f159f7b6ece726c579 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 1 Nov 2025 12:31:06 -0300 Subject: [PATCH 3/3] Apply suggestion from @nicoddemus --- changelog/13861.improvement.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/changelog/13861.improvement.rst b/changelog/13861.improvement.rst index 8106ba74c01..2f062404e1c 100644 --- a/changelog/13861.improvement.rst +++ b/changelog/13861.improvement.rst @@ -1,2 +1 @@ Better sentence structure in a test's expected error message. Previously, the error message would be "expected exception must be , but got ". Now, it is "Expected , but got ". -This PR addresses the TODO comment in `testing/python/raises_group.py:49` and widens the scope to all expected error messages in both `testing/python/raises.py` and `testing/python/raises_group.py`.