Skip to content

Commit 511b953

Browse files
committed
BaseExceptionGroup.derive should not copy __notes__
this makes the behaviour follow that of CPython more closely. Instead, copy __notes__ (if present) in the *callers* of derive. The (modified) test passes now, and it passes on py3.11. It fails before the changes.
1 parent 2f23259 commit 511b953

File tree

2 files changed

+20
-18
lines changed

2 files changed

+20
-18
lines changed

src/exceptiongroup/_exceptions.py

+13-18
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ def get_condition_filter(
4141

4242
raise TypeError("expected a function, exception type or tuple of exception types")
4343

44+
def _derive_and_copy_attributes(self, excs):
45+
eg = self.derive(excs)
46+
eg.__cause__ = self.__cause__
47+
eg.__context__ = self.__context__
48+
eg.__traceback__ = self.__traceback__
49+
if hasattr(self, "__notes__"):
50+
# Create a new list so that add_note() only affects one exceptiongroup
51+
eg.__notes__ = list(self.__notes__)
52+
return eg
4453

4554
class BaseExceptionGroup(BaseException, Generic[_BaseExceptionT_co]):
4655
"""A combination of multiple unrelated exceptions."""
@@ -154,10 +163,7 @@ def subgroup(
154163
if not modified:
155164
return self
156165
elif exceptions:
157-
group = self.derive(exceptions)
158-
group.__cause__ = self.__cause__
159-
group.__context__ = self.__context__
160-
group.__traceback__ = self.__traceback__
166+
group = _derive_and_copy_attributes(self, exceptions)
161167
return group
162168
else:
163169
return None
@@ -230,17 +236,11 @@ def split(
230236

231237
matching_group: _BaseExceptionGroupSelf | None = None
232238
if matching_exceptions:
233-
matching_group = self.derive(matching_exceptions)
234-
matching_group.__cause__ = self.__cause__
235-
matching_group.__context__ = self.__context__
236-
matching_group.__traceback__ = self.__traceback__
239+
matching_group = _derive_and_copy_attributes(self, matching_exceptions)
237240

238241
nonmatching_group: _BaseExceptionGroupSelf | None = None
239242
if nonmatching_exceptions:
240-
nonmatching_group = self.derive(nonmatching_exceptions)
241-
nonmatching_group.__cause__ = self.__cause__
242-
nonmatching_group.__context__ = self.__context__
243-
nonmatching_group.__traceback__ = self.__traceback__
243+
nonmatching_group = _derive_and_copy_attributes(self, nonmatching_exceptions)
244244

245245
return matching_group, nonmatching_group
246246

@@ -257,12 +257,7 @@ def derive(
257257
def derive(
258258
self, __excs: Sequence[_BaseExceptionT]
259259
) -> BaseExceptionGroup[_BaseExceptionT]:
260-
eg = BaseExceptionGroup(self.message, __excs)
261-
if hasattr(self, "__notes__"):
262-
# Create a new list so that add_note() only affects one exceptiongroup
263-
eg.__notes__ = list(self.__notes__)
264-
265-
return eg
260+
return BaseExceptionGroup(self.message, __excs)
266261

267262
def __str__(self) -> str:
268263
suffix = "" if len(self._exceptions) == 1 else "s"

tests/test_exceptions.py

+7
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ def derive(self, excs):
786786
except ValueError as ve:
787787
raise EG("eg", [ve, nested], 42)
788788
except EG as e:
789+
e.add_note("hello")
789790
eg = e
790791

791792
self.assertMatchesTemplate(eg, EG, [ValueError(1), [TypeError(2)]])
@@ -796,29 +797,35 @@ def derive(self, excs):
796797
self.assertMatchesTemplate(rest, EG, [ValueError(1), [TypeError(2)]])
797798
self.assertEqual(rest.code, 42)
798799
self.assertEqual(rest.exceptions[1].code, 101)
800+
self.assertEqual(rest.__notes__, ["hello"])
799801

800802
# Match Everything
801803
match, rest = self.split_exception_group(eg, (ValueError, TypeError))
802804
self.assertMatchesTemplate(match, EG, [ValueError(1), [TypeError(2)]])
803805
self.assertEqual(match.code, 42)
804806
self.assertEqual(match.exceptions[1].code, 101)
807+
self.assertEqual(match.__notes__, ["hello"])
805808
self.assertIsNone(rest)
806809

807810
# Match ValueErrors
808811
match, rest = self.split_exception_group(eg, ValueError)
809812
self.assertMatchesTemplate(match, EG, [ValueError(1)])
810813
self.assertEqual(match.code, 42)
814+
self.assertEqual(match.__notes__, ["hello"])
811815
self.assertMatchesTemplate(rest, EG, [[TypeError(2)]])
812816
self.assertEqual(rest.code, 42)
813817
self.assertEqual(rest.exceptions[0].code, 101)
818+
self.assertEqual(rest.__notes__, ["hello"])
814819

815820
# Match TypeErrors
816821
match, rest = self.split_exception_group(eg, TypeError)
817822
self.assertMatchesTemplate(match, EG, [[TypeError(2)]])
818823
self.assertEqual(match.code, 42)
819824
self.assertEqual(match.exceptions[0].code, 101)
825+
self.assertEqual(match.__notes__, ["hello"])
820826
self.assertMatchesTemplate(rest, EG, [ValueError(1)])
821827
self.assertEqual(rest.code, 42)
828+
self.assertEqual(rest.__notes__, ["hello"])
822829

823830

824831
def test_repr():

0 commit comments

Comments
 (0)