Skip to content

Commit

Permalink
bpo-44232: Fix type_new() error reporting (GH-26359) (GH-26365)
Browse files Browse the repository at this point in the history
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.
(cherry picked from commit bd199e7)

Co-authored-by: Victor Stinner <[email protected]>
  • Loading branch information
miss-islington and vstinner authored May 26, 2021
1 parent 2442b34 commit 7b3b698
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 0 deletions.
18 changes: 18 additions & 0 deletions Lib/test/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,24 @@ class N(type, metaclass=M):
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):

Expand Down
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 4 additions & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 7b3b698

Please sign in to comment.