summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Taylor <juliantaylor108@gmail.com>2017-05-10 18:19:52 +0200
committerGitHub <noreply@github.com>2017-05-10 18:19:52 +0200
commit14ff219a13e194c5e7995218fea3c7648eb1c875 (patch)
treebcb6992c727bb477d6f37be40a2b03b77d4b19bc
parent82e923fd8879e557bc0b0c9de63e0500d0b190a0 (diff)
parent8f9eeef2abde02f03249c3ddfcce68bcdf0ee644 (diff)
downloadpython-numpy-14ff219a13e194c5e7995218fea3c7648eb1c875.tar.gz
python-numpy-14ff219a13e194c5e7995218fea3c7648eb1c875.tar.bz2
python-numpy-14ff219a13e194c5e7995218fea3c7648eb1c875.zip
Merge pull request #9087 from eric-wieser/fix-ufunc-resolution
BUG: __array_ufunc__ should always be looked up on the type, never the instance
-rw-r--r--numpy/core/_internal.py2
-rw-r--r--numpy/core/src/multiarray/common.c6
-rw-r--r--numpy/core/src/multiarray/ctors.c10
-rw-r--r--numpy/core/src/multiarray/methods.c2
-rw-r--r--numpy/core/src/multiarray/multiarraymodule.c2
-rw-r--r--numpy/core/src/private/binop_override.h5
-rw-r--r--numpy/core/src/private/get_attr_string.h108
-rw-r--r--numpy/core/src/private/ufunc_override.c59
-rw-r--r--numpy/core/src/private/ufunc_override.h2
-rw-r--r--numpy/core/src/umath/override.c101
10 files changed, 175 insertions, 122 deletions
diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py
index f7f579c75..10fcbfdfe 100644
--- a/numpy/core/_internal.py
+++ b/numpy/core/_internal.py
@@ -688,7 +688,7 @@ class AxisError(ValueError, IndexError):
super(AxisError, self).__init__(msg)
-def array_ufunc_errmsg_formatter(ufunc, method, *inputs, **kwargs):
+def array_ufunc_errmsg_formatter(dummy, ufunc, method, *inputs, **kwargs):
""" Format the error message for when __array_ufunc__ gives up. """
args_string = ', '.join(['{!r}'.format(arg) for arg in inputs] +
['{}={!r}'.format(k, v)
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);