gh-103590: do not wrap a single exception raised from a try-except* (#103665)

This commit is contained in:
Irit Katriel 2023-04-27 12:52:15 +01:00 committed by GitHub
parent 78942ecd9b
commit 63842bd907
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 25 deletions

View File

@ -237,6 +237,11 @@ Other Language Changes
wrapped by a :exc:`RuntimeError`. Context information is added to the wrapped by a :exc:`RuntimeError`. Context information is added to the
exception as a :pep:`678` note. (Contributed by Irit Katriel in :gh:`77757`.) exception as a :pep:`678` note. (Contributed by Irit Katriel in :gh:`77757`.)
* When a ``try-except*`` construct handles the entire :exc:`ExceptionGroup`
and raises one other exception, that exception is no longer wrapped in an
:exc:`ExceptionGroup`. (Contributed by Irit Katriel in :gh:`103590`.)
New Modules New Modules
=========== ===========

View File

@ -618,18 +618,17 @@ class TestExceptStarRaise(ExceptStarTest):
raise orig raise orig
except* (TypeError, ValueError) as e: except* (TypeError, ValueError) as e:
raise SyntaxError(3) raise SyntaxError(3)
except BaseException as e: except SyntaxError as e:
exc = e exc = e
self.assertExceptionIsLike( self.assertExceptionIsLike(exc, SyntaxError(3))
exc, ExceptionGroup("", [SyntaxError(3)]))
self.assertExceptionIsLike( self.assertExceptionIsLike(
exc.exceptions[0].__context__, exc.__context__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)])) ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertMetadataNotEqual(orig, exc) self.assertMetadataNotEqual(orig, exc)
self.assertMetadataEqual(orig, exc.exceptions[0].__context__) self.assertMetadataEqual(orig, exc.__context__)
def test_raise_handle_all_raise_one_unnamed(self): def test_raise_handle_all_raise_one_unnamed(self):
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)]) orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@ -638,18 +637,17 @@ class TestExceptStarRaise(ExceptStarTest):
raise orig raise orig
except* (TypeError, ValueError) as e: except* (TypeError, ValueError) as e:
raise SyntaxError(3) raise SyntaxError(3)
except ExceptionGroup as e: except SyntaxError as e:
exc = e exc = e
self.assertExceptionIsLike( self.assertExceptionIsLike(exc, SyntaxError(3))
exc, ExceptionGroup("", [SyntaxError(3)]))
self.assertExceptionIsLike( self.assertExceptionIsLike(
exc.exceptions[0].__context__, exc.__context__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)])) ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertMetadataNotEqual(orig, exc) self.assertMetadataNotEqual(orig, exc)
self.assertMetadataEqual(orig, exc.exceptions[0].__context__) self.assertMetadataEqual(orig, exc.__context__)
def test_raise_handle_all_raise_two_named(self): def test_raise_handle_all_raise_two_named(self):
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)]) orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@ -773,23 +771,22 @@ class TestExceptStarRaiseFrom(ExceptStarTest):
raise orig raise orig
except* (TypeError, ValueError) as e: except* (TypeError, ValueError) as e:
raise SyntaxError(3) from e raise SyntaxError(3) from e
except BaseException as e: except SyntaxError as e:
exc = e exc = e
self.assertExceptionIsLike( self.assertExceptionIsLike(exc, SyntaxError(3))
exc, ExceptionGroup("", [SyntaxError(3)]))
self.assertExceptionIsLike( self.assertExceptionIsLike(
exc.exceptions[0].__context__, exc.__context__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)])) ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertExceptionIsLike( self.assertExceptionIsLike(
exc.exceptions[0].__cause__, exc.__cause__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)])) ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertMetadataNotEqual(orig, exc) self.assertMetadataNotEqual(orig, exc)
self.assertMetadataEqual(orig, exc.exceptions[0].__context__) self.assertMetadataEqual(orig, exc.__context__)
self.assertMetadataEqual(orig, exc.exceptions[0].__cause__) self.assertMetadataEqual(orig, exc.__cause__)
def test_raise_handle_all_raise_one_unnamed(self): def test_raise_handle_all_raise_one_unnamed(self):
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)]) orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@ -799,23 +796,22 @@ class TestExceptStarRaiseFrom(ExceptStarTest):
except* (TypeError, ValueError) as e: except* (TypeError, ValueError) as e:
e = sys.exception() e = sys.exception()
raise SyntaxError(3) from e raise SyntaxError(3) from e
except ExceptionGroup as e: except SyntaxError as e:
exc = e exc = e
self.assertExceptionIsLike( self.assertExceptionIsLike(exc, SyntaxError(3))
exc, ExceptionGroup("", [SyntaxError(3)]))
self.assertExceptionIsLike( self.assertExceptionIsLike(
exc.exceptions[0].__context__, exc.__context__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)])) ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertExceptionIsLike( self.assertExceptionIsLike(
exc.exceptions[0].__cause__, exc.__cause__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)])) ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertMetadataNotEqual(orig, exc) self.assertMetadataNotEqual(orig, exc)
self.assertMetadataEqual(orig, exc.exceptions[0].__context__) self.assertMetadataEqual(orig, exc.__context__)
self.assertMetadataEqual(orig, exc.exceptions[0].__cause__) self.assertMetadataEqual(orig, exc.__cause__)
def test_raise_handle_all_raise_two_named(self): def test_raise_handle_all_raise_two_named(self):
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)]) orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])

View File

@ -0,0 +1 @@
Do not wrap a single exception raised from a ``try-except*`` construct in an :exc:`ExceptionGroup`.

View File

@ -1421,7 +1421,12 @@ _PyExc_PrepReraiseStar(PyObject *orig, PyObject *excs)
if (res < 0) { if (res < 0) {
goto done; goto done;
} }
result = _PyExc_CreateExceptionGroup("", raised_list); if (PyList_GET_SIZE(raised_list) > 1) {
result = _PyExc_CreateExceptionGroup("", raised_list);
}
else {
result = Py_NewRef(PyList_GetItem(raised_list, 0));
}
if (result == NULL) { if (result == NULL) {
goto done; goto done;
} }