Issue #15146: Add PyType_FromSpecWithBases. Patch by Robin Schreiber.
This commit is contained in:
parent
110ee34e41
commit
9c56409d33
|
@ -85,3 +85,15 @@ Type Objects
|
||||||
their initialization. This function is responsible for adding inherited slots
|
their initialization. This function is responsible for adding inherited slots
|
||||||
from a type's base class. Return ``0`` on success, or return ``-1`` and sets an
|
from a type's base class. Return ``0`` on success, or return ``-1`` and sets an
|
||||||
exception on error.
|
exception on error.
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec)
|
||||||
|
|
||||||
|
Creates and returns a heap type object from the *spec* passed to the function.
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
||||||
|
|
||||||
|
Creates and returns a heap type object from the *spec*. In addition to that,
|
||||||
|
the created heap type contains all types contained by the *bases* tuple as base
|
||||||
|
types. This allows the caller to reference other heap types as base types.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
|
@ -433,6 +433,9 @@ typedef struct{
|
||||||
} PyType_Spec;
|
} PyType_Spec;
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*);
|
PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*);
|
||||||
|
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000
|
||||||
|
PyAPI_FUNC(PyObject*) PyType_FromSpecWithBases(PyType_Spec*, PyObject*);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef Py_LIMITED_API
|
#ifndef Py_LIMITED_API
|
||||||
/* The *real* layout of a type object when allocated on the heap */
|
/* The *real* layout of a type object when allocated on the heap */
|
||||||
|
|
|
@ -10,6 +10,8 @@ What's New in Python 3.3.0 Beta 1?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #15146: Add PyType_FromSpecWithBases. Patch by Robin Schreiber.
|
||||||
|
|
||||||
- Issue #15142: Fix reference leak when deallocating instances of types
|
- Issue #15142: Fix reference leak when deallocating instances of types
|
||||||
created using PyType_FromSpec().
|
created using PyType_FromSpec().
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,9 @@ _Py_IDENTIFIER(__new__);
|
||||||
static PyObject *
|
static PyObject *
|
||||||
_PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name);
|
_PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name);
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
PyType_ClearCache(void)
|
PyType_ClearCache(void)
|
||||||
{
|
{
|
||||||
|
@ -2375,22 +2378,75 @@ static short slotoffsets[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyType_FromSpec(PyType_Spec *spec)
|
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
||||||
{
|
{
|
||||||
PyHeapTypeObject *res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
|
PyHeapTypeObject *res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
|
||||||
|
PyTypeObject *type, *base;
|
||||||
|
char *s;
|
||||||
char *res_start = (char*)res;
|
char *res_start = (char*)res;
|
||||||
PyType_Slot *slot;
|
PyType_Slot *slot;
|
||||||
|
|
||||||
|
/* Set the type name and qualname */
|
||||||
|
s = strrchr(spec->name, '.');
|
||||||
|
if (s == NULL)
|
||||||
|
s = (char*)spec->name;
|
||||||
|
else
|
||||||
|
s++;
|
||||||
|
|
||||||
if (res == NULL)
|
if (res == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
res->ht_name = PyUnicode_FromString(spec->name);
|
res->ht_name = PyUnicode_FromString(s);
|
||||||
if (!res->ht_name)
|
if (!res->ht_name)
|
||||||
goto fail;
|
goto fail;
|
||||||
res->ht_qualname = res->ht_name;
|
res->ht_qualname = res->ht_name;
|
||||||
Py_INCREF(res->ht_qualname);
|
Py_INCREF(res->ht_qualname);
|
||||||
res->ht_type.tp_name = _PyUnicode_AsString(res->ht_name);
|
res->ht_type.tp_name = spec->name;
|
||||||
if (!res->ht_type.tp_name)
|
if (!res->ht_type.tp_name)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
/* Adjust for empty tuple bases */
|
||||||
|
if (!bases) {
|
||||||
|
base = &PyBaseObject_Type;
|
||||||
|
/* See whether Py_tp_base(s) was specified */
|
||||||
|
for (slot = spec->slots; slot->slot; slot++) {
|
||||||
|
if (slot->slot == Py_tp_base)
|
||||||
|
base = slot->pfunc;
|
||||||
|
else if (slot->slot == Py_tp_bases) {
|
||||||
|
bases = slot->pfunc;
|
||||||
|
Py_INCREF(bases);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!bases)
|
||||||
|
bases = PyTuple_Pack(1, base);
|
||||||
|
if (!bases)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Py_INCREF(bases);
|
||||||
|
|
||||||
|
/* Calculate best base, and check that all bases are type objects */
|
||||||
|
base = best_base(bases);
|
||||||
|
if (base == NULL) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"type '%.100s' is not an acceptable base type",
|
||||||
|
base->tp_name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = (PyTypeObject *)res;
|
||||||
|
/* Initialize essential fields */
|
||||||
|
type->tp_as_number = &res->as_number;
|
||||||
|
type->tp_as_sequence = &res->as_sequence;
|
||||||
|
type->tp_as_mapping = &res->as_mapping;
|
||||||
|
type->tp_as_buffer = &res->as_buffer;
|
||||||
|
/* Set tp_base and tp_bases */
|
||||||
|
type->tp_bases = bases;
|
||||||
|
bases = NULL;
|
||||||
|
Py_INCREF(base);
|
||||||
|
type->tp_base = base;
|
||||||
|
|
||||||
res->ht_type.tp_basicsize = spec->basicsize;
|
res->ht_type.tp_basicsize = spec->basicsize;
|
||||||
res->ht_type.tp_itemsize = spec->itemsize;
|
res->ht_type.tp_itemsize = spec->itemsize;
|
||||||
|
@ -2401,6 +2457,9 @@ PyType_FromSpec(PyType_Spec *spec)
|
||||||
PyErr_SetString(PyExc_RuntimeError, "invalid slot offset");
|
PyErr_SetString(PyExc_RuntimeError, "invalid slot offset");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if (slot->slot == Py_tp_base || slot->slot == Py_tp_bases)
|
||||||
|
/* Processed above */
|
||||||
|
continue;
|
||||||
*(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc;
|
*(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc;
|
||||||
|
|
||||||
/* need to make a copy of the docstring slot, which usually
|
/* need to make a copy of the docstring slot, which usually
|
||||||
|
@ -2427,6 +2486,13 @@ PyType_FromSpec(PyType_Spec *spec)
|
||||||
if (PyType_Ready(&res->ht_type) < 0)
|
if (PyType_Ready(&res->ht_type) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
/* Set type.__module__ */
|
||||||
|
s = strrchr(spec->name, '.');
|
||||||
|
if (s != NULL)
|
||||||
|
_PyDict_SetItemId(type->tp_dict, &PyId___module__,
|
||||||
|
PyUnicode_FromStringAndSize(
|
||||||
|
spec->name, (Py_ssize_t)(s - spec->name)));
|
||||||
|
|
||||||
return (PyObject*)res;
|
return (PyObject*)res;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
@ -2434,6 +2500,12 @@ PyType_FromSpec(PyType_Spec *spec)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyType_FromSpec(PyType_Spec *spec)
|
||||||
|
{
|
||||||
|
return PyType_FromSpecWithBases(spec, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Internal API to look for a name through the MRO.
|
/* Internal API to look for a name through the MRO.
|
||||||
This returns a borrowed reference, and doesn't set an exception! */
|
This returns a borrowed reference, and doesn't set an exception! */
|
||||||
|
@ -4763,7 +4835,7 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
object.__new__(dict). To do this, we check that the
|
object.__new__(dict). To do this, we check that the
|
||||||
most derived base that's not a heap type is this type. */
|
most derived base that's not a heap type is this type. */
|
||||||
staticbase = subtype;
|
staticbase = subtype;
|
||||||
while (staticbase && (staticbase->tp_flags & Py_TPFLAGS_HEAPTYPE))
|
while (staticbase && (staticbase->tp_new == slot_tp_new))
|
||||||
staticbase = staticbase->tp_base;
|
staticbase = staticbase->tp_base;
|
||||||
/* If staticbase is NULL now, it is a really weird type.
|
/* If staticbase is NULL now, it is a really weird type.
|
||||||
In the spirit of backwards compatibility (?), just shut up. */
|
In the spirit of backwards compatibility (?), just shut up. */
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
; When changing this file, run python33gen.py
|
||||||
LIBRARY "python3"
|
LIBRARY "python3"
|
||||||
EXPORTS
|
EXPORTS
|
||||||
PyArg_Parse=python33.PyArg_Parse
|
PyArg_Parse=python33.PyArg_Parse
|
||||||
|
@ -513,6 +514,7 @@ EXPORTS
|
||||||
PyTuple_Type=python33.PyTuple_Type DATA
|
PyTuple_Type=python33.PyTuple_Type DATA
|
||||||
PyType_ClearCache=python33.PyType_ClearCache
|
PyType_ClearCache=python33.PyType_ClearCache
|
||||||
PyType_FromSpec=python33.PyType_FromSpec
|
PyType_FromSpec=python33.PyType_FromSpec
|
||||||
|
PyType_FromSpecWithBases=python33.PyType_FromSpecWithBases
|
||||||
PyType_GenericAlloc=python33.PyType_GenericAlloc
|
PyType_GenericAlloc=python33.PyType_GenericAlloc
|
||||||
PyType_GenericNew=python33.PyType_GenericNew
|
PyType_GenericNew=python33.PyType_GenericNew
|
||||||
PyType_GetFlags=python33.PyType_GetFlags
|
PyType_GetFlags=python33.PyType_GetFlags
|
||||||
|
|
|
@ -513,6 +513,7 @@ PyTuple_Size
|
||||||
PyTuple_Type
|
PyTuple_Type
|
||||||
PyType_ClearCache
|
PyType_ClearCache
|
||||||
PyType_FromSpec
|
PyType_FromSpec
|
||||||
|
PyType_FromSpecWithBases
|
||||||
PyType_GenericAlloc
|
PyType_GenericAlloc
|
||||||
PyType_GenericNew
|
PyType_GenericNew
|
||||||
PyType_GetFlags
|
PyType_GetFlags
|
||||||
|
|
Loading…
Reference in New Issue