From 69a423b23492ecf8471efc4e59ab8a93b03d8454 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 10 May 2017 13:07:58 +0100 Subject: MAINT: Distinguish "correct" special method lookups from incorrect ones This also corrects a broken short-circuit when looking up __array_ufunc__ --- numpy/core/src/multiarray/common.c | 6 +- numpy/core/src/multiarray/ctors.c | 10 +-- numpy/core/src/multiarray/multiarraymodule.c | 2 +- numpy/core/src/private/binop_override.h | 5 +- numpy/core/src/private/get_attr_string.h | 116 ++++++++++++++++++++------- numpy/core/src/private/ufunc_override.c | 5 +- 6 files changed, 99 insertions(+), 45 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/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..c49f75693 100644 --- a/numpy/core/src/private/get_attr_string.h +++ b/numpy/core/src/private/get_attr_string.h @@ -1,37 +1,55 @@ #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 */ + PyTypeObject const * const known_types[] = { + /* Basic number types */ + &PyBool_Type, #if !defined(NPY_PY3K) - PyInt_CheckExact(obj) || - PyString_CheckExact(obj) || + &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)) { - - return 1; + &PyLong_Type, + &PyFloat_Type, + &PyComplex_Type, + + /* Basic sequence types */ + &PyList_Type, + &PyTuple_Type, + &PyDict_Type, + &PySet_Type, + &PyFrozenSet_Type, + &PyUnicode_Type, + &PyBytes_Type, +#if !defined(NPY_PY3K) + &PyString_Type, +#endif + + /* other builtins */ + &PySlice_Type, + Py_TYPE(Py_None), + Py_TYPE(Py_Ellipsis), + Py_TYPE(Py_NotImplemented), + + /* TODO: ndarray, but we can't see PyArray_Type here */ + + /* sentinel */ + NULL + }; + PyTypeObject const * const * check_tp = known_types; + + while (*check_tp) { + if (tp == *check_tp) { + return NPY_TRUE; + } + check_tp++; } - return 0; + return 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 +61,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) +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 +95,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 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 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..5c15af9e2 100644 --- a/numpy/core/src/private/ufunc_override.c +++ b/numpy/core/src/private/ufunc_override.c @@ -37,8 +37,7 @@ has_non_default_array_ufunc(PyObject *obj) return 0; } /* 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; } @@ -58,7 +57,7 @@ disables_array_ufunc(PyObject *obj) PyObject *array_ufunc; int disables; - array_ufunc = PyObject_GetAttrString(obj, "__array_ufunc__"); + array_ufunc = PyArray_LookupSpecial(obj, "__array_ufunc__"); disables = (array_ufunc == Py_None); Py_XDECREF(array_ufunc); return disables; -- cgit v1.2.3 From ccfa36c0e008e21ab0d1d5822197cb490615d6b6 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 10 May 2017 14:18:04 +0100 Subject: MAINT: Fix warnings about int vs intp --- numpy/core/src/umath/override.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/numpy/core/src/umath/override.c b/numpy/core/src/umath/override.c index c7490a043..099cc501b 100644 --- a/numpy/core/src/umath/override.c +++ b/numpy/core/src/umath/override.c @@ -45,9 +45,9 @@ normalize___call___args(PyUFuncObject *ufunc, PyObject *args, */ int 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) { @@ -119,7 +119,7 @@ normalize_reduce_args(PyUFuncObject *ufunc, PyObject *args, /* * ufunc.reduce(a[, axis, dtype, out, keepdims]) */ - int nargs = PyTuple_GET_SIZE(args); + npy_intp nargs = PyTuple_GET_SIZE(args); int i; PyObject *obj; static char *kwlist[] = {"array", "axis", "dtype", "out", "keepdims"}; @@ -163,7 +163,7 @@ normalize_accumulate_args(PyUFuncObject *ufunc, PyObject *args, /* * ufunc.accumulate(a[, axis, dtype, out]) */ - int nargs = PyTuple_GET_SIZE(args); + npy_intp nargs = PyTuple_GET_SIZE(args); int i; PyObject *obj; static char *kwlist[] = {"array", "axis", "dtype", "out", "keepdims"}; @@ -209,7 +209,7 @@ normalize_reduceat_args(PyUFuncObject *ufunc, PyObject *args, * the number of arguments has been checked in PyUFunc_GenericReduction. */ int i; - int nargs = PyTuple_GET_SIZE(args); + npy_intp nargs = PyTuple_GET_SIZE(args); PyObject *obj; static char *kwlist[] = {"array", "indices", "axis", "dtype", "out"}; @@ -255,8 +255,8 @@ 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, @@ -285,7 +285,7 @@ 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, -- cgit v1.2.3 From 5bf2a79f939bf46fa76b127c7fa09db0e235475b Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 10 May 2017 14:38:16 +0100 Subject: BUG: Fix inconsistent lookup of __array_ufunc__. Previously, we would check if the attribute existed on the class, yet use it from the instance. This also cuts 3 lookups of `__array_ufunc__` down to one. --- numpy/core/_internal.py | 2 +- numpy/core/src/multiarray/methods.c | 2 +- numpy/core/src/private/ufunc_override.c | 55 +++++++++++++++++---------------- numpy/core/src/private/ufunc_override.h | 2 +- numpy/core/src/umath/override.c | 35 ++++++++++++--------- 5 files changed, 53 insertions(+), 43 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/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/private/ufunc_override.c b/numpy/core/src/private/ufunc_override.c index 5c15af9e2..22616f440 100644 --- a/numpy/core/src/private/ufunc_override.c +++ b/numpy/core/src/private/ufunc_override.c @@ -12,13 +12,18 @@ * 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; @@ -34,46 +39,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_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 = PyArray_LookupSpecial(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; @@ -115,6 +107,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); } @@ -131,22 +124,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 099cc501b..b6377ee86 100644 --- a/numpy/core/src/umath/override.c +++ b/numpy/core/src/umath/override.c @@ -319,6 +319,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 +335,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,25 +470,27 @@ 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); @@ -494,6 +498,7 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, 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); -- cgit v1.2.3 From 08b987acc446d7cf9d7e12cb626aeb166b8bb0d9 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 10 May 2017 15:31:24 +0100 Subject: MAINT: use if instead of loop --- numpy/core/src/private/get_attr_string.h | 52 +++++++++++++------------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/numpy/core/src/private/get_attr_string.h b/numpy/core/src/private/get_attr_string.h index c49f75693..50df4464c 100644 --- a/numpy/core/src/private/get_attr_string.h +++ b/numpy/core/src/private/get_attr_string.h @@ -4,49 +4,39 @@ static NPY_INLINE npy_bool _is_basic_python_type(PyTypeObject *tp) { - PyTypeObject const * const known_types[] = { + return ( /* Basic number types */ - &PyBool_Type, + tp == &PyBool_Type || #if !defined(NPY_PY3K) - &PyInt_Type, + tp == &PyInt_Type || #endif - &PyLong_Type, - &PyFloat_Type, - &PyComplex_Type, + tp == &PyLong_Type || + tp == &PyFloat_Type || + tp == &PyComplex_Type || /* Basic sequence types */ - &PyList_Type, - &PyTuple_Type, - &PyDict_Type, - &PySet_Type, - &PyFrozenSet_Type, - &PyUnicode_Type, - &PyBytes_Type, + 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) - &PyString_Type, + tp == &PyString_Type || #endif /* other builtins */ - &PySlice_Type, - Py_TYPE(Py_None), - Py_TYPE(Py_Ellipsis), - Py_TYPE(Py_NotImplemented), + 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 */ - /* sentinel */ - NULL - }; - PyTypeObject const * const * check_tp = known_types; - - while (*check_tp) { - if (tp == *check_tp) { - return NPY_TRUE; - } - check_tp++; - } - - return NPY_FALSE; + /* sentinel to swallow trailing || */ + NPY_FALSE + ); } /* -- cgit v1.2.3 From 171cdee8012a6850ef865f81e84fa1c4d3cf09a4 Mon Sep 17 00:00:00 2001 From: Eric Wieser Date: Wed, 10 May 2017 14:51:58 +0100 Subject: MAINT: Remove avoidable warnings --- numpy/core/src/private/get_attr_string.h | 6 +++--- numpy/core/src/private/ufunc_override.c | 1 - numpy/core/src/umath/override.c | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/numpy/core/src/private/get_attr_string.h b/numpy/core/src/private/get_attr_string.h index 50df4464c..bec87c5ed 100644 --- a/numpy/core/src/private/get_attr_string.h +++ b/numpy/core/src/private/get_attr_string.h @@ -53,7 +53,7 @@ _is_basic_python_type(PyTypeObject *tp) * * Returns attribute value on success, NULL on failure. */ -static PyObject * +static NPY_INLINE PyObject * maybe_get_attr(PyObject *obj, char *name) { PyTypeObject *tp = Py_TYPE(obj); @@ -94,7 +94,7 @@ maybe_get_attr(PyObject *obj, char *name) * * In future, could be made more like _Py_LookupSpecial */ -static PyObject * +static NPY_INLINE PyObject * PyArray_LookupSpecial(PyObject *obj, char *name) { PyTypeObject *tp = Py_TYPE(obj); @@ -115,7 +115,7 @@ PyArray_LookupSpecial(PyObject *obj, char *name) * * Kept for backwards compatibility. In future, we should deprecate this. */ -static PyObject * +static NPY_INLINE PyObject * PyArray_LookupSpecial_OnInstance(PyObject *obj, char *name) { PyTypeObject *tp = Py_TYPE(obj); diff --git a/numpy/core/src/private/ufunc_override.c b/numpy/core/src/private/ufunc_override.c index 22616f440..401228236 100644 --- a/numpy/core/src/private/ufunc_override.c +++ b/numpy/core/src/private/ufunc_override.c @@ -28,7 +28,6 @@ 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) { diff --git a/numpy/core/src/umath/override.c b/numpy/core/src/umath/override.c index b6377ee86..a8fab87a0 100644 --- a/numpy/core/src/umath/override.c +++ b/numpy/core/src/umath/override.c @@ -496,7 +496,6 @@ PyUFunc_CheckOverride(PyUFuncObject *ufunc, char *method, /* Call __array_ufunc__ functions in correct order */ while (1) { - PyObject *array_ufunc; PyObject *override_obj; PyObject *override_array_ufunc; -- cgit v1.2.3 From 8f9eeef2abde02f03249c3ddfcce68bcdf0ee644 Mon Sep 17 00:00:00 2001 From: Julian Taylor Date: Wed, 10 May 2017 17:46:49 +0200 Subject: MAINT: fix intp formatting warnings --- numpy/core/src/umath/override.c | 47 +++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/numpy/core/src/umath/override.c b/numpy/core/src/umath/override.c index a8fab87a0..6b441cbbb 100644 --- a/numpy/core/src/umath/override.c +++ b/numpy/core/src/umath/override.c @@ -43,7 +43,7 @@ normalize___call___args(PyUFuncObject *ufunc, PyObject *args, /* * ufunc.__call__(*args, **kwds) */ - int i; + npy_intp i; int not_all_none; npy_intp nin = ufunc->nin; npy_intp nout = ufunc->nout; @@ -52,13 +52,14 @@ normalize___call___args(PyUFuncObject *ufunc, PyObject *args, 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++) { @@ -120,14 +121,14 @@ normalize_reduce_args(PyUFuncObject *ufunc, PyObject *args, * ufunc.reduce(a[, axis, dtype, out, keepdims]) */ npy_intp nargs = PyTuple_GET_SIZE(args); - int i; + 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); @@ -164,14 +165,14 @@ normalize_accumulate_args(PyUFuncObject *ufunc, PyObject *args, * ufunc.accumulate(a[, axis, dtype, out]) */ npy_intp nargs = PyTuple_GET_SIZE(args); - int i; + 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,7 +209,7 @@ 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; + npy_intp i; npy_intp nargs = PyTuple_GET_SIZE(args); PyObject *obj; static char *kwlist[] = {"array", "indices", "axis", "dtype", "out"}; @@ -216,7 +217,7 @@ normalize_reduceat_args(PyUFuncObject *ufunc, PyObject *args, 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); @@ -260,14 +261,14 @@ normalize_outer_args(PyUFuncObject *ufunc, PyObject *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; } @@ -290,7 +291,7 @@ normalize_at_args(PyUFuncObject *ufunc, PyObject *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); -- cgit v1.2.3