summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2013-04-13 09:51:45 +0200
committerSebastian Berg <sebastian@sipsolutions.net>2013-05-31 19:16:02 +0200
commit8dfc25d0e1fcaed67b8c688cfd9f5ac0641fc5e7 (patch)
tree1eef23206d25b9365d6ba72482291b899ba3bbe0 /numpy
parent5c8d5c263b93700ae92aff38bb9a8d05c0a185e6 (diff)
downloadnumpy-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.c318
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)) {