@@ -2000,58 +2000,90 @@ PyMethod_New(PyObject *func, PyObject *self, PyObject *class)
20002000 return (PyObject * )im ;
20012001}
20022002
2003- /* Class method methods */
2003+ /* Descriptors for PyMethod attributes */
2004+
2005+ /* im_class, im_func and im_self are stored in the PyMethod object */
20042006
20052007#define OFF (x ) offsetof(PyMethodObject, x)
20062008
20072009static struct memberlist instancemethod_memberlist [] = {
2008- {"im_func" , T_OBJECT , OFF (im_func )},
2009- {"im_self" , T_OBJECT , OFF (im_self )},
2010- {"im_class" , T_OBJECT , OFF (im_class )},
2011- /* Dummies that are not handled by getattr() except for __members__ */
2012- {"__doc__" , T_INT , 0 },
2013- {"__name__" , T_INT , 0 },
2014- {"__dict__" , T_OBJECT , 0 },
2010+ {"im_class" , T_OBJECT , OFF (im_class ), READONLY |RESTRICTED },
2011+ {"im_func" , T_OBJECT , OFF (im_func ), READONLY |RESTRICTED },
2012+ {"im_self" , T_OBJECT , OFF (im_self ), READONLY |RESTRICTED },
20152013 {NULL } /* Sentinel */
20162014};
20172015
2018- static int
2019- instancemethod_setattro (register PyMethodObject * im , PyObject * name ,
2020- PyObject * v )
2016+ /* __dict__, __doc__ and __name__ are retrieved from im_func */
2017+
2018+ static PyObject *
2019+ im_get_dict (PyMethodObject * im )
20212020{
2022- char * sname = PyString_AsString (name );
2021+ return PyObject_GetAttrString (im -> im_func , "__dict__" );
2022+ }
2023+
2024+ static PyObject *
2025+ im_get_doc (PyMethodObject * im )
2026+ {
2027+ return PyObject_GetAttrString (im -> im_func , "__doc__" );
2028+ }
20232029
2024- PyErr_Format (PyExc_TypeError , "read-only attribute: %s" , sname );
2025- return -1 ;
2030+ static PyObject *
2031+ im_get_name (PyMethodObject * im )
2032+ {
2033+ return PyObject_GetAttrString (im -> im_func , "__name__" );
20262034}
2027-
2035+
2036+ static struct getsetlist instancemethod_getsetlist [] = {
2037+ {"__dict__" , (getter )im_get_dict },
2038+ {"__doc__" , (getter )im_get_doc },
2039+ {"__name__" , (getter )im_get_name },
2040+ {NULL } /* Sentinel */
2041+ };
2042+
2043+ /* The getattr() implementation for PyMethod objects is similar to
2044+ PyObject_GenericGetAttr(), but instead of looking in __dict__ it
2045+ asks im_self for the attribute. Then the error handling is a bit
2046+ different because we want to preserve the exception raised by the
2047+ delegate, unless we have an alternative from our class. */
20282048
20292049static PyObject *
2030- instancemethod_getattro (register PyMethodObject * im , PyObject * name )
2050+ instancemethod_getattro (PyObject * obj , PyObject * name )
20312051{
2032- PyObject * rtn ;
2033- char * sname = PyString_AsString ( name ) ;
2034- if ( sname [ 0 ] == '_' ) {
2035- /* Inherit __name__ and __doc__ from the callable object
2036- implementing the method */
2037- if (strcmp ( sname , "__name__" ) == 0 ||
2038- strcmp ( sname , "__doc__" ) == 0 )
2039- return PyObject_GetAttr ( im -> im_func , name ) ;
2052+ PyMethodObject * im = ( PyMethodObject * ) obj ;
2053+ PyTypeObject * tp = obj -> ob_type ;
2054+ PyObject * descr , * res ;
2055+ descrgetfunc f ;
2056+
2057+ if (tp -> tp_dict == NULL ) {
2058+ if ( PyType_Ready ( tp ) < 0 )
2059+ return NULL ;
20402060 }
2041- if (PyEval_GetRestricted ()) {
2042- PyErr_SetString (PyExc_RuntimeError ,
2043- "instance-method attributes not accessible in restricted mode" );
2044- return NULL ;
2061+
2062+ descr = _PyType_Lookup (tp , name );
2063+ f = NULL ;
2064+ if (descr != NULL ) {
2065+ f = descr -> ob_type -> tp_descr_get ;
2066+ if (f != NULL && PyDescr_IsData (descr ))
2067+ return f (descr , obj , (PyObject * )obj -> ob_type );
2068+ }
2069+
2070+ res = PyObject_GetAttr (im -> im_func , name );
2071+ if (res != NULL || !PyErr_ExceptionMatches (PyExc_AttributeError ))
2072+ return res ;
2073+
2074+ if (f != NULL ) {
2075+ PyErr_Clear ();
2076+ return f (descr , obj , (PyObject * )obj -> ob_type );
20452077 }
2046- if (sname [0 ] == '_' && strcmp (sname , "__dict__" ) == 0 )
2047- return PyObject_GetAttr (im -> im_func , name );
20482078
2049- rtn = PyMember_Get ((char * )im , instancemethod_memberlist , sname );
2050- if (rtn == NULL && PyErr_ExceptionMatches (PyExc_AttributeError )) {
2079+ if (descr != NULL ) {
20512080 PyErr_Clear ();
2052- rtn = PyObject_GetAttr (im -> im_func , name );
2081+ Py_INCREF (descr );
2082+ return descr ;
20532083 }
2054- return rtn ;
2084+
2085+ assert (PyErr_Occurred ());
2086+ return NULL ;
20552087}
20562088
20572089static void
@@ -2298,7 +2330,7 @@ PyTypeObject PyMethod_Type = {
22982330 instancemethod_call , /* tp_call */
22992331 0 , /* tp_str */
23002332 (getattrofunc )instancemethod_getattro , /* tp_getattro */
2301- ( setattrofunc ) instancemethod_setattro , /* tp_setattro */
2333+ PyObject_GenericSetAttr , /* tp_setattro */
23022334 0 , /* tp_as_buffer */
23032335 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC ,/* tp_flags */
23042336 0 , /* tp_doc */
@@ -2309,8 +2341,8 @@ PyTypeObject PyMethod_Type = {
23092341 0 , /* tp_iter */
23102342 0 , /* tp_iternext */
23112343 0 , /* tp_methods */
2312- 0 , /* tp_members */
2313- 0 , /* tp_getset */
2344+ instancemethod_memberlist , /* tp_members */
2345+ instancemethod_getsetlist , /* tp_getset */
23142346 0 , /* tp_base */
23152347 0 , /* tp_dict */
23162348 instancemethod_descr_get , /* tp_descr_get */
0 commit comments