Skip to content

Commit a8c4375

Browse files
committed
pythongh-123909: PyType_From*: Disallow metaclasses with custom tp_new
1 parent fb1b51a commit a8c4375

File tree

4 files changed

+30
-49
lines changed

4 files changed

+30
-49
lines changed

Doc/c-api/type.rst

+14-12
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,12 @@ The following functions and structs are used to create
345345
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
346346
which may result in incomplete initialization.
347347
Creating classes whose metaclass overrides
348-
:c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
349-
will be no longer allowed.
348+
:c:member:`~PyTypeObject.tp_new` is deprecated.
349+
350+
.. versionchanged:: 3.14
351+
352+
Creating classes whose metaclass overrides
353+
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
350354
351355
.. c:function:: PyObject* PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
352356
@@ -362,24 +366,22 @@ The following functions and structs are used to create
362366
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
363367
which may result in incomplete initialization.
364368
Creating classes whose metaclass overrides
365-
:c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
366-
will be no longer allowed.
369+
:c:member:`~PyTypeObject.tp_new` is deprecated.
370+
371+
.. versionchanged:: 3.14
372+
373+
Creating classes whose metaclass overrides
374+
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
367375
368376
.. c:function:: PyObject* PyType_FromSpec(PyType_Spec *spec)
369377
370378
Equivalent to ``PyType_FromMetaclass(NULL, NULL, spec, NULL)``.
371379
372380
.. versionchanged:: 3.12
381+
.. versionchanged:: 3.14
373382
374-
The function now finds and uses a metaclass corresponding to the
375-
base classes provided in *Py_tp_base[s]* slots.
376-
Previously, only :class:`type` instances were returned.
377-
378-
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
379-
which may result in incomplete initialization.
380383
Creating classes whose metaclass overrides
381-
:c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
382-
will be no longer allowed.
384+
:c:member:`~PyTypeObject.tp_new` is no longer allowed.
383385
384386
.. raw:: html
385387

Lib/test/test_capi/test_misc.py

+3-9
Original file line numberDiff line numberDiff line change
@@ -722,22 +722,16 @@ def test_heaptype_with_custom_metaclass_custom_new(self):
722722
with self.assertRaisesRegex(TypeError, msg):
723723
t = _testcapi.pytype_fromspec_meta(metaclass)
724724

725-
def test_heaptype_with_custom_metaclass_deprecation(self):
725+
def test_heaptype_base_with_custom_metaclass(self):
726726
metaclass = _testcapi.HeapCTypeMetaclassCustomNew
727727

728-
# gh-103968: a metaclass with custom tp_new is deprecated, but still
729-
# allowed for functions that existed in 3.11
730-
# (PyType_FromSpecWithBases is used here).
731728
class Base(metaclass=metaclass):
732729
pass
733730

734731
# Class creation from C
735-
with warnings_helper.check_warnings(
736-
('.* _testcapi.Subclass .* custom tp_new.*in Python 3.14.*', DeprecationWarning),
737-
):
732+
msg = "Metaclasses with custom tp_new are not supported."
733+
with self.assertRaisesRegex(TypeError, msg):
738734
sub = _testcapi.make_type_with_base(Base)
739-
self.assertTrue(issubclass(sub, Base))
740-
self.assertIsInstance(sub, metaclass)
741735

742736
def test_multiple_inheritance_ctypes_with_weakref_or_dict(self):
743737
for weakref_cls in (_testcapi.HeapCTypeWithWeakref,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:c:func:`PyType_FromSpec`, :c:func:`PyType_FromSpecWithBases` and
2+
:c:func:`PyType_FromModuleAndSpec` will now fail if the metaclass of the new
3+
type has custom :c:member:`~PyTypeObject.tp_new`.

Objects/typeobject.c

+10-28
Original file line numberDiff line numberDiff line change
@@ -4668,10 +4668,10 @@ special_offset_from_member(
46684668
return -1;
46694669
}
46704670

4671-
static PyObject *
4672-
_PyType_FromMetaclass_impl(
4671+
PyObject *
4672+
PyType_FromMetaclass(
46734673
PyTypeObject *metaclass, PyObject *module,
4674-
PyType_Spec *spec, PyObject *bases_in, int _allow_tp_new)
4674+
PyType_Spec *spec, PyObject *bases_in)
46754675
{
46764676
/* Invariant: A non-NULL value in one of these means this function holds
46774677
* a strong reference or owns allocated memory.
@@ -4848,21 +4848,10 @@ _PyType_FromMetaclass_impl(
48484848
goto finally;
48494849
}
48504850
if (metaclass->tp_new && metaclass->tp_new != PyType_Type.tp_new) {
4851-
if (_allow_tp_new) {
4852-
if (PyErr_WarnFormat(
4853-
PyExc_DeprecationWarning, 1,
4854-
"Type %s uses PyType_Spec with a metaclass that has custom "
4855-
"tp_new. This is deprecated and will no longer be allowed in "
4856-
"Python 3.14.", spec->name) < 0) {
4857-
goto finally;
4858-
}
4859-
}
4860-
else {
4861-
PyErr_SetString(
4862-
PyExc_TypeError,
4863-
"Metaclasses with custom tp_new are not supported.");
4864-
goto finally;
4865-
}
4851+
PyErr_SetString(
4852+
PyExc_TypeError,
4853+
"Metaclasses with custom tp_new are not supported.");
4854+
goto finally;
48664855
}
48674856

48684857
/* Calculate best base, and check that all bases are type objects */
@@ -5109,29 +5098,22 @@ _PyType_FromMetaclass_impl(
51095098
return (PyObject*)res;
51105099
}
51115100

5112-
PyObject *
5113-
PyType_FromMetaclass(PyTypeObject *metaclass, PyObject *module,
5114-
PyType_Spec *spec, PyObject *bases_in)
5115-
{
5116-
return _PyType_FromMetaclass_impl(metaclass, module, spec, bases_in, 0);
5117-
}
5118-
51195101
PyObject *
51205102
PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases)
51215103
{
5122-
return _PyType_FromMetaclass_impl(NULL, module, spec, bases, 1);
5104+
return PyType_FromMetaclass(NULL, module, spec, bases);
51235105
}
51245106

51255107
PyObject *
51265108
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
51275109
{
5128-
return _PyType_FromMetaclass_impl(NULL, NULL, spec, bases, 1);
5110+
return PyType_FromMetaclass(NULL, NULL, spec, bases);
51295111
}
51305112

51315113
PyObject *
51325114
PyType_FromSpec(PyType_Spec *spec)
51335115
{
5134-
return _PyType_FromMetaclass_impl(NULL, NULL, spec, NULL, 1);
5116+
return PyType_FromMetaclass(NULL, NULL, spec, NULL);
51355117
}
51365118

51375119
PyObject *

0 commit comments

Comments
 (0)