@@ -300,15 +300,23 @@ PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
300300 }
301301}
302302
303- /* Internal routine to do a method lookup in the type
303+ /* Internal routines to do a method lookup in the type
304304 without looking in the instance dictionary
305305 (so we can't use PyObject_GetAttr) but still binding
306306 it to the instance. The arguments are the object,
307307 the method name as a C string, and the address of a
308- static variable used to cache the interned Python string. */
308+ static variable used to cache the interned Python string.
309+
310+ Two variants:
311+
312+ - lookup_maybe() returns NULL without raising an exception
313+ when the _PyType_Lookup() call fails;
314+
315+ - lookup_method() always raises an exception upon errors.
316+ */
309317
310318static PyObject *
311- lookup_method (PyObject * self , char * attrstr , PyObject * * attrobj )
319+ lookup_maybe (PyObject * self , char * attrstr , PyObject * * attrobj )
312320{
313321 PyObject * res ;
314322
@@ -318,9 +326,7 @@ lookup_method(PyObject *self, char *attrstr, PyObject **attrobj)
318326 return NULL ;
319327 }
320328 res = _PyType_Lookup (self -> ob_type , * attrobj );
321- if (res == NULL )
322- PyErr_SetObject (PyExc_AttributeError , * attrobj );
323- else {
329+ if (res != NULL ) {
324330 descrgetfunc f ;
325331 if ((f = res -> ob_type -> tp_descr_get ) == NULL )
326332 Py_INCREF (res );
@@ -330,6 +336,15 @@ lookup_method(PyObject *self, char *attrstr, PyObject **attrobj)
330336 return res ;
331337}
332338
339+ static PyObject *
340+ lookup_method (PyObject * self , char * attrstr , PyObject * * attrobj )
341+ {
342+ PyObject * res = lookup_maybe (self , attrstr , attrobj );
343+ if (res == NULL && !PyErr_Occurred ())
344+ PyErr_SetObject (PyExc_AttributeError , * attrobj );
345+ return res ;
346+ }
347+
333348/* A variation of PyObject_CallMethod that uses lookup_method()
334349 instead of PyObject_GetAttrString(). This uses the same convention
335350 as lookup_method to cache the interned name string object. */
@@ -342,11 +357,53 @@ call_method(PyObject *o, char *name, PyObject **nameobj, char *format, ...)
342357 PyObject * dummy_str = NULL ;
343358 va_start (va , format );
344359
345- func = lookup_method (o , name , & dummy_str );
360+ func = lookup_maybe (o , name , & dummy_str );
361+ if (func == NULL ) {
362+ va_end (va );
363+ if (!PyErr_Occurred ())
364+ PyErr_SetObject (PyExc_AttributeError , dummy_str );
365+ Py_XDECREF (dummy_str );
366+ return NULL ;
367+ }
368+ Py_DECREF (dummy_str );
369+
370+ if (format && * format )
371+ args = Py_VaBuildValue (format , va );
372+ else
373+ args = PyTuple_New (0 );
374+
375+ va_end (va );
376+
377+ if (args == NULL )
378+ return NULL ;
379+
380+ assert (PyTuple_Check (args ));
381+ retval = PyObject_Call (func , args , NULL );
382+
383+ Py_DECREF (args );
384+ Py_DECREF (func );
385+
386+ return retval ;
387+ }
388+
389+ /* Clone of call_method() that returns NotImplemented when the lookup fails. */
390+
391+ PyObject *
392+ call_maybe (PyObject * o , char * name , PyObject * * nameobj , char * format , ...)
393+ {
394+ va_list va ;
395+ PyObject * args , * func = 0 , * retval ;
396+ PyObject * dummy_str = NULL ;
397+ va_start (va , format );
398+
399+ func = lookup_maybe (o , name , & dummy_str );
346400 Py_XDECREF (dummy_str );
347401 if (func == NULL ) {
348402 va_end (va );
349- PyErr_SetString (PyExc_AttributeError , name );
403+ if (!PyErr_Occurred ()) {
404+ Py_INCREF (Py_NotImplemented );
405+ return Py_NotImplemented ;
406+ }
350407 return NULL ;
351408 }
352409
@@ -2447,7 +2504,7 @@ FUNCNAME(PyObject *self, PyObject *other) \
24472504 if (self->ob_type->tp_as_number != NULL && \
24482505 self->ob_type->tp_as_number->SLOTNAME == TESTFUNC) { \
24492506 PyObject *r; \
2450- r = call_method ( \
2507+ r = call_maybe ( \
24512508 self, OPSTR, &cache_str, "(O)", other); \
24522509 if (r != Py_NotImplemented || \
24532510 other->ob_type == self->ob_type) \
@@ -2456,7 +2513,7 @@ FUNCNAME(PyObject *self, PyObject *other) \
24562513 } \
24572514 if (other->ob_type->tp_as_number != NULL && \
24582515 other->ob_type->tp_as_number->SLOTNAME == TESTFUNC) { \
2459- return call_method ( \
2516+ return call_maybe ( \
24602517 other, ROPSTR, &rcache_str, "(O)", self); \
24612518 } \
24622519 Py_INCREF(Py_NotImplemented); \
0 commit comments