aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2022-11-18 08:10:55 -0800
committerGitHub <noreply@github.com>2022-11-18 08:10:55 -0800
commit82ab9e6b7938484724a19e293a640d956111a012 (patch)
tree71e603440c9c07a233dda45a3e816624def46d73
parentbbac9a8bcc4d7c0692e8b4f62a955f7ca107b496 (diff)
downloadcpython3-82ab9e6b7938484724a19e293a640d956111a012.tar.gz
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@users.noreply.github.com>
-rw-r--r--Doc/library/exceptions.rst4
-rw-r--r--Lib/test/test_exception_group.py22
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-11-18-11-24-25.gh-issue-99553.F64h-n.rst2
-rw-r--r--Objects/exceptions.c14
4 files changed, 37 insertions, 5 deletions
diff --git a/Doc/library/exceptions.rst b/Doc/library/exceptions.rst
index fc856277d6..4271a30de7 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 2cfd873830..7fb45462e2 100644
--- a/Lib/test/test_exception_group.py
+++ b/Lib/test/test_exception_group.py
@@ -79,16 +79,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
index 0000000000..8d9f55d6d9
--- /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 01522aa806..4fba9b0a62 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) {