[Python-checkins] [3.11] gh-103590: do not wrap a single exception raised from a try-except* (#104094)
iritkatriel
webhook-mailer at python.org
Tue May 2 14:24:09 EDT 2023
https://github.com/python/cpython/commit/5386730cdd3f2da88e485220dc9fb606f5082430
commit: 5386730cdd3f2da88e485220dc9fb606f5082430
branch: 3.11
author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com>
committer: iritkatriel <1055913+iritkatriel at users.noreply.github.com>
date: 2023-05-02T19:24:02+01:00
summary:
[3.11] gh-103590: do not wrap a single exception raised from a try-except* (#104094)
files:
A Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst
M Doc/reference/compound_stmts.rst
M Lib/test/test_except_star.py
M Objects/exceptions.c
diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst
index f0a8936c35bf..54228b8a4e60 100644
--- a/Doc/reference/compound_stmts.rst
+++ b/Doc/reference/compound_stmts.rst
@@ -365,6 +365,10 @@ Any remaining exceptions that were not handled by any :keyword:`!except*`
clause are re-raised at the end, combined into an exception group along with
all exceptions that were raised from within :keyword:`!except*` clauses.
+From version 3.11.4, when the entire :exc:`ExceptionGroup` is handled and
+only one exception is raised from an :keyword:`!except*` clause, this
+exception is no longer wrapped to form a new :exc:`ExceptionGroup`.
+
If the raised exception is not an exception group and its type matches
one of the :keyword:`!except*` clauses, it is caught and wrapped by an
exception group with an empty message string. ::
diff --git a/Lib/test/test_except_star.py b/Lib/test/test_except_star.py
index c5167c5bba38..6d6f6043b83b 100644
--- a/Lib/test/test_except_star.py
+++ b/Lib/test/test_except_star.py
@@ -636,18 +636,17 @@ def test_raise_handle_all_raise_one_named(self):
raise orig
except* (TypeError, ValueError) as e:
raise SyntaxError(3)
- except BaseException as e:
+ except SyntaxError as e:
exc = e
- self.assertExceptionIsLike(
- exc, ExceptionGroup("", [SyntaxError(3)]))
+ self.assertExceptionIsLike(exc, SyntaxError(3))
self.assertExceptionIsLike(
- exc.exceptions[0].__context__,
+ exc.__context__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
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):
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@@ -656,18 +655,17 @@ def test_raise_handle_all_raise_one_unnamed(self):
raise orig
except* (TypeError, ValueError) as e:
raise SyntaxError(3)
- except ExceptionGroup as e:
+ except SyntaxError as e:
exc = e
- self.assertExceptionIsLike(
- exc, ExceptionGroup("", [SyntaxError(3)]))
+ self.assertExceptionIsLike(exc, SyntaxError(3))
self.assertExceptionIsLike(
- exc.exceptions[0].__context__,
+ exc.__context__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
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):
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@@ -791,23 +789,22 @@ def test_raise_handle_all_raise_one_named(self):
raise orig
except* (TypeError, ValueError) as e:
raise SyntaxError(3) from e
- except BaseException as e:
+ except SyntaxError as e:
exc = e
- self.assertExceptionIsLike(
- exc, ExceptionGroup("", [SyntaxError(3)]))
+ self.assertExceptionIsLike(exc, SyntaxError(3))
self.assertExceptionIsLike(
- exc.exceptions[0].__context__,
+ exc.__context__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertExceptionIsLike(
- exc.exceptions[0].__cause__,
+ exc.__cause__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertMetadataNotEqual(orig, exc)
- self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
- self.assertMetadataEqual(orig, exc.exceptions[0].__cause__)
+ self.assertMetadataEqual(orig, exc.__context__)
+ self.assertMetadataEqual(orig, exc.__cause__)
def test_raise_handle_all_raise_one_unnamed(self):
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
@@ -817,23 +814,22 @@ def test_raise_handle_all_raise_one_unnamed(self):
except* (TypeError, ValueError) as e:
e = sys.exception()
raise SyntaxError(3) from e
- except ExceptionGroup as e:
+ except SyntaxError as e:
exc = e
- self.assertExceptionIsLike(
- exc, ExceptionGroup("", [SyntaxError(3)]))
+ self.assertExceptionIsLike(exc, SyntaxError(3))
self.assertExceptionIsLike(
- exc.exceptions[0].__context__,
+ exc.__context__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertExceptionIsLike(
- exc.exceptions[0].__cause__,
+ exc.__cause__,
ExceptionGroup("eg", [TypeError(1), ValueError(2)]))
self.assertMetadataNotEqual(orig, exc)
- self.assertMetadataEqual(orig, exc.exceptions[0].__context__)
- self.assertMetadataEqual(orig, exc.exceptions[0].__cause__)
+ self.assertMetadataEqual(orig, exc.__context__)
+ self.assertMetadataEqual(orig, exc.__cause__)
def test_raise_handle_all_raise_two_named(self):
orig = ExceptionGroup("eg", [TypeError(1), ValueError(2)])
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst
new file mode 100644
index 000000000000..af733a8207a2
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-16-12-41.gh-issue-103590.7DHDOE.rst
@@ -0,0 +1 @@
+Do not wrap a single exception raised from a ``try-except*`` construct in an :exc:`ExceptionGroup`.
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index 4fba9b0a6248..a95b75205b87 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -1423,7 +1423,12 @@ _PyExc_PrepReraiseStar(PyObject *orig, PyObject *excs)
if (res < 0) {
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) {
goto done;
}
More information about the Python-checkins
mailing list