summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c77
1 files changed, 67 insertions, 10 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 8b1ac54..52fd7e9 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -300,15 +300,23 @@ PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b)
}
}
-/* Internal routine to do a method lookup in the type
+/* Internal routines to do a method lookup in the type
without looking in the instance dictionary
(so we can't use PyObject_GetAttr) but still binding
it to the instance. The arguments are the object,
the method name as a C string, and the address of a
- static variable used to cache the interned Python string. */
+ static variable used to cache the interned Python string.
+
+ Two variants:
+
+ - lookup_maybe() returns NULL without raising an exception
+ when the _PyType_Lookup() call fails;
+
+ - lookup_method() always raises an exception upon errors.
+*/
static PyObject *
-lookup_method(PyObject *self, char *attrstr, PyObject **attrobj)
+lookup_maybe(PyObject *self, char *attrstr, PyObject **attrobj)
{
PyObject *res;
@@ -318,9 +326,7 @@ lookup_method(PyObject *self, char *attrstr, PyObject **attrobj)
return NULL;
}
res = _PyType_Lookup(self->ob_type, *attrobj);
- if (res == NULL)
- PyErr_SetObject(PyExc_AttributeError, *attrobj);
- else {
+ if (res != NULL) {
descrgetfunc f;
if ((f = res->ob_type->tp_descr_get) == NULL)
Py_INCREF(res);
@@ -330,6 +336,15 @@ lookup_method(PyObject *self, char *attrstr, PyObject **attrobj)
return res;
}
+static PyObject *
+lookup_method(PyObject *self, char *attrstr, PyObject **attrobj)
+{
+ PyObject *res = lookup_maybe(self, attrstr, attrobj);
+ if (res == NULL && !PyErr_Occurred())
+ PyErr_SetObject(PyExc_AttributeError, *attrobj);
+ return res;
+}
+
/* A variation of PyObject_CallMethod that uses lookup_method()
instead of PyObject_GetAttrString(). This uses the same convention
as lookup_method to cache the interned name string object. */
@@ -342,11 +357,53 @@ call_method(PyObject *o, char *name, PyObject **nameobj, char *format, ...)
PyObject *dummy_str = NULL;
va_start(va, format);
- func = lookup_method(o, name, &dummy_str);
+ func = lookup_maybe(o, name, &dummy_str);
+ if (func == NULL) {
+ va_end(va);
+ if (!PyErr_Occurred())
+ PyErr_SetObject(PyExc_AttributeError, dummy_str);
+ Py_XDECREF(dummy_str);
+ return NULL;
+ }
+ Py_DECREF(dummy_str);
+
+ if (format && *format)
+ args = Py_VaBuildValue(format, va);
+ else
+ args = PyTuple_New(0);
+
+ va_end(va);
+
+ if (args == NULL)
+ return NULL;
+
+ assert(PyTuple_Check(args));
+ retval = PyObject_Call(func, args, NULL);
+
+ Py_DECREF(args);
+ Py_DECREF(func);
+
+ return retval;
+}
+
+/* Clone of call_method() that returns NotImplemented when the lookup fails. */
+
+PyObject *
+call_maybe(PyObject *o, char *name, PyObject **nameobj, char *format, ...)
+{
+ va_list va;
+ PyObject *args, *func = 0, *retval;
+ PyObject *dummy_str = NULL;
+ va_start(va, format);
+
+ func = lookup_maybe(o, name, &dummy_str);
Py_XDECREF(dummy_str);
if (func == NULL) {
va_end(va);
- PyErr_SetString(PyExc_AttributeError, name);
+ if (!PyErr_Occurred()) {
+ Py_INCREF(Py_NotImplemented);
+ return Py_NotImplemented;
+ }
return NULL;
}
@@ -2447,7 +2504,7 @@ FUNCNAME(PyObject *self, PyObject *other) \
if (self->ob_type->tp_as_number != NULL && \
self->ob_type->tp_as_number->SLOTNAME == TESTFUNC) { \
PyObject *r; \
- r = call_method( \
+ r = call_maybe( \
self, OPSTR, &cache_str, "(O)", other); \
if (r != Py_NotImplemented || \
other->ob_type == self->ob_type) \
@@ -2456,7 +2513,7 @@ FUNCNAME(PyObject *self, PyObject *other) \
} \
if (other->ob_type->tp_as_number != NULL && \
other->ob_type->tp_as_number->SLOTNAME == TESTFUNC) { \
- return call_method( \
+ return call_maybe( \
other, ROPSTR, &rcache_str, "(O)", self); \
} \
Py_INCREF(Py_NotImplemented); \