Skip to content

Commit 43226e1

Browse files
worksbyfridayclaude
andcommitted
Fix ExceptionGroup repr changing when original exception sequence is mutated
Store a string representation of exceptions at creation time (_exceptions_str) and use it in __repr__ instead of self.args[1], which reflects mutations to the original mutable sequence. This mirrors the CPython fix (python/cpython#141736) which was backported to Python 3.13.12+. The test is version-conditional: on Python < 3.11 (using the backport), it expects the fixed behavior; on 3.11+ (using the builtin), it expects the behavior of that specific CPython version. Fixes agronholm#154. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2cba843 commit 43226e1

2 files changed

Lines changed: 19 additions & 5 deletions

File tree

‎src/exceptiongroup/_exceptions.py‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def __new__(
102102

103103
instance = super().__new__(cls, __message, __exceptions)
104104
instance._exceptions = tuple(__exceptions)
105+
instance._exceptions_str = repr(list(__exceptions))
105106
return instance
106107

107108
def __init__(
@@ -275,7 +276,7 @@ def __str__(self) -> str:
275276
return f"{self.message} ({len(self._exceptions)} sub-exception{suffix})"
276277

277278
def __repr__(self) -> str:
278-
return f"{self.__class__.__name__}({self.args[0]!r}, {self.args[1]!r})"
279+
return f"{self.__class__.__name__}({self.args[0]!r}, {self._exceptions_str})"
279280

280281

281282
class ExceptionGroup(BaseExceptionGroup[_ExceptionT_co], Exception):

‎tests/test_exceptions.py‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,20 @@ def test_exceptions_mutate_original_sequence():
882882

883883
exceptions.append(KeyError("bar"))
884884
assert excgrp.exceptions is exc_tuple
885-
assert repr(excgrp) == (
886-
"BaseExceptionGroup('foo', [ValueError(1), KeyboardInterrupt(), "
887-
"KeyError('bar')])"
888-
)
885+
if sys.version_info < (3, 11):
886+
# Backport: repr should reflect the original exceptions, not the
887+
# mutated list (matches CPython fix: cpython#141736)
888+
assert repr(excgrp) == (
889+
"BaseExceptionGroup('foo', [ValueError(1), KeyboardInterrupt()])"
890+
)
891+
elif sys.version_info >= (3, 13, 12) or sys.version_info >= (3, 14):
892+
# CPython 3.13.12+ and 3.14+ include the fix
893+
assert repr(excgrp) == (
894+
"BaseExceptionGroup('foo', [ValueError(1), KeyboardInterrupt()])"
895+
)
896+
else:
897+
# CPython 3.11-3.13.11 still have the old behavior
898+
assert repr(excgrp) == (
899+
"BaseExceptionGroup('foo', [ValueError(1), KeyboardInterrupt(), "
900+
"KeyError('bar')])"
901+
)

0 commit comments

Comments
 (0)