Skip to content

Commit e97e3ec

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

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
@@ -1816,6 +1816,24 @@ def test_refleaks_in_staticmethod___init__(self):
18161816
sm.__init__(None)
18171817
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10)
18181818

1819+
def test_staticmethod_new_none_repr(self):
1820+
sm = staticmethod.__new__(staticmethod, None)
1821+
self.assertIsInstance(repr(sm), str)
1822+
1823+
def test_classmethod_new_none_repr(self):
1824+
cm = classmethod.__new__(classmethod, None)
1825+
self.assertIsInstance(repr(cm), str)
1826+
1827+
def test_staticmethod_func_readonly(self):
1828+
sm = staticmethod(lambda x: x)
1829+
with self.assertRaises(AttributeError):
1830+
sm.__func__ = None
1831+
1832+
def test_classmethod_func_readonly(self):
1833+
cm = classmethod(lambda x: x)
1834+
with self.assertRaises(AttributeError):
1835+
cm.__func__ = None
1836+
18191837
@support.impl_detail("the module 'xxsubtype' is internal")
18201838
@unittest.skipIf(xxsubtype is None, "requires xxsubtype module")
18211839
def test_staticmethods_in_c(self):

Objects/funcobject.c

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

1558+
static PyObject *cm_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
1559+
static PyObject *sm_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
1560+
15581561
static PyObject*
15591562
cm_repr(PyObject *self)
15601563
{
15611564
classmethod *cm = _PyClassMethod_CAST(self);
1562-
return PyUnicode_FromFormat("<classmethod(%R)>", cm->cm_callable);
1565+
PyObject *callable = cm->cm_callable != NULL ? cm->cm_callable : Py_None;
1566+
return PyUnicode_FromFormat("<classmethod(%R)>", callable);
15631567
}
15641568

15651569
PyDoc_STRVAR(classmethod_doc,
@@ -1623,7 +1627,7 @@ PyTypeObject PyClassMethod_Type = {
16231627
offsetof(classmethod, cm_dict), /* tp_dictoffset */
16241628
cm_init, /* tp_init */
16251629
PyType_GenericAlloc, /* tp_alloc */
1626-
PyType_GenericNew, /* tp_new */
1630+
cm_new, /* tp_new */
16271631
PyObject_GC_Del, /* tp_free */
16281632
};
16291633

@@ -1638,6 +1642,17 @@ PyClassMethod_New(PyObject *callable)
16381642
return (PyObject *)cm;
16391643
}
16401644

1645+
static PyObject *
1646+
cm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1647+
{
1648+
classmethod *cm = (classmethod *)PyType_GenericAlloc(type, 0);
1649+
if (cm == NULL)
1650+
return NULL;
1651+
cm->cm_callable = Py_NewRef(Py_None);
1652+
cm->cm_dict = NULL;
1653+
return (PyObject *)cm;
1654+
}
1655+
16411656

16421657
/* Static method object */
16431658

@@ -1796,7 +1811,8 @@ static PyObject*
17961811
sm_repr(PyObject *self)
17971812
{
17981813
staticmethod *sm = _PyStaticMethod_CAST(self);
1799-
return PyUnicode_FromFormat("<staticmethod(%R)>", sm->sm_callable);
1814+
PyObject *callable = sm->sm_callable != NULL ? sm->sm_callable : Py_None;
1815+
return PyUnicode_FromFormat("<staticmethod(%R)>", callable);
18001816
}
18011817

18021818
PyDoc_STRVAR(staticmethod_doc,
@@ -1858,7 +1874,7 @@ PyTypeObject PyStaticMethod_Type = {
18581874
offsetof(staticmethod, sm_dict), /* tp_dictoffset */
18591875
sm_init, /* tp_init */
18601876
PyType_GenericAlloc, /* tp_alloc */
1861-
PyType_GenericNew, /* tp_new */
1877+
sm_new, /* tp_new */
18621878
PyObject_GC_Del, /* tp_free */
18631879
};
18641880

@@ -1872,3 +1888,14 @@ PyStaticMethod_New(PyObject *callable)
18721888
}
18731889
return (PyObject *)sm;
18741890
}
1891+
1892+
static PyObject *
1893+
sm_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1894+
{
1895+
staticmethod *sm = (staticmethod *)PyType_GenericAlloc(type, 0);
1896+
if (sm == NULL)
1897+
return NULL;
1898+
sm->sm_callable = Py_NewRef(Py_None);
1899+
sm->sm_dict = NULL;
1900+
return (PyObject *)sm;
1901+
}

0 commit comments

Comments
 (0)