From 7b7225016d9e52141f6149971fb530a67c070e15 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Tue, 3 Feb 2026 23:12:52 +0530 Subject: [PATCH 1/3] Initialize staticmethod/classmethod callables in tp_new --- Lib/test/test_descr.py | 18 ++++++++++++++++++ Objects/funcobject.c | 35 +++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 82a48ad4d1aced..92d17cb6f51592 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1832,6 +1832,24 @@ def test_staticmethods_in_c(self): self.assertEqual(a, a1) self.assertEqual(d, d1) + def test_staticmethod_new(self): + sm = staticmethod.__new__(staticmethod, None) + self.assertEqual(repr(sm), '') + + def test_classmethod_new(self): + cm = classmethod.__new__(classmethod, None) + self.assertIsInstance(repr(cm), str) + + def test_staticmethod_func_readonly(self): + sm = staticmethod(lambda x: x) + with self.assertRaises(AttributeError): + sm.__func__ = None + + def test_classmethod_func_readonly(self): + cm = classmethod(lambda x: x) + with self.assertRaises(AttributeError): + cm.__func__ = None + def test_classic(self): # Testing classic classes... class C: diff --git a/Objects/funcobject.c b/Objects/funcobject.c index b659ac8023373b..203497964d32a2 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -1555,11 +1555,24 @@ static PyMethodDef cm_methodlist[] = { {NULL} /* Sentinel */ }; +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 PyObject* cm_repr(PyObject *self) { classmethod *cm = _PyClassMethod_CAST(self); - return PyUnicode_FromFormat("", cm->cm_callable); + PyObject *callable = cm->cm_callable != NULL ? cm->cm_callable : Py_None; + return PyUnicode_FromFormat("", callable); } PyDoc_STRVAR(classmethod_doc, @@ -1623,7 +1636,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 */ }; @@ -1639,6 +1652,7 @@ PyClassMethod_New(PyObject *callable) } + /* Static method object */ /* A static method does not receive an implicit first argument. @@ -1796,7 +1810,20 @@ static PyObject* sm_repr(PyObject *self) { staticmethod *sm = _PyStaticMethod_CAST(self); - return PyUnicode_FromFormat("", sm->sm_callable); + PyObject *callable = sm->sm_callable != NULL ? sm->sm_callable : Py_None; + return PyUnicode_FromFormat("", 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; } PyDoc_STRVAR(staticmethod_doc, @@ -1858,7 +1885,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 */ }; From 80f9c476ed685a3687719a124f209fdc2226d2a1 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Tue, 3 Feb 2026 23:24:21 +0530 Subject: [PATCH 2/3] Initialize staticmethod/classmethod callables in tp_new --- Objects/funcobject.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 203497964d32a2..c8acd109189c41 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -1652,7 +1652,6 @@ PyClassMethod_New(PyObject *callable) } - /* Static method object */ /* A static method does not receive an implicit first argument. From ee324feb31229fd10788baed92d01aa29cf64075 Mon Sep 17 00:00:00 2001 From: Aniket Singh Yadav Date: Tue, 3 Feb 2026 23:30:14 +0530 Subject: [PATCH 3/3] Initialize staticmethod/classmethod callables in tp_new --- Lib/test/test_descr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 92d17cb6f51592..3591d3c1e1d7fa 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1838,7 +1838,7 @@ def test_staticmethod_new(self): def test_classmethod_new(self): cm = classmethod.__new__(classmethod, None) - self.assertIsInstance(repr(cm), str) + self.assertEqual(repr(cm), '') def test_staticmethod_func_readonly(self): sm = staticmethod(lambda x: x)