diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -469,6 +469,10 @@ PyAPI_FUNC(long) PyType_GetFlags(PyTypeObject*); +#ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyType_New(PyTypeObject *, PyObject *, PyObject *, PyObject *); +#endif + #define PyType_Check(op) \ PyType_FastSubclass(Py_TYPE(op), Py_TPFLAGS_TYPE_SUBCLASS) #define PyType_CheckExact(op) (Py_TYPE(op) == &PyType_Type) diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1962,12 +1962,10 @@ } static PyObject * -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; - PyTypeObject *type = NULL, *base, *tmptype, *winner; +_type_new(PyTypeObject *metatype, PyObject *name, PyObject *bases, PyObject *ns) +{ + PyObject *dict = NULL, *qualname, *slots = NULL, *tmp, *newslots; + PyTypeObject *type = NULL, *base, *tmptype; PyHeapTypeObject *et; PyMemberDef *mp; Py_ssize_t i, nbases, nslots, slotoffset, add_dict, add_weak; @@ -1975,49 +1973,6 @@ _Py_IDENTIFIER(__qualname__); _Py_IDENTIFIER(__slots__); - assert(args != NULL && PyTuple_Check(args)); - assert(kwds == NULL || PyDict_Check(kwds)); - - /* Special case: type(x) should return x->ob_type */ - { - const Py_ssize_t nargs = PyTuple_GET_SIZE(args); - const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds); - - if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) { - PyObject *x = PyTuple_GET_ITEM(args, 0); - Py_INCREF(Py_TYPE(x)); - return (PyObject *) Py_TYPE(x); - } - - /* SF bug 475327 -- if that didn't trigger, we need 3 - arguments. but PyArg_ParseTupleAndKeywords below may give - a msg saying type() needs exactly 3. */ - if (nargs + nkwds != 3) { - PyErr_SetString(PyExc_TypeError, - "type() takes 1 or 3 arguments"); - return NULL; - } - } - - /* Check arguments: (name, bases, dict) */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "UO!O!:type", kwlist, - &name, - &PyTuple_Type, &bases, - &PyDict_Type, &orig_dict)) - return NULL; - - /* Determine the proper metatype to deal with this: */ - winner = _PyType_CalculateMetaclass(metatype, bases); - if (winner == NULL) { - return NULL; - } - - if (winner != metatype) { - if (winner->tp_new != type_new) /* Pass it to the winner */ - return winner->tp_new(winner, args, kwds); - metatype = winner; - } - /* Adjust for empty tuple bases */ nbases = PyTuple_GET_SIZE(bases); if (nbases == 0) { @@ -2041,7 +1996,7 @@ goto error; } - dict = PyDict_Copy(orig_dict); + dict = PyDict_Copy(ns); if (dict == NULL) goto error; @@ -2369,6 +2324,59 @@ return NULL; } +static PyObject * +type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) +{ + PyTypeObject *winner; + PyObject *name, *bases = NULL, *ns = NULL; + static char *kwlist[] = {"name", "bases", "dict", 0}; + + assert(args != NULL && PyTuple_Check(args)); + assert(kwds == NULL || PyDict_Check(kwds)); + + /* Special case: type(x) should return x->ob_type */ + { + const Py_ssize_t nargs = PyTuple_GET_SIZE(args); + const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds); + + if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) { + PyObject *x = PyTuple_GET_ITEM(args, 0); + Py_INCREF(Py_TYPE(x)); + return (PyObject *) Py_TYPE(x); + } + + /* SF bug 475327 -- if that didn't trigger, we need 3 + arguments. but PyArg_ParseTupleAndKeywords below may give + a msg saying type() needs exactly 3. */ + if (nargs + nkwds != 3) { + PyErr_SetString(PyExc_TypeError, + "type() takes 1 or 3 arguments"); + return NULL; + } + } + + /* Check arguments: (name, bases, ns) */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "UO!O!:type", kwlist, + &name, + &PyTuple_Type, &bases, + &PyDict_Type, &ns)) + return NULL; + + /* Determine the proper metatype to deal with this: */ + winner = _PyType_CalculateMetaclass(metatype, bases); + if (winner == NULL) { + return NULL; + } + + if (winner != metatype) { + if (winner->tp_new != type_new) /* Pass it to the winner */ + return winner->tp_new(winner, args, kwds); + metatype = winner; + } + + return _type_new(metatype, name, bases, ns); +} + static short slotoffsets[] = { -1, /* invalid slot */ #include "typeslots.inc" @@ -6183,6 +6191,84 @@ } +/* easy spelling for "type(name, bases, ns)" */ + +PyObject * +_PyType_New(PyTypeObject *metatype, PyObject *name, PyObject *bases, PyObject *ns) +{ + PyTypeObject *winner; + PyObject *type = NULL, *args = NULL; + + if (!PyType_IsSubtype(metatype, &PyType_Type)) { + PyErr_SetString(PyExc_TypeError, + "first argument must be a metaclass"); + return NULL; + } + + if (bases == NULL) { + bases = PyTuple_New(0); + if (bases == NULL) + return NULL; + } + else { + Py_INCREF(bases); + } + + if (ns == NULL) { + ns = PyDict_New(); + if (ns == NULL) + goto finish; + } + else { + Py_INCREF(ns); + } + + /* Determine the proper metatype to deal with this: */ + winner = _PyType_CalculateMetaclass(metatype, bases); + if (winner == NULL) + goto finish; + if (winner != metatype) { + if (winner->tp_new != type_new) { /* Pass it to the winner */ + args = PyTuple_Pack(3, name, bases, ns); + if (args == NULL) + goto finish; + type = winner->tp_new(winner, args, NULL); + Py_DECREF(args); + if (type == NULL) + goto finish; + } + metatype = winner; + } + if (type == NULL) + type = _type_new(metatype, name, bases, ns); + + /* call metatype.__init__(), but only if necessary */ + if (type != NULL) { + /* If the returned type is not an instance of metatype, + it won't be initialized. */ + if (!PyType_IsSubtype(Py_TYPE(type), metatype)) + goto finish; + + if (metatype->tp_init != NULL && metatype->tp_init != type_init) { + if (args == NULL) + args = PyTuple_Pack(3, name, bases, ns); + if (args == NULL || metatype->tp_init(type, args, NULL) < 0) { + Py_DECREF(type); + type = NULL; + } + Py_XDECREF(args); + goto finish; + } + } + +finish: + Py_DECREF(bases); + Py_DECREF(ns); + + return type; +} + + /* Cooperative 'super' */ typedef struct {