mirror of https://github.com/python/cpython
gh-123909: PyType_From*: Disallow metaclasses with custom tp_new (GH-123947)
This commit is contained in:
parent
d7e83398c1
commit
432bf31327
|
@ -345,8 +345,12 @@ The following functions and structs are used to create
|
||||||
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
|
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
|
||||||
which may result in incomplete initialization.
|
which may result in incomplete initialization.
|
||||||
Creating classes whose metaclass overrides
|
Creating classes whose metaclass overrides
|
||||||
:c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
|
:c:member:`~PyTypeObject.tp_new` is deprecated.
|
||||||
will be no longer allowed.
|
|
||||||
|
.. versionchanged:: 3.14
|
||||||
|
|
||||||
|
Creating classes whose metaclass overrides
|
||||||
|
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
|
||||||
|
|
||||||
.. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
.. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
||||||
|
|
||||||
|
@ -362,8 +366,12 @@ The following functions and structs are used to create
|
||||||
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
|
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
|
||||||
which may result in incomplete initialization.
|
which may result in incomplete initialization.
|
||||||
Creating classes whose metaclass overrides
|
Creating classes whose metaclass overrides
|
||||||
:c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
|
:c:member:`~PyTypeObject.tp_new` is deprecated.
|
||||||
will be no longer allowed.
|
|
||||||
|
.. versionchanged:: 3.14
|
||||||
|
|
||||||
|
Creating classes whose metaclass overrides
|
||||||
|
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
|
||||||
|
|
||||||
.. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec)
|
.. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec)
|
||||||
|
|
||||||
|
@ -378,8 +386,12 @@ The following functions and structs are used to create
|
||||||
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
|
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
|
||||||
which may result in incomplete initialization.
|
which may result in incomplete initialization.
|
||||||
Creating classes whose metaclass overrides
|
Creating classes whose metaclass overrides
|
||||||
:c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
|
:c:member:`~PyTypeObject.tp_new` is deprecated.
|
||||||
will be no longer allowed.
|
|
||||||
|
.. versionchanged:: 3.14
|
||||||
|
|
||||||
|
Creating classes whose metaclass overrides
|
||||||
|
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
|
||||||
|
|
||||||
.. raw:: html
|
.. raw:: html
|
||||||
|
|
||||||
|
|
|
@ -722,22 +722,16 @@ class CAPITest(unittest.TestCase):
|
||||||
with self.assertRaisesRegex(TypeError, msg):
|
with self.assertRaisesRegex(TypeError, msg):
|
||||||
t = _testcapi.pytype_fromspec_meta(metaclass)
|
t = _testcapi.pytype_fromspec_meta(metaclass)
|
||||||
|
|
||||||
def test_heaptype_with_custom_metaclass_deprecation(self):
|
def test_heaptype_base_with_custom_metaclass(self):
|
||||||
metaclass = _testcapi.HeapCTypeMetaclassCustomNew
|
metaclass = _testcapi.HeapCTypeMetaclassCustomNew
|
||||||
|
|
||||||
# gh-103968: a metaclass with custom tp_new is deprecated, but still
|
|
||||||
# allowed for functions that existed in 3.11
|
|
||||||
# (PyType_FromSpecWithBases is used here).
|
|
||||||
class Base(metaclass=metaclass):
|
class Base(metaclass=metaclass):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Class creation from C
|
# Class creation from C
|
||||||
with warnings_helper.check_warnings(
|
msg = "Metaclasses with custom tp_new are not supported."
|
||||||
('.* _testcapi.Subclass .* custom tp_new.*in Python 3.14.*', DeprecationWarning),
|
with self.assertRaisesRegex(TypeError, msg):
|
||||||
):
|
|
||||||
sub = _testcapi.make_type_with_base(Base)
|
sub = _testcapi.make_type_with_base(Base)
|
||||||
self.assertTrue(issubclass(sub, Base))
|
|
||||||
self.assertIsInstance(sub, metaclass)
|
|
||||||
|
|
||||||
def test_multiple_inheritance_ctypes_with_weakref_or_dict(self):
|
def test_multiple_inheritance_ctypes_with_weakref_or_dict(self):
|
||||||
for weakref_cls in (_testcapi.HeapCTypeWithWeakref,
|
for weakref_cls in (_testcapi.HeapCTypeWithWeakref,
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
:c:func:`PyType_FromSpec`, :c:func:`PyType_FromSpecWithBases` and
|
||||||
|
:c:func:`PyType_FromModuleAndSpec` will now fail if the metaclass of the new
|
||||||
|
type has custom :c:member:`~PyTypeObject.tp_new`.
|
|
@ -4668,10 +4668,10 @@ special_offset_from_member(
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
PyObject *
|
||||||
_PyType_FromMetaclass_impl(
|
PyType_FromMetaclass(
|
||||||
PyTypeObject *metaclass, PyObject *module,
|
PyTypeObject *metaclass, PyObject *module,
|
||||||
PyType_Spec *spec, PyObject *bases_in, int _allow_tp_new)
|
PyType_Spec *spec, PyObject *bases_in)
|
||||||
{
|
{
|
||||||
/* Invariant: A non-NULL value in one of these means this function holds
|
/* Invariant: A non-NULL value in one of these means this function holds
|
||||||
* a strong reference or owns allocated memory.
|
* a strong reference or owns allocated memory.
|
||||||
|
@ -4848,22 +4848,11 @@ _PyType_FromMetaclass_impl(
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
if (metaclass->tp_new && metaclass->tp_new != PyType_Type.tp_new) {
|
if (metaclass->tp_new && metaclass->tp_new != PyType_Type.tp_new) {
|
||||||
if (_allow_tp_new) {
|
|
||||||
if (PyErr_WarnFormat(
|
|
||||||
PyExc_DeprecationWarning, 1,
|
|
||||||
"Type %s uses PyType_Spec with a metaclass that has custom "
|
|
||||||
"tp_new. This is deprecated and will no longer be allowed in "
|
|
||||||
"Python 3.14.", spec->name) < 0) {
|
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
PyExc_TypeError,
|
PyExc_TypeError,
|
||||||
"Metaclasses with custom tp_new are not supported.");
|
"Metaclasses with custom tp_new are not supported.");
|
||||||
goto finally;
|
goto finally;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate best base, and check that all bases are type objects */
|
/* Calculate best base, and check that all bases are type objects */
|
||||||
PyTypeObject *base = best_base(bases); // borrowed ref
|
PyTypeObject *base = best_base(bases); // borrowed ref
|
||||||
|
@ -5109,29 +5098,22 @@ _PyType_FromMetaclass_impl(
|
||||||
return (PyObject*)res;
|
return (PyObject*)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
|
||||||
PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module,
|
|
||||||
PyType_Spec *spec, PyObject *bases_in)
|
|
||||||
{
|
|
||||||
return _PyType_FromMetaclass_impl(metaclass, module, spec, bases_in, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
|
PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
|
||||||
{
|
{
|
||||||
return _PyType_FromMetaclass_impl(NULL, module, spec, bases, 1);
|
return PyType_FromMetaclass(NULL, module, spec, bases);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
|
||||||
{
|
{
|
||||||
return _PyType_FromMetaclass_impl(NULL, NULL, spec, bases, 1);
|
return PyType_FromMetaclass(NULL, NULL, spec, bases);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyType_FromSpec(PyType_Spec *spec)
|
PyType_FromSpec(PyType_Spec *spec)
|
||||||
{
|
{
|
||||||
return _PyType_FromMetaclass_impl(NULL, NULL, spec, NULL, 1);
|
return PyType_FromMetaclass(NULL, NULL, spec, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
|
Loading…
Reference in New Issue