gh-60074: add new stable API function PyType_FromMetaclass (GH-93012)

Added a new stable API function ``PyType_FromMetaclass``, which mirrors
the behavior of ``PyType_FromModuleAndSpec`` except that it takes an
additional metaclass argument. This is, e.g., useful for language
binding tools that need to store additional information in the type
object.
This commit is contained in:
Wenzel Jakob 2022-05-27 10:27:39 +02:00 committed by GitHub
parent 20d30ba2cc
commit 5e34b494a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 150 additions and 14 deletions

View file

@ -3366,13 +3366,8 @@ static const PySlot_Offset pyslot_offsets[] = {
};
PyObject *
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
{
return PyType_FromModuleAndSpec(NULL, spec, bases);
}
PyObject *
PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module,
PyType_Spec *spec, PyObject *bases)
{
PyHeapTypeObject *res;
PyObject *modname;
@ -3384,6 +3379,16 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
char *res_start;
short slot_offset, subslot_offset;
if (!metaclass) {
metaclass = &PyType_Type;
}
if (metaclass->tp_new != PyType_Type.tp_new) {
PyErr_SetString(PyExc_TypeError,
"Metaclasses with custom tp_new are not supported.");
return NULL;
}
nmembers = weaklistoffset = dictoffset = vectorcalloffset = 0;
for (slot = spec->slots; slot->slot; slot++) {
if (slot->slot == Py_tp_members) {
@ -3412,7 +3417,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
}
}
res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, nmembers);
res = (PyHeapTypeObject*)metaclass->tp_alloc(metaclass, nmembers);
if (res == NULL)
return NULL;
res_start = (char*)res;
@ -3639,10 +3644,22 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
return NULL;
}
PyObject *
PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
{
return PyType_FromMetaclass(NULL, module, spec, bases);
}
PyObject *
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
{
return PyType_FromMetaclass(NULL, NULL, spec, bases);
}
PyObject *
PyType_FromSpec(PyType_Spec *spec)
{
return PyType_FromSpecWithBases(spec, NULL);
return PyType_FromMetaclass(NULL, NULL, spec, NULL);
}
PyObject *