Skip to content

Commit 0827991

Browse files
committed
Issue 5982: Classmethod and staticmethod expose wrapped function with __func__.
1 parent 0687241 commit 0827991

3 files changed

Lines changed: 28 additions & 3 deletions

File tree

Lib/test/test_funcattrs.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,23 @@ def test_comparison(self):
254254
self.assert_(cell(-36) == cell(-36.0))
255255
self.assert_(cell(True) > empty_cell())
256256

257+
class StaticMethodAttrsTest(unittest.TestCase):
258+
def test_func_attribute(self):
259+
def f():
260+
pass
261+
262+
c = classmethod(f)
263+
self.assert_(c.__func__ is f)
264+
265+
s = staticmethod(f)
266+
self.assert_(s.__func__ is f)
267+
257268

258269
def test_main():
259270
support.run_unittest(FunctionPropertiesTest, ImplicitReferencesTest,
260271
ArbitraryFunctionAttrTest, FunctionDictsTest,
261-
FunctionDocstringTest, CellTest)
272+
FunctionDocstringTest, CellTest,
273+
StaticMethodAttrsTest)
262274

263275
if __name__ == "__main__":
264276
test_main()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Core and Builtins
1515
- Issue #6089: Fixed str.format with certain invalid field specifiers
1616
that would raise SystemError.
1717

18+
- Issue #5982: staticmethod and classmethod now expose the wrapped
19+
function with __func__.
20+
1821
- Added support for multiple context managers in the same with-statement.
1922
Deprecated contextlib.nested() which is no longer needed.
2023

Objects/funcobject.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,11 @@ cm_init(PyObject *self, PyObject *args, PyObject *kwds)
775775
return 0;
776776
}
777777

778+
static PyMemberDef cm_memberlist[] = {
779+
{"__func__", T_OBJECT, offsetof(classmethod, cm_callable), READONLY},
780+
{NULL} /* Sentinel */
781+
};
782+
778783
PyDoc_STRVAR(classmethod_doc,
779784
"classmethod(function) -> method\n\
780785
\n\
@@ -825,7 +830,7 @@ PyTypeObject PyClassMethod_Type = {
825830
0, /* tp_iter */
826831
0, /* tp_iternext */
827832
0, /* tp_methods */
828-
0, /* tp_members */
833+
cm_memberlist, /* tp_members */
829834
0, /* tp_getset */
830835
0, /* tp_base */
831836
0, /* tp_dict */
@@ -925,6 +930,11 @@ sm_init(PyObject *self, PyObject *args, PyObject *kwds)
925930
return 0;
926931
}
927932

933+
static PyMemberDef sm_memberlist[] = {
934+
{"__func__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY},
935+
{NULL} /* Sentinel */
936+
};
937+
928938
PyDoc_STRVAR(staticmethod_doc,
929939
"staticmethod(function) -> method\n\
930940
\n\
@@ -972,7 +982,7 @@ PyTypeObject PyStaticMethod_Type = {
972982
0, /* tp_iter */
973983
0, /* tp_iternext */
974984
0, /* tp_methods */
975-
0, /* tp_members */
985+
sm_memberlist, /* tp_members */
976986
0, /* tp_getset */
977987
0, /* tp_base */
978988
0, /* tp_dict */

0 commit comments

Comments
 (0)