diff options
author | Sebastian Berg <sebastian@sipsolutions.net> | 2013-04-13 09:51:45 +0200 |
---|---|---|
committer | Sebastian Berg <sebastian@sipsolutions.net> | 2013-05-31 19:16:02 +0200 |
commit | 8dfc25d0e1fcaed67b8c688cfd9f5ac0641fc5e7 (patch) | |
tree | 1eef23206d25b9365d6ba72482291b899ba3bbe0 /numpy | |
parent | 5c8d5c263b93700ae92aff38bb9a8d05c0a185e6 (diff) | |
download | numpy-8dfc25d0e1fcaed67b8c688cfd9f5ac0641fc5e7.tar.gz |
API: Deprecating the use of non-integers for indices arguments
This changes the conversion utils to give deprecations for a all
non-integers (this currently includes python bools). The biggest
change is PyArray_PyIntAsIntp in which the deprecation is done.
Some other conversions are then also pointed to it.
Uses the Index machinery even for numpy types, which is faster
then the current code.
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/core/src/multiarray/conversion_utils.c | 318 |
1 files changed, 133 insertions, 185 deletions
diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index 27d435881..71690c20b 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -84,7 +84,7 @@ PyArray_OutputConverter(PyObject *object, PyArrayObject **address) NPY_NO_EXPORT int PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq) { - int len; + Py_ssize_t len; int nd; seq->ptr = NULL; @@ -94,14 +94,15 @@ PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq) } len = PySequence_Size(obj); if (len == -1) { - /* Check to see if it is a number */ + /* Check to see if it is an integer number */ if (PyNumber_Check(obj)) { + /* DEPRECATED: replace PyNumber_Check with PyIndex_Check */ len = 1; } } if (len < 0) { PyErr_SetString(PyExc_TypeError, - "expected sequence object with len >= 0"); + "expected sequence object with len >= 0 or a single integer"); return NPY_FAIL; } if (len > NPY_MAXDIMS) { @@ -117,7 +118,7 @@ PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq) } } seq->len = len; - nd = PyArray_IntpFromSequence(obj, (npy_intp *)seq->ptr, len); + nd = PyArray_IntpFromSequence(obj, (npy_intp *)seq->ptr, (int) len); if (nd == -1 || nd != len) { PyDimMem_FREE(seq->ptr); seq->ptr = NULL; @@ -187,7 +188,7 @@ PyArray_AxisConverter(PyObject *obj, int *axis) *axis = NPY_MAXDIMS; } else { - *axis = (int) PyInt_AsLong(obj); + *axis = (int) PyArray_PyIntAsInt(obj); if (PyErr_Occurred()) { return NPY_FAIL; } @@ -223,9 +224,9 @@ PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags) } for (i = 0; i < naxes; ++i) { PyObject *tmp = PyTuple_GET_ITEM(axis_in, i); - long axis = PyInt_AsLong(tmp); - long axis_orig = axis; - if (axis == -1 && PyErr_Occurred()) { + int axis = PyArray_PyIntAsInt(tmp); + int axis_orig = axis; + if (error_converting(axis)) { return NPY_FAIL; } if (axis < 0) { @@ -233,7 +234,7 @@ PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags) } if (axis < 0 || axis >= ndim) { PyErr_Format(PyExc_ValueError, - "'axis' entry %ld is out of bounds [-%d, %d)", + "'axis' entry %d is out of bounds [-%d, %d)", axis_orig, ndim, ndim); return NPY_FAIL; } @@ -249,14 +250,14 @@ PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags) } /* Try to interpret axis as an integer */ else { - long axis, axis_orig; + int axis, axis_orig; memset(out_axis_flags, 0, ndim); - axis = PyInt_AsLong(axis_in); + axis = PyArray_PyIntAsInt(axis_in); axis_orig = axis; - /* TODO: PyNumber_Index would be good to use here */ - if (axis == -1 && PyErr_Occurred()) { + + if (error_converting(axis)) { return NPY_FAIL; } if (axis < 0) { @@ -272,7 +273,7 @@ PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags) if (axis < 0 || axis >= ndim) { PyErr_Format(PyExc_ValueError, - "'axis' entry %ld is out of bounds [-%d, %d)", + "'axis' entry %d is out of bounds [-%d, %d)", axis_orig, ndim, ndim); return NPY_FAIL; } @@ -529,8 +530,8 @@ PyArray_ClipmodeConverter(PyObject *object, NPY_CLIPMODE *val) return ret; } else { - int number = PyInt_AsLong(object); - if (number == -1 && PyErr_Occurred()) { + int number = PyArray_PyIntAsInt(object); + if (error_converting(number)) { goto fail; } if (number <= (int) NPY_RAISE @@ -664,61 +665,105 @@ PyArray_CastingConverter(PyObject *obj, NPY_CASTING *casting) NPY_NO_EXPORT int PyArray_PyIntAsInt(PyObject *o) { - long long_value = -1; - PyObject *obj; - static char *msg = "an integer is required"; - PyArrayObject *arr; - PyArray_Descr *descr; - int ret; + npy_intp long_value; + /* This assumes that NPY_SIZEOF_INTP >= NPY_SIZEOF_INT */ + long_value = PyArray_PyIntAsIntp(o); +#if (NPY_SIZEOF_INTP > NPY_SIZEOF_INT) + if ((long_value < INT_MIN) || (long_value > INT_MAX)) { + PyErr_SetString(PyExc_ValueError, "integer won't fit into a C int"); + return -1; + } +#endif + return (int) long_value; +} + +/*NUMPY_API*/ +NPY_NO_EXPORT npy_intp +PyArray_PyIntAsIntp(PyObject *o) +{ +#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + npy_long long_value = -1; +#else + npy_longlong long_value = -1; +#endif + PyObject *obj, *err; + static char *msg = "an integer is required"; if (!o) { PyErr_SetString(PyExc_TypeError, msg); return -1; } - if (PyInt_Check(o)) { - long_value = (long) PyInt_AS_LONG(o); - goto finish; - } else if (PyLong_Check(o)) { - long_value = (long) PyLong_AsLong(o); - goto finish; - } - descr = &INT_Descr; - arr = NULL; - if (PyArray_Check(o)) { - if (PyArray_SIZE((PyArrayObject *)o)!=1 || - !PyArray_ISINTEGER((PyArrayObject *)o)) { - PyErr_SetString(PyExc_TypeError, msg); + /* Be a bit stricter and not allow bools */ + if (PyBool_Check(o)) { + if (DEPRECATE("using a boolean instead of an integer" + " will result in an error in the future") < 0) { return -1; } - Py_INCREF(descr); - arr = (PyArrayObject *)PyArray_CastToType((PyArrayObject *)o, - descr, 0); } - if (PyArray_IsScalar(o, Integer)) { - Py_INCREF(descr); - arr = (PyArrayObject *)PyArray_FromScalar(o, descr); - } - if (arr != NULL) { - ret = *((int *)PyArray_DATA(arr)); - Py_DECREF(arr); - return ret; + + /* + * Since it is the usual case, first check if o is an integer. This is + * an exact check, since otherwise __index__ is used. + */ +#if !defined(NPY_PY3K) + if PyInt_CheckExact(o) { + #if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + long_value = (npy_longlong) PyInt_AsLong(o); + #else + long_value = PyInt_AsLong(o); + #endif + goto finish; } -#if (PY_VERSION_HEX >= 0x02050000) - if (PyIndex_Check(o)) { - PyObject* value = PyNumber_Index(o); - long_value = (npy_longlong) PyInt_AsSsize_t(value); + else +#endif + if PyLong_CheckExact(o) { +#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + long_value = PyLong_AsLongLong(o); +#else + long_value = PyLong_AsLong(o); +#endif goto finish; } + /* + * The most general case. PyNumber_Index(o) covers everything + * including arrays. In principle it may be possible to replace + * the whole function by PyIndex_AsSSize_t after deprecation. + */ + obj = PyNumber_Index(o); + if (obj) { +#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + long_value = PyLong_AsLongLong(obj); +#else + long_value = PyLong_AsLong(obj); #endif + Py_DECREF(obj); + goto finish; + } + else { + /* + * Set the TypeError like PyNumber_Index(o) would after trying + * the general case. + */ + PyErr_Clear(); + } + + /* + * For backward compatibility check the number C-Api number protcol + * This should be removed up the finish label after deprecation. + */ if (Py_TYPE(o)->tp_as_number != NULL && Py_TYPE(o)->tp_as_number->nb_int != NULL) { obj = Py_TYPE(o)->tp_as_number->nb_int(o); if (obj == NULL) { return -1; } - long_value = (long) PyLong_AsLong(obj); + #if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + long_value = PyLong_AsLongLong(obj); + #else + long_value = PyLong_AsLong(obj); + #endif Py_DECREF(obj); } #if !defined(NPY_PY3K) @@ -728,126 +773,54 @@ PyArray_PyIntAsInt(PyObject *o) if (obj == NULL) { return -1; } - long_value = (long) PyLong_AsLong(obj); + #if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + long_value = PyLong_AsLongLong(obj); + #else + long_value = PyLong_AsLong(obj); + #endif Py_DECREF(obj); } #endif else { - PyErr_SetString(PyExc_NotImplementedError,""); - } - - finish: - if error_converting(long_value) { - PyErr_SetString(PyExc_TypeError, msg); - return -1; - } - -#if (NPY_SIZEOF_LONG > NPY_SIZEOF_INT) - if ((long_value < INT_MIN) || (long_value > INT_MAX)) { - PyErr_SetString(PyExc_ValueError, "integer won't fit into a C int"); - return -1; - } -#endif - return (int) long_value; -} - -/*NUMPY_API*/ -NPY_NO_EXPORT npy_intp -PyArray_PyIntAsIntp(PyObject *o) -{ - npy_longlong long_value = -1; - PyObject *obj; - static char *msg = "an integer is required"; - PyArrayObject *arr; - PyArray_Descr *descr; - npy_intp ret; - - if (!o) { PyErr_SetString(PyExc_TypeError, msg); return -1; } - if (PyInt_Check(o)) { - long_value = (npy_longlong) PyInt_AS_LONG(o); - goto finish; - } else if (PyLong_Check(o)) { - long_value = (npy_longlong) PyLong_AsLongLong(o); - goto finish; - } - -#if NPY_SIZEOF_INTP == NPY_SIZEOF_LONG - descr = &LONG_Descr; -#elif NPY_SIZEOF_INTP == NPY_SIZEOF_INT - descr = &INT_Descr; -#else - descr = &LONGLONG_Descr; -#endif - arr = NULL; - - if (PyArray_Check(o)) { - if (PyArray_SIZE((PyArrayObject *)o)!=1 || - !PyArray_ISINTEGER((PyArrayObject *)o)) { - PyErr_SetString(PyExc_TypeError, msg); + /* Give a deprecation warning, unless there was already an error */ + if (!error_converting(long_value)) { + if (DEPRECATE("using a non-integer number instead of an integer" + " will result in an error in the future") < 0) { return -1; } - Py_INCREF(descr); - arr = (PyArrayObject *)PyArray_CastToType((PyArrayObject *)o, - descr, 0); - } - else if (PyArray_IsScalar(o, Integer)) { - Py_INCREF(descr); - arr = (PyArrayObject *)PyArray_FromScalar(o, descr); - } - if (arr != NULL) { - ret = *((npy_intp *)PyArray_DATA(arr)); - Py_DECREF(arr); - return ret; - } - -#if (PY_VERSION_HEX >= 0x02050000) - if (PyIndex_Check(o)) { - PyObject* value = PyNumber_Index(o); - if (value == NULL) { - return -1; - } - long_value = (npy_longlong) PyInt_AsSsize_t(value); - goto finish; - } -#endif -#if !defined(NPY_PY3K) - if (Py_TYPE(o)->tp_as_number != NULL && \ - Py_TYPE(o)->tp_as_number->nb_long != NULL) { - obj = Py_TYPE(o)->tp_as_number->nb_long(o); - if (obj != NULL) { - long_value = (npy_longlong) PyLong_AsLongLong(obj); - Py_DECREF(obj); - } - } - else -#endif - if (Py_TYPE(o)->tp_as_number != NULL && \ - Py_TYPE(o)->tp_as_number->nb_int != NULL) { - obj = Py_TYPE(o)->tp_as_number->nb_int(o); - if (obj != NULL) { - long_value = (npy_longlong) PyLong_AsLongLong(obj); - Py_DECREF(obj); - } - } - else { - PyErr_SetString(PyExc_NotImplementedError,""); } finish: - if error_converting(long_value) { - PyErr_SetString(PyExc_TypeError, msg); + if (long_value == -1) { + err = PyErr_Occurred(); + /* Only replace TypeError's here, which are the normal errors. */ + if (err) { + if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) { + PyErr_SetString(PyExc_TypeError, msg); + } return -1; } + } -#if (NPY_SIZEOF_LONGLONG > NPY_SIZEOF_INTP) +#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP) + #if (NPY_SIZEOF_LONGLONG > NPY_SIZEOF_INTP) if ((long_value < NPY_MIN_INTP) || (long_value > NPY_MAX_INTP)) { - PyErr_SetString(PyExc_ValueError, - "integer won't fit into a C intp"); + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C numpy.intp"); return -1; } + #endif +#else + #if (NPY_SIZEOF_LONG > NPY_SIZEOF_INTP) + if ((long_value < NPY_MIN_INTP) || (long_value > NPY_MAX_INTP)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C numpy.intp"); + return -1; + } + #endif #endif return (npy_intp) long_value; } @@ -867,29 +840,11 @@ PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals) * Check to see if sequence is a single integer first. * or, can be made into one */ - if ((nd=PySequence_Length(seq)) == -1) { + nd = PySequence_Length(seq); + if (nd == -1) { if (PyErr_Occurred()) PyErr_Clear(); -#if NPY_SIZEOF_LONG >= NPY_SIZEOF_INTP && !defined(NPY_PY3K) - if (!(op = PyNumber_Int(seq))) { - return -1; - } -#else - if (!(op = PyNumber_Long(seq))) { - return -1; - } -#endif - nd = 1; -#if NPY_SIZEOF_LONG >= NPY_SIZEOF_INTP - vals[0] = (npy_intp ) PyInt_AsLong(op); -#else - vals[0] = (npy_intp ) PyLong_AsLongLong(op); -#endif - Py_DECREF(op); - /* - * Check wether there was an error - if the error was an overflow, raise - * a ValueError instead to be more helpful - */ + vals[0] = PyArray_PyIntAsIntp(seq); if(vals[0] == -1) { err = PyErr_Occurred(); if (err && @@ -901,6 +856,7 @@ PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals) return -1; } } + nd = 1; } else { for (i = 0; i < PyArray_MIN(nd,maxvals); i++) { @@ -908,18 +864,10 @@ PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals) if (op == NULL) { return -1; } -#if NPY_SIZEOF_LONG >= NPY_SIZEOF_INTP - vals[i]=(npy_intp )PyInt_AsLong(op); -#else - vals[i]=(npy_intp )PyLong_AsLongLong(op); -#endif - Py_DECREF(op); - /* - * Check wether there was an error - if the error was an overflow, - * raise a ValueError instead to be more helpful - */ - if(vals[0] == -1) { + + vals[i] = PyArray_PyIntAsIntp(op); + if(vals[i] == -1) { err = PyErr_Occurred(); if (err && PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) { |