From 05940a881404ed86c0b58758e9d6da46c0d7e4e7 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Fri, 20 May 2022 13:22:32 +0200 Subject: [PATCH 1/6] gh-60074: add new stable API function PyType_FromMetaclass 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. --- Doc/c-api/type.rst | 17 ++++- Doc/c-api/typeobj.rst | 2 +- Doc/data/stable_abi.dat | 1 + Doc/whatsnew/3.11.rst | 5 ++ Include/object.h | 1 + Lib/test/test_capi.py | 13 ++++ Lib/test/test_stable_abi_ctypes.py | 1 + ...2-05-20-13-32-24.gh-issue-93012.e9B-pv.rst | 8 ++ Misc/stable_abi.toml | 2 + Modules/_testcapimodule.c | 73 +++++++++++++++++++ Objects/typeobject.c | 15 +++- PC/python3dll.c | 1 + 12 files changed, 135 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-05-20-13-32-24.gh-issue-93012.e9B-pv.rst diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index d740e4eb0897e5..d02fddabe7f5e5 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -192,7 +192,7 @@ The following functions and structs are used to create .. c:function:: PyObject* PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) - Creates and returns a :ref:`heap type ` from the *spec* + Create and return a :ref:`heap type ` from the *spec* (:const:`Py_TPFLAGS_HEAPTYPE`). The *bases* argument can be used to specify base classes; it can either @@ -208,7 +208,9 @@ The following functions and structs are used to create The associated module is not inherited by subclasses; it must be specified for each class individually. - This function calls :c:func:`PyType_Ready` on the new type. + This function calls :c:func:`PyType_Ready` on the new type. Its behavior is + equivalent to ``PyType_FromMetaclass(&PyType_Type, NULL, spec, + bases)``. .. versionadded:: 3.9 @@ -217,6 +219,17 @@ The following functions and structs are used to create The function now accepts a single class as the *bases* argument and ``NULL`` as the ``tp_doc`` slot. +.. c:function:: PyObject* PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases) + + Create and return a :ref:`heap type ` from the *spec* + (:const:`Py_TPFLAGS_HEAPTYPE`). This function is a generalization of + :c:func:`PyType_FromModuleAndSpec`, with the main difference being that + the metaclass *metaclass* is used to construct the resulting type object. + + Metaclasses that override :c:member:`~PyTypeObject.tp_new` are not supported. + + .. versionadded:: 3.11 + .. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) Equivalent to ``PyType_FromModuleAndSpec(NULL, spec, bases)``. diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst index b3f371bb9c0623..df479046d4aeb7 100644 --- a/Doc/c-api/typeobj.rst +++ b/Doc/c-api/typeobj.rst @@ -2071,7 +2071,7 @@ flag set. This is done by filling a :c:type:`PyType_Spec` structure and calling :c:func:`PyType_FromSpec`, :c:func:`PyType_FromSpecWithBases`, -or :c:func:`PyType_FromModuleAndSpec`. +:c:func:`PyType_FromModuleAndSpec`, or :c:func:`PyType_FromMetaclass`. .. _number-structs: diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 3912a7c1242de0..c0ee7ce7cbbd89 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -653,6 +653,7 @@ function,PyTuple_Size,3.2,, var,PyTuple_Type,3.2,, type,PyTypeObject,3.2,,opaque function,PyType_ClearCache,3.2,, +function,PyType_FromMetaclass,3.11,, function,PyType_FromModuleAndSpec,3.10,, function,PyType_FromSpec,3.2,, function,PyType_FromSpecWithBases,3.3,, diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 1f88d2557aa3d0..bf3edd24d582cc 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1608,6 +1608,11 @@ New Features * Added the :c:member:`PyConfig.safe_path` member. (Contributed by Victor Stinner in :gh:`57684`.) +* Added the new limited C API function :c:func:`PyType_FromMetaclass`, + which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using + an additional metaclass argument. + (Contributed by Wenzel Jakob in :gh:`93012`.) + Porting to Python 3.11 ---------------------- diff --git a/Include/object.h b/Include/object.h index f01b9fa86d0148..d4c89ba404ef90 100644 --- a/Include/object.h +++ b/Include/object.h @@ -256,6 +256,7 @@ PyAPI_FUNC(void *) PyType_GetModuleState(PyTypeObject *); #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030B0000 PyAPI_FUNC(PyObject *) PyType_GetName(PyTypeObject *); PyAPI_FUNC(PyObject *) PyType_GetQualName(PyTypeObject *); +PyAPI_FUNC(PyObject *) PyType_FromMetaclass(PyTypeObject*, PyObject*, PyType_Spec*, PyObject*); #endif /* Generic type check */ diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 904ae9bc47ecfe..e28248363b5dc4 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -608,6 +608,19 @@ def test_heaptype_with_setattro(self): del obj.value self.assertEqual(obj.pvalue, 0) + def test_heaptype_with_custom_metaclass(self): + self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclass, type)) + self.assertTrue(issubclass(_testcapi.HeapCTypeMetaclassCustomNew, type)) + + t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclass) + self.assertIsInstance(t, type) + self.assertEqual(t.__name__, "HeapCTypeViaMetaclass") + self.assertIs(type(t), _testcapi.HeapCTypeMetaclass) + + msg = "Metaclasses with custom tp_new are not supported." + with self.assertRaisesRegex(TypeError, msg): + t = _testcapi.pytype_fromspec_meta(_testcapi.HeapCTypeMetaclassCustomNew) + def test_pynumber_tobase(self): from _testcapi import pynumber_tobase self.assertEqual(pynumber_tobase(123, 2), '0b1111011') diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 18c85061ca0893..53e93ab6b9b4c9 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -660,6 +660,7 @@ def test_windows_feature_macros(self): "PyTuple_Size", "PyTuple_Type", "PyType_ClearCache", + "PyType_FromMetaclass", "PyType_FromModuleAndSpec", "PyType_FromSpec", "PyType_FromSpecWithBases", diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-20-13-32-24.gh-issue-93012.e9B-pv.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-20-13-32-24.gh-issue-93012.e9B-pv.rst new file mode 100644 index 00000000000000..8de0f000647dc8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-20-13-32-24.gh-issue-93012.e9B-pv.rst @@ -0,0 +1,8 @@ +Added the new function :c:func:`PyType_FromMetaclass`, which generalizes the +existing :c:func:`PyType_FromModuleAndSpec` using an additional metaclass +argument. This is useful for language binding tools, where it can be used to +intercept type-related operations like subclassing or static attribute access +by specifying a metaclass with custom slots. + +Importantly, :c:func:`PyType_FromMetaclass` is available in the Limited API, +which provides a path towards migrating more binding tools onto the Stable ABI. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index d848f18d68ff64..387f4cd513027b 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2275,3 +2275,5 @@ added = '3.11' [function.PyErr_SetHandledException] added = '3.11' +[function.PyType_FromMetaclass] + added = '3.11' diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 3bc776140aabaa..37f4ded8001c6f 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -308,6 +308,32 @@ test_dict_inner(int count) } } +static PyObject *pytype_fromspec_meta(PyObject* self, PyObject *meta) +{ + if (!PyType_Check(meta)) { + PyErr_SetString( + TestError, + "pytype_fromspec_meta: must be invoked with a type argument!"); + return NULL; + } + + PyType_Slot HeapCTypeViaMetaclass_slots[] = { + {0}, + }; + + PyType_Spec HeapCTypeViaMetaclass_spec = { + "_testcapi.HeapCTypeViaMetaclass", + sizeof(PyObject), + 0, + Py_TPFLAGS_DEFAULT, + HeapCTypeViaMetaclass_slots + }; + + return PyType_FromMetaclass( + (PyTypeObject *) meta, NULL, &HeapCTypeViaMetaclass_spec, NULL); +} + + static PyObject* test_dict_iteration(PyObject* self, PyObject *Py_UNUSED(ignored)) { @@ -5886,6 +5912,7 @@ static PyMethodDef TestMethods[] = { {"test_long_numbits", test_long_numbits, METH_NOARGS}, {"test_k_code", test_k_code, METH_NOARGS}, {"test_empty_argparse", test_empty_argparse, METH_NOARGS}, + {"pytype_fromspec_meta", pytype_fromspec_meta, METH_O}, {"parse_tuple_and_keywords", parse_tuple_and_keywords, METH_VARARGS}, {"pyobject_repr_from_null", pyobject_repr_from_null, METH_NOARGS}, {"pyobject_str_from_null", pyobject_str_from_null, METH_NOARGS}, @@ -7078,6 +7105,38 @@ static PyType_Spec HeapCTypeSubclassWithFinalizer_spec = { HeapCTypeSubclassWithFinalizer_slots }; +static PyType_Slot HeapCTypeMetaclass_slots[] = { + {0}, +}; + +static PyType_Spec HeapCTypeMetaclass_spec = { + "_testcapi.HeapCTypeMetaclass", + sizeof(PyHeapTypeObject), + sizeof(PyMemberDef), + Py_TPFLAGS_DEFAULT, + HeapCTypeMetaclass_slots +}; + +static PyObject * +heap_ctype_metaclass_custom_tp_new(PyTypeObject *tp, PyObject *args, PyObject *kwargs) +{ + return PyType_Type.tp_new(tp, args, kwargs); +} + +static PyType_Slot HeapCTypeMetaclassCustomNew_slots[] = { + { Py_tp_new, heap_ctype_metaclass_custom_tp_new }, + {0}, +}; + +static PyType_Spec HeapCTypeMetaclassCustomNew_spec = { + "_testcapi.HeapCTypeMetaclassCustomNew", + sizeof(PyHeapTypeObject), + sizeof(PyMemberDef), + Py_TPFLAGS_DEFAULT, + HeapCTypeMetaclassCustomNew_slots +}; + + typedef struct { PyObject_HEAD PyObject *dict; @@ -7591,6 +7650,20 @@ PyInit__testcapi(void) Py_DECREF(subclass_with_finalizer_bases); PyModule_AddObject(m, "HeapCTypeSubclassWithFinalizer", HeapCTypeSubclassWithFinalizer); + PyObject *HeapCTypeMetaclass = PyType_FromMetaclass( + &PyType_Type, m, &HeapCTypeMetaclass_spec, (PyObject *) &PyType_Type); + if (HeapCTypeMetaclass == NULL) { + return NULL; + } + PyModule_AddObject(m, "HeapCTypeMetaclass", HeapCTypeMetaclass); + + PyObject *HeapCTypeMetaclassCustomNew = PyType_FromMetaclass( + &PyType_Type, m, &HeapCTypeMetaclassCustomNew_spec, (PyObject *) &PyType_Type); + if (HeapCTypeMetaclassCustomNew == NULL) { + return NULL; + } + PyModule_AddObject(m, "HeapCTypeMetaclassCustomNew", HeapCTypeMetaclassCustomNew); + if (PyType_Ready(&ContainerNoGC_type) < 0) { return NULL; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1daf2b8d3b0ff8..3faea3fb72c56f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3373,6 +3373,13 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) PyObject * PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) +{ + return PyType_FromMetaclass(&PyType_Type, module, spec, bases); +} + +PyObject * +PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, + PyType_Spec *spec, PyObject *bases) { PyHeapTypeObject *res; PyObject *modname; @@ -3384,6 +3391,12 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) char *res_start; short slot_offset, subslot_offset; + 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 +3425,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; diff --git a/PC/python3dll.c b/PC/python3dll.c index 50e7a9607bec95..024ec49d68d797 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -599,6 +599,7 @@ EXPORT_FUNC(PyTuple_Pack) EXPORT_FUNC(PyTuple_SetItem) EXPORT_FUNC(PyTuple_Size) EXPORT_FUNC(PyType_ClearCache) +EXPORT_FUNC(PyType_FromMetaclass) EXPORT_FUNC(PyType_FromModuleAndSpec) EXPORT_FUNC(PyType_FromSpec) EXPORT_FUNC(PyType_FromSpecWithBases) From 30e4e1bfd096697e63aaaeacdafbfd5a7d0254d3 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 24 May 2022 22:42:41 +0200 Subject: [PATCH 2/6] retarget to Python 3.12 --- Doc/c-api/type.rst | 2 +- Doc/data/stable_abi.dat | 2 +- Doc/whatsnew/3.11.rst | 5 ----- Doc/whatsnew/3.12.rst | 5 +++++ Misc/stable_abi.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index d02fddabe7f5e5..60a6fafb535411 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -228,7 +228,7 @@ The following functions and structs are used to create Metaclasses that override :c:member:`~PyTypeObject.tp_new` are not supported. - .. versionadded:: 3.11 + .. versionadded:: 3.12 .. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index c0ee7ce7cbbd89..82cd5796efd27d 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -653,7 +653,7 @@ function,PyTuple_Size,3.2,, var,PyTuple_Type,3.2,, type,PyTypeObject,3.2,,opaque function,PyType_ClearCache,3.2,, -function,PyType_FromMetaclass,3.11,, +function,PyType_FromMetaclass,3.12,, function,PyType_FromModuleAndSpec,3.10,, function,PyType_FromSpec,3.2,, function,PyType_FromSpecWithBases,3.3,, diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index bf3edd24d582cc..1f88d2557aa3d0 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -1608,11 +1608,6 @@ New Features * Added the :c:member:`PyConfig.safe_path` member. (Contributed by Victor Stinner in :gh:`57684`.) -* Added the new limited C API function :c:func:`PyType_FromMetaclass`, - which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using - an additional metaclass argument. - (Contributed by Wenzel Jakob in :gh:`93012`.) - Porting to Python 3.11 ---------------------- diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 033de1780b3d18..fd487848f09a34 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -151,6 +151,11 @@ C API Changes New Features ------------ +* Added the new limited C API function :c:func:`PyType_FromMetaclass`, + which generalizes the existing :c:func:`PyType_FromModuleAndSpec` using + an additional metaclass argument. + (Contributed by Wenzel Jakob in :gh:`93012`.) + Porting to Python 3.12 ---------------------- diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 387f4cd513027b..84bec827096050 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2276,4 +2276,4 @@ [function.PyErr_SetHandledException] added = '3.11' [function.PyType_FromMetaclass] - added = '3.11' + added = '3.12' From 0525d785f19e487cedac494a63c1f892f6a91450 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Wed, 25 May 2022 17:00:38 +0200 Subject: [PATCH 3/6] incorporated feedback --- Doc/c-api/type.rst | 31 +++++++++++++++---------------- Objects/typeobject.c | 5 ++++- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst index 60a6fafb535411..99b3845237d868 100644 --- a/Doc/c-api/type.rst +++ b/Doc/c-api/type.rst @@ -190,11 +190,16 @@ Creating Heap-Allocated Types The following functions and structs are used to create :ref:`heap types `. -.. c:function:: PyObject* PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) +.. c:function:: PyObject* PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases) Create and return a :ref:`heap type ` from the *spec* (:const:`Py_TPFLAGS_HEAPTYPE`). + The metaclass *metaclass* is used to construct the resulting type object. + When *metaclass* is ``NULL``, the default :c:type:`PyType_Type` is used + instead. Note that metaclasses that override + :c:member:`~PyTypeObject.tp_new` are not supported. + The *bases* argument can be used to specify base classes; it can either be only one class or a tuple of classes. If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead. @@ -208,9 +213,13 @@ The following functions and structs are used to create The associated module is not inherited by subclasses; it must be specified for each class individually. - This function calls :c:func:`PyType_Ready` on the new type. Its behavior is - equivalent to ``PyType_FromMetaclass(&PyType_Type, NULL, spec, - bases)``. + This function calls :c:func:`PyType_Ready` on the new type. + + .. versionadded:: 3.12 + +.. c:function:: PyObject* PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) + + Equivalent to ``PyType_FromMetaclass(NULL, module, spec, bases)``. .. versionadded:: 3.9 @@ -219,26 +228,16 @@ The following functions and structs are used to create The function now accepts a single class as the *bases* argument and ``NULL`` as the ``tp_doc`` slot. -.. c:function:: PyObject* PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases) - - Create and return a :ref:`heap type ` from the *spec* - (:const:`Py_TPFLAGS_HEAPTYPE`). This function is a generalization of - :c:func:`PyType_FromModuleAndSpec`, with the main difference being that - the metaclass *metaclass* is used to construct the resulting type object. - - Metaclasses that override :c:member:`~PyTypeObject.tp_new` are not supported. - - .. versionadded:: 3.12 .. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) - Equivalent to ``PyType_FromModuleAndSpec(NULL, spec, bases)``. + Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, bases)``. .. versionadded:: 3.3 .. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec) - Equivalent to ``PyType_FromSpecWithBases(spec, NULL)``. + Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, NULL)``. .. c:type:: PyType_Spec diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 3faea3fb72c56f..8f8ae1ba45968e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3374,7 +3374,7 @@ PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) PyObject * PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) { - return PyType_FromMetaclass(&PyType_Type, module, spec, bases); + return PyType_FromMetaclass(NULL, module, spec, bases); } PyObject * @@ -3391,6 +3391,9 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, 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."); From db620804e45b8f757b26cb58c20ed02573abeac3 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Wed, 25 May 2022 17:03:28 +0200 Subject: [PATCH 4/6] .. also remove unnecessary indirection from implementation --- Objects/typeobject.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8f8ae1ba45968e..a2181d205acae2 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3365,18 +3365,6 @@ static const PySlot_Offset pyslot_offsets[] = { #include "typeslots.inc" }; -PyObject * -PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases) -{ - return PyType_FromModuleAndSpec(NULL, spec, bases); -} - -PyObject * -PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) -{ - return PyType_FromMetaclass(NULL, module, spec, bases); -} - PyObject * PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, PyType_Spec *spec, PyObject *bases) @@ -3655,10 +3643,22 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, 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 * From b4a478cda8d7d0e543011e0c84336d0a7c58aca9 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Wed, 25 May 2022 20:15:43 +0200 Subject: [PATCH 5/6] fix Py_LIMITED_API check in object.h --- Include/object.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Include/object.h b/Include/object.h index d4c89ba404ef90..a3c6bd4fa984d5 100644 --- a/Include/object.h +++ b/Include/object.h @@ -256,6 +256,8 @@ PyAPI_FUNC(void *) PyType_GetModuleState(PyTypeObject *); #if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030B0000 PyAPI_FUNC(PyObject *) PyType_GetName(PyTypeObject *); PyAPI_FUNC(PyObject *) PyType_GetQualName(PyTypeObject *); +#endif +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030C0000 PyAPI_FUNC(PyObject *) PyType_FromMetaclass(PyTypeObject*, PyObject*, PyType_Spec*, PyObject*); #endif From 872249e70d7f5d274de22696e597a1133d869c71 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 26 May 2022 17:41:48 +0200 Subject: [PATCH 6/6] Style nitpick --- Objects/typeobject.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a2181d205acae2..ff5196c904eefb 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3379,8 +3379,9 @@ PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module, char *res_start; short slot_offset, subslot_offset; - if (!metaclass) + if (!metaclass) { metaclass = &PyType_Type; + } if (metaclass->tp_new != PyType_Type.tp_new) { PyErr_SetString(PyExc_TypeError, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy