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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy