diff options
Diffstat (limited to 'numpy/core/src')
-rw-r--r-- | numpy/core/src/multiarray/common.c | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 10 | ||||
-rw-r--r-- | numpy/core/src/multiarray/methods.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 2 | ||||
-rw-r--r-- | numpy/core/src/private/binop_override.h | 5 | ||||
-rw-r--r-- | numpy/core/src/private/get_attr_string.h | 108 | ||||
-rw-r--r-- | numpy/core/src/private/ufunc_override.c | 59 | ||||
-rw-r--r-- | numpy/core/src/private/ufunc_override.h | 2 | ||||
-rw-r--r-- | numpy/core/src/umath/override.c | 101 |
9 files changed, 174 insertions, 121 deletions
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index 1df3b8b48..099cc0394 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -329,7 +329,7 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, } /* The array interface */ - ip = PyArray_GetAttrString_SuppressException(obj, "__array_interface__"); + ip = PyArray_LookupSpecial_OnInstance(obj, "__array_interface__"); if (ip != NULL) { if (PyDict_Check(ip)) { PyObject *typestr; @@ -362,7 +362,7 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, } /* The array struct interface */ - ip = PyArray_GetAttrString_SuppressException(obj, "__array_struct__"); + ip = PyArray_LookupSpecial_OnInstance(obj, "__array_struct__"); if (ip != NULL) { PyArrayInterface *inter; char buf[40]; @@ -397,7 +397,7 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, #endif /* The __array__ attribute */ - ip = PyArray_GetAttrString_SuppressException(obj, "__array__"); + ip = PyArray_LookupSpecial_OnInstance(obj, "__array__"); if (ip != NULL) { Py_DECREF(ip); ip = PyObject_CallMethod(obj, "__array__", NULL); diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 829bffcbd..7eae0beaa 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -753,7 +753,7 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it, } /* obj has the __array_struct__ interface */ - e = PyArray_GetAttrString_SuppressException(obj, "__array_struct__"); + e = PyArray_LookupSpecial_OnInstance(obj, "__array_struct__"); if (e != NULL) { int nd = -1; if (NpyCapsule_Check(e)) { @@ -778,7 +778,7 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it, } /* obj has the __array_interface__ interface */ - e = PyArray_GetAttrString_SuppressException(obj, "__array_interface__"); + e = PyArray_LookupSpecial_OnInstance(obj, "__array_interface__"); if (e != NULL) { int nd = -1; if (PyDict_Check(e)) { @@ -2062,7 +2062,7 @@ PyArray_FromStructInterface(PyObject *input) PyArrayObject *ret; char endian = NPY_NATBYTE; - attr = PyArray_GetAttrString_SuppressException(input, "__array_struct__"); + attr = PyArray_LookupSpecial_OnInstance(input, "__array_struct__"); if (attr == NULL) { return Py_NotImplemented; } @@ -2176,7 +2176,7 @@ PyArray_FromInterface(PyObject *origin) npy_intp dims[NPY_MAXDIMS], strides[NPY_MAXDIMS]; int dataflags = NPY_ARRAY_BEHAVED; - iface = PyArray_GetAttrString_SuppressException(origin, + iface = PyArray_LookupSpecial_OnInstance(origin, "__array_interface__"); if (iface == NULL) { return Py_NotImplemented; @@ -2409,7 +2409,7 @@ PyArray_FromArrayAttr(PyObject *op, PyArray_Descr *typecode, PyObject *context) PyObject *new; PyObject *array_meth; - array_meth = PyArray_GetAttrString_SuppressException(op, "__array__"); + array_meth = PyArray_LookupSpecial_OnInstance(op, "__array__"); if (array_meth == NULL) { return Py_NotImplemented; } diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c index 1a78b958c..898887042 100644 --- a/numpy/core/src/multiarray/methods.c +++ b/numpy/core/src/multiarray/methods.c @@ -1024,7 +1024,7 @@ array_ufunc(PyArrayObject *self, PyObject *args, PyObject *kwds) return NULL; } /* ndarray cannot handle overrides itself */ - num_override_args = PyUFunc_WithOverride(normal_args, kwds, NULL); + num_override_args = PyUFunc_WithOverride(normal_args, kwds, NULL, NULL); if (num_override_args == -1) { return NULL; } diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 2c5849dc0..81a1bc543 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -84,7 +84,7 @@ PyArray_GetPriority(PyObject *obj, double default_) return NPY_SCALAR_PRIORITY; } - ret = PyArray_GetAttrString_SuppressException(obj, "__array_priority__"); + ret = PyArray_LookupSpecial_OnInstance(obj, "__array_priority__"); if (ret == NULL) { return default_; } diff --git a/numpy/core/src/private/binop_override.h b/numpy/core/src/private/binop_override.h index caa6d42da..47df63e38 100644 --- a/numpy/core/src/private/binop_override.h +++ b/numpy/core/src/private/binop_override.h @@ -121,15 +121,14 @@ binop_should_defer(PyObject *self, PyObject *other, int inplace) self == NULL || Py_TYPE(self) == Py_TYPE(other) || PyArray_CheckExact(other) || - PyArray_CheckAnyScalarExact(other) || - _is_basic_python_type(other)) { + PyArray_CheckAnyScalarExact(other)) { return 0; } /* * Classes with __array_ufunc__ are living in the future, and only need to * check whether __array_ufunc__ equals None. */ - attr = PyArray_GetAttrString_SuppressException(other, "__array_ufunc__"); + attr = PyArray_LookupSpecial(other, "__array_ufunc__"); if (attr) { defer = !inplace && (attr == Py_None); Py_DECREF(attr); diff --git a/numpy/core/src/private/get_attr_string.h b/numpy/core/src/private/get_attr_string.h index b32be28f7..bec87c5ed 100644 --- a/numpy/core/src/private/get_attr_string.h +++ b/numpy/core/src/private/get_attr_string.h @@ -1,37 +1,45 @@ #ifndef __GET_ATTR_STRING_H #define __GET_ATTR_STRING_H -static NPY_INLINE int -_is_basic_python_type(PyObject * obj) +static NPY_INLINE npy_bool +_is_basic_python_type(PyTypeObject *tp) { - if (obj == Py_None || - PyBool_Check(obj) || - /* Basic number types */ + return ( + /* Basic number types */ + tp == &PyBool_Type || #if !defined(NPY_PY3K) - PyInt_CheckExact(obj) || - PyString_CheckExact(obj) || + tp == &PyInt_Type || #endif - PyLong_CheckExact(obj) || - PyFloat_CheckExact(obj) || - PyComplex_CheckExact(obj) || - /* Basic sequence types */ - PyList_CheckExact(obj) || - PyTuple_CheckExact(obj) || - PyDict_CheckExact(obj) || - PyAnySet_CheckExact(obj) || - PyUnicode_CheckExact(obj) || - PyBytes_CheckExact(obj) || - PySlice_Check(obj)) { + tp == &PyLong_Type || + tp == &PyFloat_Type || + tp == &PyComplex_Type || - return 1; - } + /* Basic sequence types */ + tp == &PyList_Type || + tp == &PyTuple_Type || + tp == &PyDict_Type || + tp == &PySet_Type || + tp == &PyFrozenSet_Type || + tp == &PyUnicode_Type || + tp == &PyBytes_Type || +#if !defined(NPY_PY3K) + tp == &PyString_Type || +#endif + + /* other builtins */ + tp == &PySlice_Type || + tp == Py_TYPE(Py_None) || + tp == Py_TYPE(Py_Ellipsis) || + tp == Py_TYPE(Py_NotImplemented) || + + /* TODO: ndarray, but we can't see PyArray_Type here */ - return 0; + /* sentinel to swallow trailing || */ + NPY_FALSE + ); } /* - * PyArray_GetAttrString_SuppressException: - * * Stripped down version of PyObject_GetAttrString, * avoids lookups for None, tuple, and List objects, * and doesn't create a PyErr since this code ignores it. @@ -43,19 +51,14 @@ _is_basic_python_type(PyObject * obj) * * 'name' is the attribute to search for. * - * Returns attribute value on success, 0 on failure. + * Returns attribute value on success, NULL on failure. */ -static PyObject * -PyArray_GetAttrString_SuppressException(PyObject *obj, char *name) +static NPY_INLINE PyObject * +maybe_get_attr(PyObject *obj, char *name) { PyTypeObject *tp = Py_TYPE(obj); PyObject *res = (PyObject *)NULL; - /* We do not need to check for special attributes on trivial types */ - if (_is_basic_python_type(obj)) { - return NULL; - } - /* Attribute referenced by (char *)name */ if (tp->tp_getattr != NULL) { res = (*tp->tp_getattr)(obj, name); @@ -82,4 +85,47 @@ PyArray_GetAttrString_SuppressException(PyObject *obj, char *name) return res; } +/* + * Lookup a special method, following the python approach of looking up + * on the type object, rather than on the instance itself. + * + * Assumes that the special method is a numpy-specific one, so does not look + * at builtin types, nor does it look at a base ndarray. + * + * In future, could be made more like _Py_LookupSpecial + */ +static NPY_INLINE PyObject * +PyArray_LookupSpecial(PyObject *obj, char *name) +{ + PyTypeObject *tp = Py_TYPE(obj); + + /* We do not need to check for special attributes on trivial types */ + if (_is_basic_python_type(tp)) { + return NULL; + } + + return maybe_get_attr((PyObject *)tp, name); +} + +/* + * PyArray_LookupSpecial_OnInstance: + * + * Implements incorrect special method lookup rules, that break the python + * convention, and looks on the instance, not the type. + * + * Kept for backwards compatibility. In future, we should deprecate this. + */ +static NPY_INLINE PyObject * +PyArray_LookupSpecial_OnInstance(PyObject *obj, char *name) +{ + PyTypeObject *tp = Py_TYPE(obj); + + /* We do not need to check for special attributes on trivial types */ + if (_is_basic_python_type(tp)) { + return NULL; + } + + return maybe_get_attr(obj, name); +} + #endif diff --git a/numpy/core/src/private/ufunc_override.c b/numpy/core/src/private/ufunc_override.c index c150c5021..401228236 100644 --- a/numpy/core/src/private/ufunc_override.c +++ b/numpy/core/src/private/ufunc_override.c @@ -12,18 +12,22 @@ * is not the default, i.e., the object is not an ndarray, and its * __array_ufunc__ is not the same as that of ndarray. * + * Returns a new reference, the value of type(obj).__array_ufunc__ + * + * If the __array_ufunc__ matches that of ndarray, or does not exist, return + * NULL. + * * Note that since this module is used with both multiarray and umath, we do * not have access to PyArray_Type and therewith neither to PyArray_CheckExact * nor to the default __array_ufunc__ method, so instead we import locally. * TODO: Can this really not be done more smartly? */ -static int -has_non_default_array_ufunc(PyObject *obj) +static PyObject * +get_non_default_array_ufunc(PyObject *obj) { static PyObject *ndarray = NULL; static PyObject *ndarray_array_ufunc = NULL; PyObject *cls_array_ufunc; - int non_default; /* on first entry, import and cache ndarray and its __array_ufunc__ */ if (ndarray == NULL) { @@ -34,47 +38,33 @@ has_non_default_array_ufunc(PyObject *obj) /* Fast return for ndarray */ if ((PyObject *)Py_TYPE(obj) == ndarray) { - return 0; + return NULL; } /* does the class define __array_ufunc__? */ - cls_array_ufunc = PyArray_GetAttrString_SuppressException( - (PyObject *)Py_TYPE(obj), "__array_ufunc__"); + cls_array_ufunc = PyArray_LookupSpecial(obj, "__array_ufunc__"); if (cls_array_ufunc == NULL) { - return 0; + return NULL; } /* is it different from ndarray.__array_ufunc__? */ - non_default = (cls_array_ufunc != ndarray_array_ufunc); + if (cls_array_ufunc != ndarray_array_ufunc) { + return cls_array_ufunc; + } Py_DECREF(cls_array_ufunc); - return non_default; -} - -/* - * Check whether an object sets __array_ufunc__ = None. The __array_func__ - * attribute must already be known to exist. - */ -static int -disables_array_ufunc(PyObject *obj) -{ - PyObject *array_ufunc; - int disables; - - array_ufunc = PyObject_GetAttrString(obj, "__array_ufunc__"); - disables = (array_ufunc == Py_None); - Py_XDECREF(array_ufunc); - return disables; + return NULL; } /* * Check whether a set of input and output args have a non-default * `__array_ufunc__` method. Return the number of overrides, setting * corresponding objects in PyObject array with_override (if not NULL) - * using borrowed references. + * using borrowed references, and the corresponding __array_ufunc__ methods + * in methods, using new references * * returns -1 on failure. */ NPY_NO_EXPORT int PyUFunc_WithOverride(PyObject *args, PyObject *kwds, - PyObject **with_override) + PyObject **with_override, PyObject **methods) { int i; @@ -116,6 +106,7 @@ PyUFunc_WithOverride(PyObject *args, PyObject *kwds, } for (i = 0; i < nargs + nout_kwd; ++i) { + PyObject *method; if (i < nargs) { obj = PyTuple_GET_ITEM(args, i); } @@ -132,22 +123,32 @@ PyUFunc_WithOverride(PyObject *args, PyObject *kwds, * ignore the base ndarray.__ufunc__, so we skip any ndarray as well as * any ndarray subclass instances that did not override __array_ufunc__. */ - if (has_non_default_array_ufunc(obj)) { - if (disables_array_ufunc(obj)) { + method = get_non_default_array_ufunc(obj); + if (method != NULL) { + if (method == Py_None) { PyErr_Format(PyExc_TypeError, "operand '%.200s' does not support ufuncs " "(__array_ufunc__=None)", obj->ob_type->tp_name); + Py_DECREF(method); goto fail; } if (with_override != NULL) { with_override[num_override_args] = obj; } + if (methods != NULL) { + methods[num_override_args] = method; + } ++num_override_args; } } return num_override_args; fail: + if (methods != NULL) { + for (i = 0; i < num_override_args; i++) { + Py_XDECREF(methods[i]); + } + } return -1; } diff --git a/numpy/core/src/private/ufunc_override.h b/numpy/core/src/private/ufunc_override.h index 15a932174..2ed1c626f 100644 --- a/numpy/core/src/private/ufunc_override.h +++ b/numpy/core/src/private/ufunc_override.h @@ -11,5 +11,5 @@ */ NPY_NO_EXPORT int PyUFunc_WithOverride(PyObject *args, PyObject *kwds, - PyObject **with_override); + PyObject **with_override, PyObject **methods); #endif diff --git a/numpy/core/src/umath/override.c b/numpy/core/src/umath/override.c index c7490a043..6b441cbbb 100644 --- a/numpy/core/src/umath/override.c +++ b/numpy/core/src/umath/override.c @@ -43,22 +43,23 @@ normalize___call___args(PyUFuncObject *ufunc, PyObject *args, /* * ufunc.__call__(*args, **kwds) */ - int i; + npy_intp i; int not_all_none; - int nin = ufunc->nin; - int nout = ufunc->nout; - int nargs = PyTuple_GET_SIZE(args); + npy_intp nin = ufunc->nin; + npy_intp nout = ufunc->nout; + npy_intp nargs = PyTuple_GET_SIZE(args); PyObject *obj; if (nargs < nin) { PyErr_Format(PyExc_TypeError, - "ufunc() missing %d of %d required positional argument(s)", - nin - nargs, nin); + "ufunc() missing %"NPY_INTP_FMT" of %"NPY_INTP_FMT + "required positional argument(s)", nin - nargs, nin); return -1; } if (nargs > nin+nout) { PyErr_Format(PyExc_TypeError, - "ufunc() takes from %d to %d arguments but %d were given", + "ufunc() takes from %"NPY_INTP_FMT" to %"NPY_INTP_FMT + "arguments but %"NPY_INTP_FMT" were given", nin, nin+nout, nargs); return -1; } @@ -72,8 +73,8 @@ normalize___call___args(PyUFuncObject *ufunc, PyObject *args, if (nargs > nin) { if(PyDict_GetItemString(*normal_kwds, "out")) { PyErr_Format(PyExc_TypeError, - "argument given by name ('out') and position (%d)", - nin); + "argument given by name ('out') and position " + "(%"NPY_INTP_FMT")", nin); return -1; } for (i = nin; i < nargs; i++) { @@ -119,15 +120,15 @@ normalize_reduce_args(PyUFuncObject *ufunc, PyObject *args, /* * ufunc.reduce(a[, axis, dtype, out, keepdims]) */ - int nargs = PyTuple_GET_SIZE(args); - int i; + npy_intp nargs = PyTuple_GET_SIZE(args); + npy_intp i; PyObject *obj; static char *kwlist[] = {"array", "axis", "dtype", "out", "keepdims"}; if (nargs < 1 || nargs > 5) { PyErr_Format(PyExc_TypeError, "ufunc.reduce() takes from 1 to 5 positional " - "arguments but %d were given", nargs); + "arguments but %"NPY_INTP_FMT" were given", nargs); return -1; } *normal_args = PyTuple_GetSlice(args, 0, 1); @@ -138,8 +139,8 @@ normalize_reduce_args(PyUFuncObject *ufunc, PyObject *args, for (i = 1; i < nargs; i++) { if (PyDict_GetItemString(*normal_kwds, kwlist[i])) { PyErr_Format(PyExc_TypeError, - "argument given by name ('%s') and position (%d)", - kwlist[i], i); + "argument given by name ('%s') and position " + "(%"NPY_INTP_FMT")", kwlist[i], i); return -1; } obj = PyTuple_GET_ITEM(args, i); @@ -163,15 +164,15 @@ normalize_accumulate_args(PyUFuncObject *ufunc, PyObject *args, /* * ufunc.accumulate(a[, axis, dtype, out]) */ - int nargs = PyTuple_GET_SIZE(args); - int i; + npy_intp nargs = PyTuple_GET_SIZE(args); + npy_intp i; PyObject *obj; static char *kwlist[] = {"array", "axis", "dtype", "out", "keepdims"}; if (nargs < 1 || nargs > 4) { PyErr_Format(PyExc_TypeError, "ufunc.accumulate() takes from 1 to 4 positional " - "arguments but %d were given", nargs); + "arguments but %"NPY_INTP_FMT" were given", nargs); return -1; } *normal_args = PyTuple_GetSlice(args, 0, 1); @@ -182,8 +183,8 @@ normalize_accumulate_args(PyUFuncObject *ufunc, PyObject *args, for (i = 1; i < nargs; i++) { if (PyDict_GetItemString(*normal_kwds, kwlist[i])) { PyErr_Format(PyExc_TypeError, - "argument given by name ('%s') and position (%d)", - kwlist[i], i); + "argument given by name ('%s') and position " + "(%"NPY_INTP_FMT")", kwlist[i], i); return -1; } obj = PyTuple_GET_ITEM(args, i); @@ -208,15 +209,15 @@ normalize_reduceat_args(PyUFuncObject *ufunc, PyObject *args, * ufunc.reduceat(a, indicies[, axis, dtype, out]) * the number of arguments has been checked in PyUFunc_GenericReduction. */ - int i; - int nargs = PyTuple_GET_SIZE(args); + npy_intp i; + npy_intp nargs = PyTuple_GET_SIZE(args); PyObject *obj; static char *kwlist[] = {"array", "indices", "axis", "dtype", "out"}; if (nargs < 2 || nargs > 5) { PyErr_Format(PyExc_TypeError, "ufunc.reduceat() takes from 2 to 4 positional " - "arguments but %d were given", nargs); + "arguments but %"NPY_INTP_FMT" were given", nargs); return -1; } /* a and indicies */ @@ -228,8 +229,8 @@ normalize_reduceat_args(PyUFuncObject *ufunc, PyObject *args, for (i = 2; i < nargs; i++) { if (PyDict_GetItemString(*normal_kwds, kwlist[i])) { PyErr_Format(PyExc_TypeError, - "argument given by name ('%s') and position (%d)", - kwlist[i], i); + "argument given by name ('%s') and position " + "(%"NPY_INTP_FMT")", kwlist[i], i); return -1; } obj = PyTuple_GET_ITEM(args, i); @@ -255,19 +256,19 @@ normalize_outer_args(PyUFuncObject *ufunc, PyObject *args, * all positional arguments should be inputs. * for the keywords, we only need to check 'sig' vs 'signature'. */ - int nin = ufunc->nin; - int nargs = PyTuple_GET_SIZE(args); + npy_intp nin = ufunc->nin; + npy_intp nargs = PyTuple_GET_SIZE(args); if (nargs < nin) { PyErr_Format(PyExc_TypeError, - "ufunc.outer() missing %d of %d required positional " - "argument(s)", nin - nargs, nin); + "ufunc.outer() missing %"NPY_INTP_FMT" of %"NPY_INTP_FMT + "required positional " "argument(s)", nin - nargs, nin); return -1; } if (nargs > nin) { PyErr_Format(PyExc_TypeError, - "ufunc.outer() takes %d arguments but %d were given", - nin, nargs); + "ufunc.outer() takes %"NPY_INTP_FMT" arguments but" + "%"NPY_INTP_FMT" were given", nin, nargs); return -1; } @@ -285,12 +286,12 @@ normalize_at_args(PyUFuncObject *ufunc, PyObject *args, PyObject **normal_args, PyObject **normal_kwds) { /* ufunc.at(a, indices[, b]) */ - int nargs = PyTuple_GET_SIZE(args); + npy_intp nargs = PyTuple_GET_SIZE(args); if (nargs < 2 || nargs > 3) { PyErr_Format(PyExc_TypeError, "ufunc.at() takes from 2 to 3 positional " - "arguments but %d were given", nargs); + "arguments but %"NPY_INTP_FMT" were given", nargs); return -1; } *normal_args = PyTuple_GetSlice(args, 0, nargs); @@ -319,6 +320,7 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, int num_override_args; PyObject *with_override[NPY_MAXARGS]; + PyObject *array_ufunc_methods[NPY_MAXARGS]; PyObject *obj; PyObject *other_obj; @@ -334,7 +336,8 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, /* * Check inputs for overrides */ - num_override_args = PyUFunc_WithOverride(args, kwds, with_override); + num_override_args = PyUFunc_WithOverride( + args, kwds, with_override, array_ufunc_methods); if (num_override_args == -1) { goto fail; } @@ -468,32 +471,34 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, } len = PyTuple_GET_SIZE(normal_args); - override_args = PyTuple_New(len + 2); + override_args = PyTuple_New(len + 3); if (override_args == NULL) { goto fail; } - Py_INCREF(ufunc); /* PyTuple_SET_ITEM steals reference */ - PyTuple_SET_ITEM(override_args, 0, (PyObject *)ufunc); + Py_INCREF(Py_None); + PyTuple_SET_ITEM(override_args, 0, Py_None); + Py_INCREF(ufunc); + PyTuple_SET_ITEM(override_args, 1, (PyObject *)ufunc); method_name = PyUString_FromString(method); if (method_name == NULL) { goto fail; } Py_INCREF(method_name); - PyTuple_SET_ITEM(override_args, 1, method_name); + PyTuple_SET_ITEM(override_args, 2, method_name); for (i = 0; i < len; i++) { PyObject *item = PyTuple_GET_ITEM(normal_args, i); Py_INCREF(item); - PyTuple_SET_ITEM(override_args, i + 2, item); + PyTuple_SET_ITEM(override_args, i + 3, item); } Py_DECREF(normal_args); /* Call __array_ufunc__ functions in correct order */ while (1) { - PyObject *array_ufunc; PyObject *override_obj; + PyObject *override_array_ufunc; override_obj = NULL; *result = NULL; @@ -524,6 +529,7 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, if (override_obj) { /* We won't call this one again */ with_override[i] = NULL; + override_array_ufunc = array_ufunc_methods[i]; break; } } @@ -548,15 +554,13 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, goto fail; } - /* Access the override */ - array_ufunc = PyObject_GetAttrString(override_obj, - "__array_ufunc__"); - if (array_ufunc == NULL) { - goto fail; - } + /* Set the self argument, since we have an unbound method */ + Py_INCREF(override_obj); + PyTuple_SetItem(override_args, 0, override_obj); - *result = PyObject_Call(array_ufunc, override_args, normal_kwds); - Py_DECREF(array_ufunc); + /* Call the method */ + *result = PyObject_Call( + override_array_ufunc, override_args, normal_kwds); if (*result == NULL) { /* Exception occurred */ @@ -580,6 +584,9 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, return 0; fail: + for (i = 0; i < num_override_args; i++) { + Py_XDECREF(array_ufunc_methods[i]); + } Py_XDECREF(method_name); Py_XDECREF(normal_kwds); Py_XDECREF(override_args); |