https://github.com/python/cpython/commit/160810de89477836f2fde7139f7ab0670399efff
commit: 160810de89477836f2fde7139f7ab0670399efff
branch: 3.14
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-02-06T10:21:02+01:00
summary:

[3.14] gh-144330: Initialize classmethod and staticmethod in new (#144498)

gh-144330: Initialize classmethod and staticmethod in new

Initialize cm_callable and sm_callable to None in classmethod and
staticmethod constructor.

Co-authored-by: Aniket Singh Yadav <[email protected]>
Co-authored-by: Stan Ulbrych <[email protected]>

files:
M Lib/test/test_descr.py
M Objects/funcobject.c

diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index d420f097e74721..99f3f1ba999130 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -5138,6 +5138,26 @@ def foo(self):
         with self.assertRaisesRegex(NotImplementedError, "BAR"):
             B().foo
 
+    def test_staticmethod_new(self):
+        class MyStaticMethod(staticmethod):
+            def __init__(self, func):
+                pass
+        def func(): pass
+        sm = MyStaticMethod(func)
+        self.assertEqual(repr(sm), '<staticmethod(None)>')
+        self.assertIsNone(sm.__func__)
+        self.assertIsNone(sm.__wrapped__)
+
+    def test_classmethod_new(self):
+        class MyClassMethod(classmethod):
+            def __init__(self, func):
+                pass
+        def func(): pass
+        cm = MyClassMethod(func)
+        self.assertEqual(repr(cm), '<classmethod(None)>')
+        self.assertIsNone(cm.__func__)
+        self.assertIsNone(cm.__wrapped__)
+
 
 class DictProxyTests(unittest.TestCase):
     def setUp(self):
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 9532c21fc7082e..b870106479a607 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -1470,6 +1470,18 @@ cm_descr_get(PyObject *self, PyObject *obj, PyObject 
*type)
     return PyMethod_New(cm->cm_callable, type);
 }
 
+static PyObject *
+cm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    classmethod *cm = (classmethod *)PyType_GenericAlloc(type, 0);
+    if (cm == NULL) {
+        return NULL;
+    }
+    cm->cm_callable = Py_None;
+    cm->cm_dict = NULL;
+    return (PyObject *)cm;
+}
+
 static int
 cm_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
@@ -1616,7 +1628,7 @@ PyTypeObject PyClassMethod_Type = {
     offsetof(classmethod, cm_dict),             /* tp_dictoffset */
     cm_init,                                    /* tp_init */
     PyType_GenericAlloc,                        /* tp_alloc */
-    PyType_GenericNew,                          /* tp_new */
+    cm_new,                                     /* tp_new */
     PyObject_GC_Del,                            /* tp_free */
 };
 
@@ -1701,6 +1713,18 @@ sm_descr_get(PyObject *self, PyObject *obj, PyObject 
*type)
     return Py_NewRef(sm->sm_callable);
 }
 
+static PyObject *
+sm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+    staticmethod *sm = (staticmethod *)PyType_GenericAlloc(type, 0);
+    if (sm == NULL) {
+        return NULL;
+    }
+    sm->sm_callable = Py_None;
+    sm->sm_dict = NULL;
+    return (PyObject *)sm;
+}
+
 static int
 sm_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
@@ -1851,7 +1875,7 @@ PyTypeObject PyStaticMethod_Type = {
     offsetof(staticmethod, sm_dict),            /* tp_dictoffset */
     sm_init,                                    /* tp_init */
     PyType_GenericAlloc,                        /* tp_alloc */
-    PyType_GenericNew,                          /* tp_new */
+    sm_new,                                     /* tp_new */
     PyObject_GC_Del,                            /* tp_free */
 };
 

_______________________________________________
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]

Reply via email to