diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 0a5ecd5..31b1345 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1726,6 +1726,18 @@ order (MRO) for bases """ else: self.fail("non-sequence mro() return not caught") + def test_activemro(self): + class Meta(type): + def mro(self): + self.__dict__["f"]() + return super().mro() + + class A(metaclass=Meta): + def f(): + __class__.myself = __class__ + + self.assertIs(A, A.myself) + def test_overloading(self): # Testing operator overloading... diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 5227f6a..b33c0b9 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2270,7 +2270,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) { PyObject *name, *bases = NULL, *orig_dict, *dict = NULL; static char *kwlist[] = {"name", "bases", "dict", 0}; - PyObject *qualname, *slots = NULL, *tmp, *newslots; + PyObject *qualname, *slots = NULL, *tmp, *newslots, *cell; PyTypeObject *type = NULL, *base, *tmptype, *winner; PyHeapTypeObject *et; PyMemberDef *mp; @@ -2278,6 +2278,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) int j, may_add_dict, may_add_weak, add_dict, add_weak; _Py_IDENTIFIER(__qualname__); _Py_IDENTIFIER(__slots__); + _Py_IDENTIFIER(__classcell__); assert(args != NULL && PyTuple_Check(args)); assert(kwds == NULL || PyDict_Check(kwds)); @@ -2656,6 +2657,14 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) else type->tp_free = PyObject_Del; + /* store type in class' cell */ + cell = _PyDict_GetItemId(dict, &PyId___classcell__); + if (cell != NULL && PyCell_Check(cell)) { + PyCell_Set(cell, (PyObject *) type); + PyDict_DelItem(dict, PyId___classcell__.object); + PyErr_Clear(); + } + /* Initialize the rest */ if (PyType_Ready(type) < 0) goto error; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 220c92d..59baa83 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -183,8 +183,6 @@ builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds) cls = PyEval_CallObjectWithKeywords(meta, margs, mkw); Py_DECREF(margs); } - if (cls != NULL && PyCell_Check(cell)) - PyCell_Set(cell, cls); Py_DECREF(cell); } Py_DECREF(ns); diff --git a/Python/compile.c b/Python/compile.c index e46676c..953d629 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1883,7 +1883,7 @@ compiler_class(struct compiler *c, stmt_ty s) return 0; } if (c->u->u_ste->ste_needs_class_closure) { - /* return the (empty) __class__ cell */ + /* store __classcell__ into class namespace */ str = PyUnicode_InternFromString("__class__"); if (str == NULL) { compiler_exit_scope(c); @@ -1896,14 +1896,21 @@ compiler_class(struct compiler *c, stmt_ty s) return 0; } assert(i == 0); - /* Return the cell where to store __class__ */ + ADDOP_I(c, LOAD_CLOSURE, i); + str = PyUnicode_InternFromString("__classcell__"); + if (!str || !compiler_nameop(c, str, Store)) { + Py_XDECREF(str); + compiler_exit_scope(c); + return 0; + } + Py_DECREF(str); } else { + /* This happens when nobody references the cell. */ assert(PyDict_Size(c->u->u_cellvars) == 0); - /* This happens when nobody references the cell. Return None. */ - ADDOP_O(c, LOAD_CONST, Py_None, consts); } + ADDOP_O(c, LOAD_CONST, Py_None, consts); ADDOP_IN_SCOPE(c, RETURN_VALUE); /* create the code object */ co = assemble(c, 1);