Skip to content

Commit 5386730

Browse files
authored
[3.11] gh-103590: do not wrap a single exception raised from a try-except* (#104094)
1 parent f9231a0 commit 5386730

File tree

4 files changed

+31
-25
lines changed

4 files changed

+31
-25
lines changed

Doc/reference/compound_stmts.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,10 @@ Any remaining exceptions that were not handled by any :keyword:`!except*`
365365
clause are re-raised at the end, combined into an exception group along with
366366
all exceptions that were raised from within :keyword:`!except*` clauses.
367367

368+
From version 3.11.4, when the entire :exc:`ExceptionGroup` is handled and
369+
only one exception is raised from an :keyword:`!except*` clause, this
370+
exception is no longer wrapped to form a new :exc:`ExceptionGroup`.
371+
368372
If the raised exception is not an exception group and its type matches
369373
one of the :keyword:`!except*` clauses, it is caught and wrapped by an
370374
exception group with an empty message string. ::

Lib/test/test_except_star.py

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -636,18 +636,17 @@ def test_raise_handle_all_raise_one_named(self):
636636
raise orig
637637
except* (TypeError, ValueError) as e:
638638
raise SyntaxError(3)
639-
except BaseException as e:
639+
except SyntaxError as e:
640640
exc = e
641641

642-
self.assertExceptionIsLike(
643-
exc, ExceptionGroup("", [SyntaxError(3)]))
642+
self.assertExceptionIsLike(exc, SyntaxError(3))
644643

645644
self.assertExceptionIsLike(
646-
exc.exceptions[0].__context__,
645+
exc.__context__,
647646
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
648647

649648
self.assertMetadataNotEqual(orig, exc)
650-
self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
649+
self.assertMetadataEqual(orig, exc.__context__)
651650

652651
def test_raise_handle_all_raise_one_unnamed(self):
653652
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@@ -656,18 +655,17 @@ def test_raise_handle_all_raise_one_unnamed(self):
656655
raise orig
657656
except* (TypeError, ValueError) as e:
658657
raise SyntaxError(3)
659-
except ExceptionGroup as e:
658+
except SyntaxError as e:
660659
exc = e
661660

662-
self.assertExceptionIsLike(
663-
exc, ExceptionGroup("", [SyntaxError(3)]))
661+
self.assertExceptionIsLike(exc, SyntaxError(3))
664662

665663
self.assertExceptionIsLike(
666-
exc.exceptions[0].__context__,
664+
exc.__context__,
667665
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
668666

669667
self.assertMetadataNotEqual(orig, exc)
670-
self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
668+
self.assertMetadataEqual(orig, exc.__context__)
671669

672670
def test_raise_handle_all_raise_two_named(self):
673671
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@@ -791,23 +789,22 @@ def test_raise_handle_all_raise_one_named(self):
791789
raise orig
792790
except* (TypeError, ValueError) as e:
793791
raise SyntaxError(3) from e
794-
except BaseException as e:
792+
except SyntaxError as e:
795793
exc = e
796794

797-
self.assertExceptionIsLike(
798-
exc, ExceptionGroup("", [SyntaxError(3)]))
795+
self.assertExceptionIsLike(exc, SyntaxError(3))
799796

800797
self.assertExceptionIsLike(
801-
exc.exceptions[0].__context__,
798+
exc.__context__,
802799
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
803800

804801
self.assertExceptionIsLike(
805-
exc.exceptions[0].__cause__,
802+
exc.__cause__,
806803
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
807804

808805
self.assertMetadataNotEqual(orig, exc)
809-
self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
810-
self.assertMetadataEqual(orig, exc.exceptions[0].__cause__)
806+
self.assertMetadataEqual(orig, exc.__context__)
807+
self.assertMetadataEqual(orig, exc.__cause__)
811808

812809
def test_raise_handle_all_raise_one_unnamed(self):
813810
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@@ -817,23 +814,22 @@ def test_raise_handle_all_raise_one_unnamed(self):
817814
except* (TypeError, ValueError) as e:
818815
e = sys.exception()
819816
raise SyntaxError(3) from e
820-
except ExceptionGroup as e:
817+
except SyntaxError as e:
821818
exc = e
822819

823-
self.assertExceptionIsLike(
824-
exc, ExceptionGroup("", [SyntaxError(3)]))
820+
self.assertExceptionIsLike(exc, SyntaxError(3))
825821

826822
self.assertExceptionIsLike(
827-
exc.exceptions[0].__context__,
823+
exc.__context__,
828824
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
829825

830826
self.assertExceptionIsLike(
831-
exc.exceptions[0].__cause__,
827+
exc.__cause__,
832828
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
833829

834830
self.assertMetadataNotEqual(orig, exc)
835-
self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
836-
self.assertMetadataEqual(orig, exc.exceptions[0].__cause__)
831+
self.assertMetadataEqual(orig, exc.__context__)
832+
self.assertMetadataEqual(orig, exc.__cause__)
837833

838834
def test_raise_handle_all_raise_two_named(self):
839835
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Do not wrap a single exception raised from a ``try-except*`` construct in an :exc:`ExceptionGroup`.

Objects/exceptions.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,12 @@ _PyExc_PrepReraiseStar(PyObject *orig, PyObject *excs)
14231423
if (res < 0) {
14241424
goto done;
14251425
}
1426-
result = _PyExc_CreateExceptionGroup("", raised_list);
1426+
if (PyList_GET_SIZE(raised_list) > 1) {
1427+
result = _PyExc_CreateExceptionGroup("", raised_list);
1428+
}
1429+
else {
1430+
result = Py_NewRef(PyList_GetItem(raised_list, 0));
1431+
}
14271432
if (result == NULL) {
14281433
goto done;
14291434
}

0 commit comments

Comments
 (0)