@@ -639,7 +639,7 @@ static PyObject*
639
639
func_repr (PyFunctionObject * op )
640
640
{
641
641
return PyUnicode_FromFormat ("<function %U at %p>" ,
642
- op -> func_qualname , op );
642
+ op -> func_qualname , op );
643
643
}
644
644
645
645
static int
@@ -715,6 +715,50 @@ PyTypeObject PyFunction_Type = {
715
715
};
716
716
717
717
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
+
718
762
/* Class method object */
719
763
720
764
/* A class method receives the class as implicit first argument,
@@ -798,11 +842,16 @@ cm_init(PyObject *self, PyObject *args, PyObject *kwds)
798
842
return -1 ;
799
843
Py_INCREF (callable );
800
844
Py_XSETREF (cm -> cm_callable , callable );
845
+
846
+ if (functools_wraps ((PyObject * )cm , cm -> cm_callable ) < 0 ) {
847
+ return -1 ;
848
+ }
801
849
return 0 ;
802
850
}
803
851
804
852
static PyMemberDef cm_memberlist [] = {
805
853
{"__func__" , T_OBJECT , offsetof(classmethod , cm_callable ), READONLY },
854
+ {"__wrapped__" , T_OBJECT , offsetof(classmethod , cm_callable ), READONLY },
806
855
{NULL } /* Sentinel */
807
856
};
808
857
@@ -821,13 +870,17 @@ cm_get___isabstractmethod__(classmethod *cm, void *closure)
821
870
822
871
static PyGetSetDef cm_getsetlist [] = {
823
872
{"__isabstractmethod__" ,
824
- (getter )cm_get___isabstractmethod__ , NULL ,
825
- NULL ,
826
- NULL },
873
+ (getter )cm_get___isabstractmethod__ , NULL , NULL , NULL },
827
874
{"__dict__" , PyObject_GenericGetDict , PyObject_GenericSetDict , NULL , NULL },
828
875
{NULL } /* Sentinel */
829
876
};
830
877
878
+ static PyObject *
879
+ cm_repr (classmethod * cm )
880
+ {
881
+ return PyUnicode_FromFormat ("<classmethod(%R)>" , cm -> cm_callable );
882
+ }
883
+
831
884
PyDoc_STRVAR (classmethod_doc ,
832
885
"classmethod(function) -> method\n\
833
886
\n\
@@ -860,7 +913,7 @@ PyTypeObject PyClassMethod_Type = {
860
913
0 , /* tp_getattr */
861
914
0 , /* tp_setattr */
862
915
0 , /* tp_as_async */
863
- 0 , /* tp_repr */
916
+ ( reprfunc ) cm_repr , /* tp_repr */
864
917
0 , /* tp_as_number */
865
918
0 , /* tp_as_sequence */
866
919
0 , /* tp_as_mapping */
@@ -980,11 +1033,16 @@ sm_init(PyObject *self, PyObject *args, PyObject *kwds)
980
1033
return -1 ;
981
1034
Py_INCREF (callable );
982
1035
Py_XSETREF (sm -> sm_callable , callable );
1036
+
1037
+ if (functools_wraps ((PyObject * )sm , sm -> sm_callable ) < 0 ) {
1038
+ return -1 ;
1039
+ }
983
1040
return 0 ;
984
1041
}
985
1042
986
1043
static PyMemberDef sm_memberlist [] = {
987
1044
{"__func__" , T_OBJECT , offsetof(staticmethod , sm_callable ), READONLY },
1045
+ {"__wrapped__" , T_OBJECT , offsetof(staticmethod , sm_callable ), READONLY },
988
1046
{NULL } /* Sentinel */
989
1047
};
990
1048
@@ -1003,13 +1061,17 @@ sm_get___isabstractmethod__(staticmethod *sm, void *closure)
1003
1061
1004
1062
static PyGetSetDef sm_getsetlist [] = {
1005
1063
{"__isabstractmethod__" ,
1006
- (getter )sm_get___isabstractmethod__ , NULL ,
1007
- NULL ,
1008
- NULL },
1064
+ (getter )sm_get___isabstractmethod__ , NULL , NULL , NULL },
1009
1065
{"__dict__" , PyObject_GenericGetDict , PyObject_GenericSetDict , NULL , NULL },
1010
1066
{NULL } /* Sentinel */
1011
1067
};
1012
1068
1069
+ static PyObject *
1070
+ sm_repr (staticmethod * sm )
1071
+ {
1072
+ return PyUnicode_FromFormat ("<staticmethod(%R)>" , sm -> sm_callable );
1073
+ }
1074
+
1013
1075
PyDoc_STRVAR (staticmethod_doc ,
1014
1076
"staticmethod(function) -> method\n\
1015
1077
\n\
@@ -1040,7 +1102,7 @@ PyTypeObject PyStaticMethod_Type = {
1040
1102
0 , /* tp_getattr */
1041
1103
0 , /* tp_setattr */
1042
1104
0 , /* tp_as_async */
1043
- 0 , /* tp_repr */
1105
+ ( reprfunc ) sm_repr , /* tp_repr */
1044
1106
0 , /* tp_as_number */
1045
1107
0 , /* tp_as_sequence */
1046
1108
0 , /* tp_as_mapping */
0 commit comments