https://github.com/python/cpython/commit/432bf31327c6b9647acb8bdb0eac2d392fd9f60a
commit: 432bf31327c6b9647acb8bdb0eac2d392fd9f60a
branch: main
author: Petr Viktorin <[email protected]>
committer: encukou <[email protected]>
date: 2024-09-13T13:18:49+02:00
summary:
gh-123909: PyType_From*: Disallow metaclasses with custom tp_new (GH-123947)
files:
A Misc/NEWS.d/next/C_API/2024-09-10-16-54-27.gh-issue-123909.CTGxDR.rst
M Doc/c-api/type.rst
M Lib/test/test_capi/test_misc.py
M Objects/typeobject.c
diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 0cae5c09505ebe..fa04d6c0ad5da5 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -345,8 +345,12 @@ The following functions and structs are used to create
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
which may result in incomplete initialization.
Creating classes whose metaclass overrides
- :c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
- will be no longer allowed.
+ :c:member:`~PyTypeObject.tp_new` is deprecated.
+
+ .. 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)
@@ -362,8 +366,12 @@ The following functions and structs are used to create
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
which may result in incomplete initialization.
Creating classes whose metaclass overrides
- :c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
- will be no longer allowed.
+ :c:member:`~PyTypeObject.tp_new` is deprecated.
+
+ .. 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)
@@ -378,8 +386,12 @@ The following functions and structs are used to create
The :c:member:`~PyTypeObject.tp_new` of the metaclass is *ignored*.
which may result in incomplete initialization.
Creating classes whose metaclass overrides
- :c:member:`~PyTypeObject.tp_new` is deprecated and in Python 3.14+ it
- will be no longer allowed.
+ :c:member:`~PyTypeObject.tp_new` is deprecated.
+
+ .. versionchanged:: 3.14
+
+ Creating classes whose metaclass overrides
+ :c:member:`~PyTypeObject.tp_new` is no longer allowed.
.. raw:: html
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index d50217b695967e..18392c4fce5dc1 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -722,22 +722,16 @@ def test_heaptype_with_custom_metaclass_custom_new(self):
with self.assertRaisesRegex(TypeError, msg):
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
- # 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):
pass
# Class creation from C
- with warnings_helper.check_warnings(
- ('.* _testcapi.Subclass .* custom tp_new.*in Python 3.14.*',
DeprecationWarning),
- ):
+ msg = "Metaclasses with custom tp_new are not supported."
+ with self.assertRaisesRegex(TypeError, msg):
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):
for weakref_cls in (_testcapi.HeapCTypeWithWeakref,
diff --git
a/Misc/NEWS.d/next/C_API/2024-09-10-16-54-27.gh-issue-123909.CTGxDR.rst
b/Misc/NEWS.d/next/C_API/2024-09-10-16-54-27.gh-issue-123909.CTGxDR.rst
new file mode 100644
index 00000000000000..b7a4913abbcb89
--- /dev/null
+++ b/Misc/NEWS.d/next/C_API/2024-09-10-16-54-27.gh-issue-123909.CTGxDR.rst
@@ -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`.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index a6483f74b7947d..28edd801284b81 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4668,10 +4668,10 @@ special_offset_from_member(
return -1;
}
-static PyObject *
-_PyType_FromMetaclass_impl(
+PyObject *
+PyType_FromMetaclass(
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
* a strong reference or owns allocated memory.
@@ -4848,21 +4848,10 @@ _PyType_FromMetaclass_impl(
goto finally;
}
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(
- PyExc_TypeError,
- "Metaclasses with custom tp_new are not supported.");
- goto finally;
- }
+ PyErr_SetString(
+ PyExc_TypeError,
+ "Metaclasses with custom tp_new are not supported.");
+ goto finally;
}
/* Calculate best base, and check that all bases are type objects */
@@ -5109,29 +5098,22 @@ _PyType_FromMetaclass_impl(
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 *
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 *
PyType_FromSpecWithBases(PyType_Spec *spec, PyObject *bases)
{
- return _PyType_FromMetaclass_impl(NULL, NULL, spec, bases, 1);
+ return PyType_FromMetaclass(NULL, NULL, spec, bases);
}
PyObject *
PyType_FromSpec(PyType_Spec *spec)
{
- return _PyType_FromMetaclass_impl(NULL, NULL, spec, NULL, 1);
+ return PyType_FromMetaclass(NULL, NULL, spec, NULL);
}
PyObject *
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]