]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-144330: Initialize classmethod and staticmethod in new (#144498)
authorVictor Stinner <vstinner@python.org>
Fri, 6 Feb 2026 09:21:02 +0000 (10:21 +0100)
committerGitHub <noreply@github.com>
Fri, 6 Feb 2026 09:21:02 +0000 (10:21 +0100)
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 <singhyadavaniket43@gmail.com>
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
Lib/test/test_descr.py
Objects/funcobject.c

index d420f097e74721513de0a805214ab9846f76c3d9..99f3f1ba9991303074ded5ee884cc9359f7a33c4 100644 (file)
@@ -5138,6 +5138,26 @@ class ClassPropertiesAndMethods(unittest.TestCase):
         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):
index 9532c21fc7082e857d472ecefffb730ceec40330..b870106479a607319d8016208a66701f712b35dc 100644 (file)
@@ -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 */
 };