Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/_pytest/raises.py
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ def _check_exceptions(
f"\n{indent_1}{self._repr_expected(self.expected_exceptions[i_failed])}"
)
for i_actual, actual in enumerate(actual_exceptions):
if results.get_result(i_exp, i_actual) is None:
if results.get_result(i_failed, i_actual) is None:
# we print full repr of match target
s += (
f"\n{indent_2}It matches {backquote(repr(actual))} which was paired with "
Expand Down
26 changes: 26 additions & 0 deletions testing/python/raises_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -1355,3 +1355,29 @@ def test_tuples() -> None:
),
):
RaisesGroup((ValueError, IndexError)) # type: ignore[call-overload]


def test_stale_loop_variable_in_error_message() -> None:
"""Regression test: error message for failed expected exceptions should
reference the correct expected index, not a stale loop variable from
a previous enumerate() loop."""
# We need multiple expected exceptions where a non-last expected fails.
# Expected: [RaisesExc(ValueError, match='foo'), TypeError, RuntimeError]
# Actual: [ValueError('bar'), TypeError(), KeyError()]
# Greedy matching: TypeError() pairs with TypeError (index 1->1)
# Failed expected: index 0 (match fails) and index 2 (KeyError is not RuntimeError)
# Remaining actual: index 0 (ValueError('bar')) and index 2 (KeyError())
#
# With the stale-variable bug, the error message for the first failed
# expected (index 0) would use results from the last expected (index 2)
# instead of its own, potentially showing incorrect "It matches" lines.
with pytest.raises(Failed) as exc_info:
with RaisesGroup(RaisesExc(ValueError, match="foo"), TypeError, RuntimeError):
raise ExceptionGroup(
"",
[ValueError("bar"), TypeError(), KeyError()],
)
# Verify the error message references the correct expected exceptions
message = str(exc_info.value)
assert "RaisesExc(ValueError, match='foo')" in message
assert "RuntimeError" in message