summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-05-25 20:28:10 (GMT)
committerGitHub <noreply@github.com>2021-05-25 20:28:10 (GMT)
commitbd199e72fb60a8ff001a023f23925092a290be91 (patch)
treee9b5c2af362534862219d453a36046301212d8b5
parentbd404ccac0d3e8358995ac0cbeec9373bb6c4d96 (diff)
downloadcpython-bd199e72fb60a8ff001a023f23925092a290be91.zip
cpython-bd199e72fb60a8ff001a023f23925092a290be91.tar.gz
cpython-bd199e72fb60a8ff001a023f23925092a290be91.tar.bz2
bpo-44232: Fix type_new() error reporting (GH-26359)
Fix a regression in type() when a metaclass raises an exception. The C function type_new() must properly report the exception when a metaclass constructor raises an exception and the winner class is not the metaclass.
-rw-r--r--Lib/test/test_types.py18
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2021-05-25-18-20-10.bpo-44232.DMcCCf.rst4
-rw-r--r--Objects/typeobject.c4
3 files changed, 26 insertions, 0 deletions
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index 25ebec5..767c3d0 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -1334,6 +1334,24 @@ class ClassCreationTests(unittest.TestCase):
N(5)
self.assertEqual(str(cm.exception), expected_message)
+ def test_metaclass_new_error(self):
+ # bpo-44232: The C function type_new() must properly report the
+ # exception when a metaclass constructor raises an exception and the
+ # winner class is not the metaclass.
+ class ModelBase(type):
+ def __new__(cls, name, bases, attrs):
+ super_new = super().__new__
+ new_class = super_new(cls, name, bases, {})
+ if name != "Model":
+ raise RuntimeWarning(f"{name=}")
+ return new_class
+
+ class Model(metaclass=ModelBase):
+ pass
+
+ with self.assertRaises(RuntimeWarning):
+ type("SouthPonies", (Model,), {})
+
class SimpleNamespaceTests(unittest.TestCase):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-05-25-18-20-10.bpo-44232.DMcCCf.rst b/Misc/NEWS.d/next/Core and Builtins/2021-05-25-18-20-10.bpo-44232.DMcCCf.rst
new file mode 100644
index 0000000..fcd124d
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-05-25-18-20-10.bpo-44232.DMcCCf.rst
@@ -0,0 +1,4 @@
+Fix a regression in :func:`type` when a metaclass raises an exception. The C
+function :c:func:`type_new` must properly report the exception when a metaclass
+constructor raises an exception and the winner class is not the metaclass.
+Patch by Victor Stinner.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index af99ab7..1460085 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3256,6 +3256,9 @@ type_new_get_bases(type_new_ctx *ctx, PyObject **type)
if (winner->tp_new != type_new) {
/* Pass it to the winner */
*type = winner->tp_new(winner, ctx->args, ctx->kwds);
+ if (*type == NULL) {
+ return -1;
+ }
return 1;
}
@@ -3307,6 +3310,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds)
PyObject *type = NULL;
int res = type_new_get_bases(&ctx, &type);
if (res < 0) {
+ assert(PyErr_Occurred());
return NULL;
}
if (res == 1) {