]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-99553: fix bug where an ExceptionGroup subclass can wrap a BaseException (GH-99572)
authorIrit Katriel <1055913+iritkatriel@users.noreply.github.com>
Fri, 18 Nov 2022 15:44:43 +0000 (15:44 +0000)
committerGitHub <noreply@github.com>
Fri, 18 Nov 2022 15:44:43 +0000 (15:44 +0000)
Doc/library/exceptions.rst
Lib/test/test_exception_group.py
Misc/NEWS.d/next/Core and Builtins/2022-11-18-11-24-25.gh-issue-99553.F64h-n.rst [new file with mode: 0644]
Objects/exceptions.c

index fc856277d67b2ec7af6175bf751df66b0db36e31..4271a30de74a57ad692efc9aa710e0954e234fba 100644 (file)
@@ -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
 
 
index aa28e16bedfa689addf113262f67e2462978f40c..b11524e778e66557d56560db3c95e04a117a6099 100644 (file)
@@ -78,16 +78,30 @@ class InstanceCreation(unittest.TestCase):
         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 (file)
index 0000000..8d9f55d
--- /dev/null
@@ -0,0 +1,2 @@
+Fix bug where an :exc:`ExceptionGroup` subclass can wrap a
+:exc:`BaseException`.
index af888048a63de5aed8b5ea8e24734c2574618ec3..db6f7d52804d6aa6d69f09cba850555420dfdf86 100644 (file)
@@ -753,7 +753,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) {