Skip to content

Commit 7b72250

Browse files
committed
Initialize staticmethod/classmethod callables in tp_new
1 parent 2c39b9d commit 7b72250

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-4
lines changed

Lib/test/test_descr.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,24 @@ def test_staticmethods_in_c(self):
18321832
self.assertEqual(a, a1)
18331833
self.assertEqual(d, d1)
18341834

1835+
def test_staticmethod_new(self):
1836+
sm = staticmethod.__new__(staticmethod, None)
1837+
self.assertEqual(repr(sm), '<staticmethod(None)>')
1838+
1839+
def test_classmethod_new(self):
1840+
cm = classmethod.__new__(classmethod, None)
1841+
self.assertIsInstance(repr(cm), str)
1842+
1843+
def test_staticmethod_func_readonly(self):
1844+
sm = staticmethod(lambda x: x)
1845+
with self.assertRaises(AttributeError):
1846+
sm.__func__ = None
1847+
1848+
def test_classmethod_func_readonly(self):
1849+
cm = classmethod(lambda x: x)
1850+
with self.assertRaises(AttributeError):
1851+
cm.__func__ = None
1852+
18351853
def test_classic(self):
18361854
# Testing classic classes...
18371855
class C:

Objects/funcobject.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,11 +1555,24 @@ static PyMethodDef cm_methodlist[] = {
15551555
{NULL} /* Sentinel */
15561556
};
15571557

1558+
static PyObject *
1559+
cm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1560+
{
1561+
classmethod *cm = (classmethod *)PyType_GenericAlloc(type, 0);
1562+
if (cm == NULL) {
1563+
return NULL;
1564+
}
1565+
cm->cm_callable = Py_None;
1566+
cm->cm_dict = NULL;
1567+
return (PyObject *)cm;
1568+
}
1569+
15581570
static PyObject*
15591571
cm_repr(PyObject *self)
15601572
{
15611573
classmethod *cm = _PyClassMethod_CAST(self);
1562-
return PyUnicode_FromFormat("<classmethod(%R)>", cm->cm_callable);
1574+
PyObject *callable = cm->cm_callable != NULL ? cm->cm_callable : Py_None;
1575+
return PyUnicode_FromFormat("<classmethod(%R)>", callable);
15631576
}
15641577

15651578
PyDoc_STRVAR(classmethod_doc,
@@ -1623,7 +1636,7 @@ PyTypeObject PyClassMethod_Type = {
16231636
offsetof(classmethod, cm_dict), /* tp_dictoffset */
16241637
cm_init, /* tp_init */
16251638
PyType_GenericAlloc, /* tp_alloc */
1626-
PyType_GenericNew, /* tp_new */
1639+
cm_new, /* tp_new */
16271640
PyObject_GC_Del, /* tp_free */
16281641
};
16291642

@@ -1639,6 +1652,7 @@ PyClassMethod_New(PyObject *callable)
16391652
}
16401653

16411654

1655+
16421656
/* Static method object */
16431657

16441658
/* A static method does not receive an implicit first argument.
@@ -1796,7 +1810,20 @@ static PyObject*
17961810
sm_repr(PyObject *self)
17971811
{
17981812
staticmethod *sm = _PyStaticMethod_CAST(self);
1799-
return PyUnicode_FromFormat("<staticmethod(%R)>", sm->sm_callable);
1813+
PyObject *callable = sm->sm_callable != NULL ? sm->sm_callable : Py_None;
1814+
return PyUnicode_FromFormat("<staticmethod(%R)>", callable);
1815+
}
1816+
1817+
static PyObject *
1818+
sm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1819+
{
1820+
staticmethod *sm = (staticmethod *)PyType_GenericAlloc(type, 0);
1821+
if (sm == NULL) {
1822+
return NULL;
1823+
}
1824+
sm->sm_callable = Py_None;
1825+
sm->sm_dict = NULL;
1826+
return (PyObject *)sm;
18001827
}
18011828

18021829
PyDoc_STRVAR(staticmethod_doc,
@@ -1858,7 +1885,7 @@ PyTypeObject PyStaticMethod_Type = {
18581885
offsetof(staticmethod, sm_dict), /* tp_dictoffset */
18591886
sm_init, /* tp_init */
18601887
PyType_GenericAlloc, /* tp_alloc */
1861-
PyType_GenericNew, /* tp_new */
1888+
sm_new, /* tp_new */
18621889
PyObject_GC_Del, /* tp_free */
18631890
};
18641891

0 commit comments

Comments
 (0)