]> granicus.if.org Git - python/commitdiff
Add call_maybe(): a variant of call_method() that returns
authorGuido van Rossum <guido@python.org>
Fri, 14 Sep 2001 17:51:50 +0000 (17:51 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 14 Sep 2001 17:51:50 +0000 (17:51 +0000)
NotImplemented when the lookup fails, and use this for binary
operators.  Also lookup_maybe() which doesn't raise an exception when
the lookup fails (still returning NULL).

Objects/typeobject.c

index 8b1ac54430fb1dfbba263a10e9f9227ab8a24e40..52fd7e9b731ecfce5ec0f2cfa023003585000460 100644 (file)
@@ -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); \