@@ -639,7 +639,7 @@ static PyObject*
639639func_repr (PyFunctionObject * op )
640640{
641641 return PyUnicode_FromFormat ("<function %U at %p>" ,
642- op -> func_qualname , op );
642+ op -> func_qualname , op );
643643}
644644
645645static int
@@ -715,6 +715,50 @@ PyTypeObject PyFunction_Type = {
715715};
716716
717717
718+ static int
719+ functools_copy_attr (PyObject * wrapper , PyObject * wrapped , PyObject * name )
720+ {
721+ PyObject * value = PyObject_GetAttr (wrapped , name );
722+ if (value == NULL ) {
723+ if (PyErr_ExceptionMatches (PyExc_AttributeError )) {
724+ PyErr_Clear ();
725+ return 0 ;
726+ }
727+ return -1 ;
728+ }
729+
730+ int res = PyObject_SetAttr (wrapper , name , value );
731+ Py_DECREF (value );
732+ return res ;
733+ }
734+
735+ // Similar to functools.wraps(wrapper, wrapped)
736+ static int
737+ functools_wraps (PyObject * wrapper , PyObject * wrapped )
738+ {
739+ #define COPY_ATTR (ATTR ) \
740+ do { \
741+ _Py_IDENTIFIER(ATTR); \
742+ PyObject *attr = _PyUnicode_FromId(&PyId_ ## ATTR); \
743+ if (attr == NULL) { \
744+ return -1; \
745+ } \
746+ if (functools_copy_attr(wrapper, wrapped, attr) < 0) { \
747+ return -1; \
748+ } \
749+ } while (0) \
750+
751+ COPY_ATTR (__module__ );
752+ COPY_ATTR (__name__ );
753+ COPY_ATTR (__qualname__ );
754+ COPY_ATTR (__doc__ );
755+ COPY_ATTR (__annotations__ );
756+ return 0 ;
757+
758+ #undef COPY_ATTR
759+ }
760+
761+
718762/* Class method object */
719763
720764/* A class method receives the class as implicit first argument,
@@ -798,11 +842,16 @@ cm_init(PyObject *self, PyObject *args, PyObject *kwds)
798842 return -1 ;
799843 Py_INCREF (callable );
800844 Py_XSETREF (cm -> cm_callable , callable );
845+
846+ if (functools_wraps ((PyObject * )cm , cm -> cm_callable ) < 0 ) {
847+ return -1 ;
848+ }
801849 return 0 ;
802850}
803851
804852static PyMemberDef cm_memberlist [] = {
805853 {"__func__" , T_OBJECT , offsetof(classmethod , cm_callable ), READONLY },
854+ {"__wrapped__" , T_OBJECT , offsetof(classmethod , cm_callable ), READONLY },
806855 {NULL } /* Sentinel */
807856};
808857
@@ -821,13 +870,17 @@ cm_get___isabstractmethod__(classmethod *cm, void *closure)
821870
822871static PyGetSetDef cm_getsetlist [] = {
823872 {"__isabstractmethod__" ,
824- (getter )cm_get___isabstractmethod__ , NULL ,
825- NULL ,
826- NULL },
873+ (getter )cm_get___isabstractmethod__ , NULL , NULL , NULL },
827874 {"__dict__" , PyObject_GenericGetDict , PyObject_GenericSetDict , NULL , NULL },
828875 {NULL } /* Sentinel */
829876};
830877
878+ static PyObject *
879+ cm_repr (classmethod * cm )
880+ {
881+ return PyUnicode_FromFormat ("<classmethod(%R)>" , cm -> cm_callable );
882+ }
883+
831884PyDoc_STRVAR (classmethod_doc ,
832885"classmethod(function) -> method\n\
833886\n\
@@ -860,7 +913,7 @@ PyTypeObject PyClassMethod_Type = {
860913 0 , /* tp_getattr */
861914 0 , /* tp_setattr */
862915 0 , /* tp_as_async */
863- 0 , /* tp_repr */
916+ ( reprfunc ) cm_repr , /* tp_repr */
864917 0 , /* tp_as_number */
865918 0 , /* tp_as_sequence */
866919 0 , /* tp_as_mapping */
@@ -980,11 +1033,16 @@ sm_init(PyObject *self, PyObject *args, PyObject *kwds)
9801033 return -1 ;
9811034 Py_INCREF (callable );
9821035 Py_XSETREF (sm -> sm_callable , callable );
1036+
1037+ if (functools_wraps ((PyObject * )sm , sm -> sm_callable ) < 0 ) {
1038+ return -1 ;
1039+ }
9831040 return 0 ;
9841041}
9851042
9861043static PyMemberDef sm_memberlist [] = {
9871044 {"__func__" , T_OBJECT , offsetof(staticmethod , sm_callable ), READONLY },
1045+ {"__wrapped__" , T_OBJECT , offsetof(staticmethod , sm_callable ), READONLY },
9881046 {NULL } /* Sentinel */
9891047};
9901048
@@ -1003,13 +1061,17 @@ sm_get___isabstractmethod__(staticmethod *sm, void *closure)
10031061
10041062static PyGetSetDef sm_getsetlist [] = {
10051063 {"__isabstractmethod__" ,
1006- (getter )sm_get___isabstractmethod__ , NULL ,
1007- NULL ,
1008- NULL },
1064+ (getter )sm_get___isabstractmethod__ , NULL , NULL , NULL },
10091065 {"__dict__" , PyObject_GenericGetDict , PyObject_GenericSetDict , NULL , NULL },
10101066 {NULL } /* Sentinel */
10111067};
10121068
1069+ static PyObject *
1070+ sm_repr (staticmethod * sm )
1071+ {
1072+ return PyUnicode_FromFormat ("<staticmethod(%R)>" , sm -> sm_callable );
1073+ }
1074+
10131075PyDoc_STRVAR (staticmethod_doc ,
10141076"staticmethod(function) -> method\n\
10151077\n\
@@ -1040,7 +1102,7 @@ PyTypeObject PyStaticMethod_Type = {
10401102 0 , /* tp_getattr */
10411103 0 , /* tp_setattr */
10421104 0 , /* tp_as_async */
1043- 0 , /* tp_repr */
1105+ ( reprfunc ) sm_repr , /* tp_repr */
10441106 0 , /* tp_as_number */
10451107 0 , /* tp_as_sequence */
10461108 0 , /* tp_as_mapping */
0 commit comments