[Python-checkins] gh-99553: fix bug where an ExceptionGroup subclass can wrap a BaseException (GH-99572)

miss-islington webhook-mailer at python.org
Fri Nov 18 11:11:03 EST 2022


https://github.com/python/cpython/commit/82ab9e6b7938484724a19e293a640d956111a012
commit: 82ab9e6b7938484724a19e293a640d956111a012
branch: 3.11
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: miss-islington <31488909+miss-islington at users.noreply.github.com>
date: 2022-11-18T08:10:55-08:00
summary:

gh-99553: fix bug where an ExceptionGroup subclass can wrap a BaseException (GH-99572)

(cherry picked from commit c8c6113398ee9a7867fe9b08bc539cceb61e2aaa)

Co-authored-by: Irit Katriel <1055913+iritkatriel at users.noreply.github.com>

files:
A Misc/NEWS.d/next/Core and Builtins/2022-11-18-11-24-25.gh-issue-99553.F64h-n.rst
M Doc/library/exceptions.rst
M Lib/test/test_exception_group.py
M Objects/exceptions.c

diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst
index fc856277d67b..4271a30de74a 100644
--- a/Doc/library/exceptions.rst
+++ b/Doc/library/exceptions.rst
@@ -965,6 +965,10 @@ their subgroups based on the types of the contained exceptions.
          def derive(self, excs):
             return Errors(excs, self.exit_code)
 
+   Like :exc:`ExceptionGroup`, any subclass of :exc:`BaseExceptionGroup` which
+   is also a subclass of :exc:`Exception` can only wrap instances of
+   :exc:`Exception`.
+
    .. versionadded:: 3.11
 
 
diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py
index 2cfd8738304d..7fb45462e20f 100644
--- a/Lib/test/test_exception_group.py
+++ b/Lib/test/test_exception_group.py
@@ -79,16 +79,30 @@ def test_BEG_wraps_BaseException__creates_BEG(self):
         beg = BaseExceptionGroup("beg", [ValueError(1), KeyboardInterrupt(2)])
         self.assertIs(type(beg), BaseExceptionGroup)
 
-    def test_EG_subclass_wraps_anything(self):
+    def test_EG_subclass_wraps_non_base_exceptions(self):
         class MyEG(ExceptionGroup):
             pass
 
         self.assertIs(
             type(MyEG("eg", [ValueError(12), TypeError(42)])),
             MyEG)
-        self.assertIs(
-            type(MyEG("eg", [ValueError(12), KeyboardInterrupt(42)])),
-            MyEG)
+
+    def test_EG_subclass_does_not_wrap_base_exceptions(self):
+        class MyEG(ExceptionGroup):
+            pass
+
+        msg = "Cannot nest BaseExceptions in 'MyEG'"
+        with self.assertRaisesRegex(TypeError, msg):
+            MyEG("eg", [ValueError(12), KeyboardInterrupt(42)])
+
+    def test_BEG_and_E_subclass_does_not_wrap_base_exceptions(self):
+        class MyEG(BaseExceptionGroup, ValueError):
+            pass
+
+        msg = "Cannot nest BaseExceptions in 'MyEG'"
+        with self.assertRaisesRegex(TypeError, msg):
+            MyEG("eg", [ValueError(12), KeyboardInterrupt(42)])
+
 
     def test_BEG_subclass_wraps_anything(self):
         class MyBEG(BaseExceptionGroup):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-18-11-24-25.gh-issue-99553.F64h-n.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-18-11-24-25.gh-issue-99553.F64h-n.rst
new file mode 100644
index 000000000000..8d9f55d6d9d0
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-18-11-24-25.gh-issue-99553.F64h-n.rst	
@@ -0,0 +1,2 @@
+Fix bug where an :exc:`ExceptionGroup` subclass can wrap a
+:exc:`BaseException`.
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index 01522aa8068a..4fba9b0a6248 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -774,7 +774,19 @@ BaseExceptionGroup_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
         }
     }
     else {
-        /* Do nothing - we don't interfere with subclasses */
+        /* user-defined subclass */
+        if (nested_base_exceptions) {
+            int nonbase = PyObject_IsSubclass((PyObject*)cls, PyExc_Exception);
+            if (nonbase == -1) {
+                goto error;
+            }
+            else if (nonbase == 1) {
+                PyErr_Format(PyExc_TypeError,
+                    "Cannot nest BaseExceptions in '%.200s'",
+                    cls->tp_name);
+                goto error;
+            }
+        }
     }
 
     if (!cls) {



More information about the Python-checkins mailing list