summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2013-06-09 08:11:02 -0700
committerCharles Harris <charlesr.harris@gmail.com>2013-06-09 08:11:02 -0700
commit558cd20c29db0cd89c4d92fc354602650f861064 (patch)
treead3531de30581e88b146aecbce8c057e4f792d30 /numpy
parent704b456e49b13150aa693f4fd7d66dca0d541f0b (diff)
parent163f6df5a6668d06cb7abfe38dbd03d19b26d6f3 (diff)
downloadnumpy-558cd20c29db0cd89c4d92fc354602650f861064.tar.gz
Merge pull request #3243 from seberg/deprecate-non-integer-arguments-new
Deprecate non integer arguments
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/defchararray.py4
-rw-r--r--numpy/core/src/multiarray/conversion_utils.c366
-rw-r--r--numpy/core/src/multiarray/conversion_utils.h3
-rw-r--r--numpy/core/src/multiarray/iterators.c53
-rw-r--r--numpy/core/src/multiarray/mapping.c51
-rw-r--r--numpy/core/src/multiarray/number.c6
-rw-r--r--numpy/core/src/private/npy_pycompat.h12
-rw-r--r--numpy/core/tests/test_deprecations.py295
-rw-r--r--numpy/core/tests/test_indexing.py5
-rw-r--r--numpy/lib/index_tricks.py2
-rw-r--r--numpy/lib/shape_base.py2
-rw-r--r--numpy/random/tests/test_regression.py2
12 files changed, 387 insertions, 414 deletions
diff --git a/numpy/core/defchararray.py b/numpy/core/defchararray.py
index 2a8b31616..92995baa1 100644
--- a/numpy/core/defchararray.py
+++ b/numpy/core/defchararray.py
@@ -90,7 +90,7 @@ def _get_num_chars(a):
for a unicode array this is itemsize / 4.
"""
if issubclass(a.dtype.type, unicode_):
- return a.itemsize / 4
+ return a.itemsize // 4
return a.itemsize
@@ -2593,7 +2593,7 @@ def array(obj, itemsize=None, copy=True, unicode=None, order=None):
# to divide by the size of a single Unicode character,
# which for Numpy is always 4
if issubclass(obj.dtype.type, unicode_):
- itemsize /= 4
+ itemsize //= 4
if unicode is None:
if issubclass(obj.dtype.type, unicode_):
diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c
index 27d435881..79093467f 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,18 @@ 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)) {
+ /*
+ * After the deprecation the PyNumber_Check could be replaced
+ * by 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 +121,7 @@ PyArray_IntpConverter(PyObject *obj, PyArray_Dims *seq)
}
}
seq->len = len;
- nd = PyArray_IntpFromSequence(obj, (npy_intp *)seq->ptr, len);
+ nd = PyArray_IntpFromIndexSequence(obj, (npy_intp *)seq->ptr, len);
if (nd == -1 || nd != len) {
PyDimMem_FREE(seq->ptr);
seq->ptr = NULL;
@@ -187,7 +191,7 @@ PyArray_AxisConverter(PyObject *obj, int *axis)
*axis = NPY_MAXDIMS;
}
else {
- *axis = (int) PyInt_AsLong(obj);
+ *axis = PyArray_PyIntAsInt(obj);
if (PyErr_Occurred()) {
return NPY_FAIL;
}
@@ -223,9 +227,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 +237,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 +253,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 +276,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 +533,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,85 +668,11 @@ 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;
-
-
- 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);
- 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;
- }
-#if (PY_VERSION_HEX >= 0x02050000)
- if (PyIndex_Check(o)) {
- PyObject* value = PyNumber_Index(o);
- long_value = (npy_longlong) PyInt_AsSsize_t(value);
- goto finish;
- }
-#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) {
- return -1;
- }
- long_value = (long) PyLong_AsLong(obj);
- Py_DECREF(obj);
- }
-#if !defined(NPY_PY3K)
- else 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) {
- return -1;
- }
- long_value = (long) PyLong_AsLong(obj);
- Py_DECREF(obj);
- }
-#endif
- else {
- PyErr_SetString(PyExc_NotImplementedError,"");
- }
-
- finish:
- if error_converting(long_value) {
- PyErr_SetString(PyExc_TypeError, msg);
- return -1;
- }
+ npy_intp long_value;
+ /* This assumes that NPY_SIZEOF_INTP >= NPY_SIZEOF_INT */
+ long_value = PyArray_PyIntAsIntp(o);
-#if (NPY_SIZEOF_LONG > NPY_SIZEOF_INT)
+#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;
@@ -755,145 +685,188 @@ PyArray_PyIntAsInt(PyObject *o)
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;
- PyObject *obj;
+#endif
+ PyObject *obj, *err;
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;
+
+ /* Be a bit stricter and not allow bools, np.bool_ is handled later */
+ if (PyBool_Check(o)) {
+ if (DEPRECATE("using a boolean instead of an integer"
+ " will result in an error in the future") < 0) {
+ return -1;
+ }
}
-#if NPY_SIZEOF_INTP == NPY_SIZEOF_LONG
- descr = &LONG_Descr;
-#elif NPY_SIZEOF_INTP == NPY_SIZEOF_INT
- descr = &INT_Descr;
+ /*
+ * 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)
+ /* No overflow is possible, so we can just return */
+ return PyInt_AS_LONG(o);
+ #else
+ long_value = PyInt_AS_LONG(o);
+ goto overflow_check;
+ #endif
+ }
+ else
+#endif
+ if PyLong_CheckExact(o) {
+#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP)
+ long_value = PyLong_AsLongLong(o);
#else
- descr = &LONGLONG_Descr;
+ long_value = PyLong_AsLong(o);
#endif
- arr = NULL;
+ return (npy_intp)long_value;
+ }
- if (PyArray_Check(o)) {
- if (PyArray_SIZE((PyArrayObject *)o)!=1 ||
- !PyArray_ISINTEGER((PyArrayObject *)o)) {
- PyErr_SetString(PyExc_TypeError, msg);
+ /* Disallow numpy.bool_. Boolean arrays do not currently support index. */
+ if (PyArray_IsScalar(o, Bool)) {
+ 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);
}
- else if (PyArray_IsScalar(o, Integer)) {
- Py_INCREF(descr);
- arr = (PyArrayObject *)PyArray_FromScalar(o, descr);
+
+ /*
+ * 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;
}
- if (arr != NULL) {
- ret = *((npy_intp *)PyArray_DATA(arr));
- Py_DECREF(arr);
- return ret;
+ else {
+ /*
+ * Set the TypeError like PyNumber_Index(o) would after trying
+ * the general case.
+ */
+ PyErr_Clear();
}
-#if (PY_VERSION_HEX >= 0x02050000)
- if (PyIndex_Check(o)) {
- PyObject* value = PyNumber_Index(o);
- if (value == NULL) {
+ /*
+ * 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 = (npy_longlong) PyInt_AsSsize_t(value);
- goto finish;
+ #if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP)
+ long_value = PyLong_AsLongLong(obj);
+ #else
+ long_value = PyLong_AsLong(obj);
+ #endif
+ Py_DECREF(obj);
}
-#endif
#if !defined(NPY_PY3K)
- if (Py_TYPE(o)->tp_as_number != NULL && \
- Py_TYPE(o)->tp_as_number->nb_long != NULL) {
+ else 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);
+ if (obj == NULL) {
+ return -1;
}
+ #if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP)
+ long_value = PyLong_AsLongLong(obj);
+ #else
+ long_value = PyLong_AsLong(obj);
+ #endif
+ 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,"");
+ PyErr_SetString(PyExc_TypeError, msg);
+ return -1;
+ }
+ /* 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;
+ }
}
finish:
- if error_converting(long_value) {
+ if (error_converting(long_value)) {
+ err = PyErr_Occurred();
+ /* Only replace TypeError's here, which are the normal errors. */
+ if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) {
PyErr_SetString(PyExc_TypeError, msg);
- return -1;
}
+ return -1;
+ }
-#if (NPY_SIZEOF_LONGLONG > NPY_SIZEOF_INTP)
+ overflow_check:
+#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;
+ return long_value;
}
-/*NUMPY_API
- * PyArray_IntpFromSequence
+
+/*
+ * PyArray_IntpFromIndexSequence
* Returns the number of dimensions or -1 if an error occurred.
- * vals must be large enough to hold maxvals
+ * vals must be large enough to hold maxvals.
+ * Opposed to PyArray_IntpFromSequence it uses and returns npy_intp
+ * for the number of values.
*/
-NPY_NO_EXPORT int
-PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals)
+NPY_NO_EXPORT npy_intp
+PyArray_IntpFromIndexSequence(PyObject *seq, npy_intp *vals, npy_intp maxvals)
{
- int nd, i;
+ Py_ssize_t nd;
+ npy_intp i;
PyObject *op, *err;
/*
* Check to see if sequence is a single integer first.
* or, can be made into one
*/
- if ((nd=PySequence_Length(seq)) == -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;
+ nd = PySequence_Length(seq);
+ if (nd == -1) {
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
}
-#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 &&
- PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) {
+ if (err &&
+ PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) {
PyErr_SetString(PyExc_ValueError,
"Maximum allowed dimension exceeded");
}
@@ -901,6 +874,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,21 +882,13 @@ 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)) {
+ if (err &&
+ PyErr_GivenExceptionMatches(err, PyExc_OverflowError)) {
PyErr_SetString(PyExc_ValueError,
"Maximum allowed dimension exceeded");
}
@@ -935,6 +901,18 @@ PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals)
return nd;
}
+/*NUMPY_API
+ * PyArray_IntpFromSequence
+ * Returns the number of integers converted or -1 if an error occurred.
+ * vals must be large enough to hold maxvals
+ */
+NPY_NO_EXPORT int
+PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals)
+{
+ return PyArray_IntpFromIndexSequence(seq, vals, (npy_intp)maxvals);
+}
+
+
/**
* WARNING: This flag is a bad idea, but was the only way to both
* 1) Support unpickling legacy pickles with object types.
diff --git a/numpy/core/src/multiarray/conversion_utils.h b/numpy/core/src/multiarray/conversion_utils.h
index baa110e90..cc16cd9c7 100644
--- a/numpy/core/src/multiarray/conversion_utils.h
+++ b/numpy/core/src/multiarray/conversion_utils.h
@@ -25,6 +25,9 @@ PyArray_PyIntAsInt(PyObject *o);
NPY_NO_EXPORT npy_intp
PyArray_PyIntAsIntp(PyObject *o);
+NPY_NO_EXPORT npy_intp
+PyArray_IntpFromIndexSequence(PyObject *seq, npy_intp *vals, npy_intp maxvals);
+
NPY_NO_EXPORT int
PyArray_IntpFromSequence(PyObject *seq, npy_intp *vals, int maxvals);
diff --git a/numpy/core/src/multiarray/iterators.c b/numpy/core/src/multiarray/iterators.c
index abaff6c98..4584d0c60 100644
--- a/numpy/core/src/multiarray/iterators.c
+++ b/numpy/core/src/multiarray/iterators.c
@@ -70,12 +70,6 @@ parse_index_entry(PyObject *op, npy_intp *step_size,
}
*n_steps = SINGLE_INDEX;
*step_size = 0;
- if (!PyIndex_Check_Or_Unsupported(op)) {
- if (DEPRECATE("non-integer scalar index. In a future numpy "
- "release, this will raise an error.") < 0) {
- goto fail;
- }
- }
if (check_index) {
if (check_and_adjust_index(&i, max, axis) < 0) {
goto fail;
@@ -204,26 +198,8 @@ parse_index(PyArrayObject *self, PyObject *op,
static int
slice_coerce_index(PyObject *o, npy_intp *v)
{
- /*
- * PyNumber_Index was introduced in Python 2.5 because of NumPy.
- * http://www.python.org/dev/peps/pep-0357/
- * Let's use it for indexing!
- *
- * Unfortunately, SciPy and possibly other code seems to rely
- * on the lenient coercion. :(
- */
-#if 0 /*PY_VERSION_HEX >= 0x02050000*/
- PyObject *ind = PyNumber_Index(o);
- if (ind != NULL) {
- *v = PyArray_PyIntAsIntp(ind);
- Py_DECREF(ind);
- }
- else {
- *v = -1;
- }
-#else
*v = PyArray_PyIntAsIntp(o);
-#endif
+
if ((*v) == -1 && PyErr_Occurred()) {
PyErr_Clear();
return 0;
@@ -231,24 +207,6 @@ slice_coerce_index(PyObject *o, npy_intp *v)
return 1;
}
-/*
- * Issue a DeprecationWarning for slice parameters that do not pass a
- * PyIndex_Check, returning -1 if an error occurs.
- *
- * N.B. This function, like slice_GetIndices, will be obsolete once
- * non-integer slice parameters becomes an error rather than a warning.
- */
-static NPY_INLINE int
-_validate_slice_parameter(PyObject *o)
-{
- if (!PyIndex_Check_Or_Unsupported(o)) {
- if (DEPRECATE("non-integer slice parameter. In a future numpy "
- "release, this will raise an error.") < 0) {
- return -1;
- }
- }
- return 0;
-}
/*
* This is basically PySlice_GetIndicesEx, but with our coercion
@@ -268,9 +226,6 @@ slice_GetIndices(PySliceObject *r, npy_intp length,
*step = 1;
}
else {
- if (_validate_slice_parameter(r->step) < 0) {
- return -1;
- }
if (!slice_coerce_index(r->step, step)) {
return -1;
}
@@ -286,9 +241,6 @@ slice_GetIndices(PySliceObject *r, npy_intp length,
*start = *step < 0 ? length-1 : 0;
}
else {
- if (_validate_slice_parameter(r->start) < 0) {
- return -1;
- }
if (!slice_coerce_index(r->start, start)) {
return -1;
}
@@ -307,9 +259,6 @@ slice_GetIndices(PySliceObject *r, npy_intp length,
*stop = defstop;
}
else {
- if (_validate_slice_parameter(r->stop) < 0) {
- return -1;
- }
if (!slice_coerce_index(r->stop, stop)) {
return -1;
}
diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c
index 17089761d..21874f8a9 100644
--- a/numpy/core/src/multiarray/mapping.c
+++ b/numpy/core/src/multiarray/mapping.c
@@ -560,33 +560,17 @@ array_subscript_simple(PyArrayObject *self, PyObject *op, int check_index)
PyArrayObject *ret;
npy_intp value;
- /*
- * PyNumber_Index was introduced in Python 2.5 because of NumPy.
- * http://www.python.org/dev/peps/pep-0357/
- * Let's use it for indexing!
- *
- * Unfortunately, SciPy and possibly other code seems to rely
- * on the lenient coercion. :(
- */
if (!(PyArray_Check(op) && (PyArray_SIZE((PyArrayObject*)op) > 1))) {
-#if 0 /*PY_VERSION_HEX >= 0x02050000*/
- PyObject *ind = PyNumber_Index(op);
- if (ind != NULL) {
- value = PyArray_PyIntAsIntp(ind);
- Py_DECREF(ind);
- }
- else {
- value = -1;
- }
-#else
value = PyArray_PyIntAsIntp(op);
-#endif
+
if (value == -1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
/* Operand is not an integer type */
PyErr_Clear();
}
else {
+ PyErr_SetString(PyExc_IndexError,
+ "cannot convert index to integer");
return NULL;
}
}
@@ -940,7 +924,6 @@ _is_full_index(PyObject *ind, PyArrayObject *arr)
* Returns 0 if tuple-object seq is not a tuple of integers.
* If the return value is positive, vals will be filled with the elements
* from the tuple.
- * Returns -1 on error.
*/
static int
_tuple_of_integers(PyObject *seq, npy_intp *vals, int maxvals)
@@ -960,12 +943,6 @@ _tuple_of_integers(PyObject *seq, npy_intp *vals, int maxvals)
PyErr_Clear();
return 0;
}
- if (!PyIndex_Check_Or_Unsupported(obj)) {
- if (DEPRECATE("non-integer scalar index. In a future numpy "
- "release, this will raise an error.") < 0) {
- return -1;
- }
- }
vals[i] = temp;
}
return 1;
@@ -1070,11 +1047,8 @@ array_subscript_fromobject(PyArrayObject *self, PyObject *op)
/* optimization for a tuple of integers */
if (PyArray_NDIM(self) > 1 && _is_full_index(op, self)) {
int ret = _tuple_of_integers(op, vals, PyArray_NDIM(self));
- /* In case an exception occurred (e.g. in PyErr_WarnEx) */
- if (ret < 0) {
- return NULL;
- }
- else if (ret > 0) {
+
+ if (ret > 0) {
int idim, ndim = PyArray_NDIM(self);
npy_intp *shape = PyArray_DIMS(self);
npy_intp *strides = PyArray_STRIDES(self);
@@ -1090,14 +1064,6 @@ array_subscript_fromobject(PyArrayObject *self, PyObject *op)
}
}
- if ((PyNumber_Check(op) || PyArray_IsScalar(op, Number)) &&
- !PyIndex_Check_Or_Unsupported(op)) {
- if (DEPRECATE("non-integer scalar index. In a future numpy "
- "release, this will raise an error.") < 0) {
- return NULL;
- }
- }
-
/* Check for single field access */
if (PyString_Check(op) || PyUnicode_Check(op)) {
PyObject *temp, *obj;
@@ -1472,11 +1438,8 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
/* Integer-tuple index */
if (_is_full_index(ind, self)) {
int ret = _tuple_of_integers(ind, vals, PyArray_NDIM(self));
- /* In case an exception occurred (e.g. in PyErr_WarnEx) */
- if (ret < 0) {
- return -1;
- }
- else if (ret > 0) {
+
+ if (ret > 0) {
int idim, ndim = PyArray_NDIM(self);
npy_intp *shape = PyArray_DIMS(self);
npy_intp *strides = PyArray_STRIDES(self);
diff --git a/numpy/core/src/multiarray/number.c b/numpy/core/src/multiarray/number.c
index c37a232f4..9e13d0f29 100644
--- a/numpy/core/src/multiarray/number.c
+++ b/numpy/core/src/multiarray/number.c
@@ -840,6 +840,12 @@ array_index(PyArrayObject *v)
"one element can be converted to an index");
return NULL;
}
+ if (PyArray_NDIM(v) != 0) {
+ if (DEPRECATE("converting an array with ndim > 0 to an index"
+ " will result in an error in the future") < 0) {
+ return NULL;
+ }
+ }
return PyArray_DESCR(v)->f->getitem(PyArray_DATA(v), v);
}
#endif
diff --git a/numpy/core/src/private/npy_pycompat.h b/numpy/core/src/private/npy_pycompat.h
index 2c76d68f4..8f596e75a 100644
--- a/numpy/core/src/private/npy_pycompat.h
+++ b/numpy/core/src/private/npy_pycompat.h
@@ -13,16 +13,4 @@
#define Py_SIZE(o) (((PyVarObject*)(o))->ob_size)
#endif
-/*
- * PyIndex_Check
- */
-#if (PY_VERSION_HEX < 0x02050000)
-#undef PyIndex_Check
-#define PyIndex_Check(o) 0
-#undef PyIndex_Check_Or_Unsupported
-#define PyIndex_Check_Or_Unsupported(o) 1
-#else
-#define PyIndex_Check_Or_Unsupported(o) PyIndex_Check(o)
-#endif
-
#endif /* _NPY_COMPAT_H_ */
diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py
index 9b77a1fc1..2bedbca09 100644
--- a/numpy/core/tests/test_deprecations.py
+++ b/numpy/core/tests/test_deprecations.py
@@ -6,6 +6,7 @@ to document how deprecations should eventually be turned into errors.
from __future__ import division, absolute_import, print_function
import sys
+import operator
import warnings
from nose.plugins.skip import SkipTest
@@ -13,58 +14,117 @@ import numpy as np
from numpy.testing import dec, run_module_suite, assert_raises
-def assert_deprecated(f, *args, **kwargs):
- """Check if DeprecationWarning raised as error.
+class _DeprecationTestCase(object):
+ # Just as warning: warnings uses re.match, so the start of this message
+ # must match.
+ message = ''
- The warning environment is assumed to have been set up so that the
- appropriate DeprecationWarning has been turned into an error. We do not
- use assert_warns here as the desire is to check that an error will be
- raised if the deprecation is changed to an error and there may be other
- errors that would override a warning. It is a fine point as to which
- error should appear first.
-
- Parameters
- ----------
- f : callable
- A function that will exhibit the deprecation. It need not be
- deprecated itself, but can be used to execute deprecated code.
-
- """
- assert_raises(DeprecationWarning, f, *args, **kwargs)
-
-
-def assert_not_deprecated(f, *args, **kwargs):
- """Check that DeprecationWarning not raised as error.
-
- The warning environment is assumed to have been set up so that the
- appropriate DeprecationWarning has been turned into an error. This
- function checks that no warning is raised when `f` is executed.
-
- Parameters
- ----------
- f : callable
- A function that will exhibit no deprecation. It can be used to
- execute code that should not raise DeprecationWarning.
+ def setUp(self):
+ self.warn_ctx = warnings.catch_warnings(record=True)
+ self.log = self.warn_ctx.__enter__()
- """
- try:
- f(*args, **kwargs)
- except DeprecationWarning:
- raise AssertionError()
+ # Do *not* ignore other DeprecationWarnings. Ignoring warnings
+ # can give very confusing results because of
+ # http://bugs.python.org/issue4180 and it is probably simplest to
+ # try to keep the tests cleanly giving only the right warning type.
+ # (While checking them set to "error" those are ignored anyway)
+ # We still have them show up, because otherwise they would be raised
+ warnings.filterwarnings("always", category=DeprecationWarning)
+ warnings.filterwarnings("always", message=self.message,
+ category=DeprecationWarning)
-class TestFloatScalarIndexDeprecation(object):
+ def tearDown(self):
+ self.warn_ctx.__exit__()
+
+
+ def assert_deprecated(self, function, num=1, ignore_others=False,
+ function_fails=False,
+ exceptions=(DeprecationWarning,), args=(), kwargs={}):
+ """Test if DeprecationWarnings are given and raised.
+
+ This first checks if the function when called gives `num`
+ DeprecationWarnings, after that it tries to raise these
+ DeprecationWarnings and compares them with `exceptions`.
+ The exceptions can be different for cases where this code path
+ is simply not anticipated and the exception is replaced.
+
+ Parameters
+ ----------
+ f : callable
+ The function to test
+ num : int
+ Number of DeprecationWarnings to expect. This should normally be 1.
+ ignore_other : bool
+ Whether warnings of the wrong type should be ignored (note that
+ the message is not checked)
+ function_fails : bool
+ If the function would normally fail, setting this will check for
+ warnings inside a try/except block.
+ exceptions : Exception or tuple of Exceptions
+ Exception to expect when turning the warnings into an error.
+ The default checks for DeprecationWarnings. If exceptions is
+ empty the function is expected to run successfull.
+ args : tuple
+ Arguments for `f`
+ kwargs : dict
+ Keyword arguments for `f`
+ """
+ # reset the log
+ self.log[:] = []
+
+ try:
+ function(*args, **kwargs)
+ except (Exception if function_fails else tuple()):
+ pass
+ # just in case, clear the registry
+ num_found = 0
+ for warning in self.log:
+ if warning.category is DeprecationWarning:
+ num_found += 1
+ elif not ignore_others:
+ raise AssertionError("expected DeprecationWarning but %s given"
+ % warning.category)
+ if num_found != num:
+ raise AssertionError("%i warnings found but %i expected"
+ % (len(self.log), num))
+
+ with warnings.catch_warnings():
+ warnings.filterwarnings("error", message=self.message,
+ category=DeprecationWarning)
+
+ try:
+ function(*args, **kwargs)
+ if exceptions != tuple():
+ raise AssertionError("No error raised during function call")
+ except exceptions:
+ if exceptions == tuple():
+ raise AssertionError("Error raised during function call")
+
+
+ def assert_not_deprecated(self, function, args=(), kwargs={}):
+ """Test if DeprecationWarnings are given and raised.
+
+ This is just a shorthand for:
+
+ self.assert_deprecated(function, num=0, ignore_others=True,
+ exceptions=tuple(), args=args, kwargs=kwargs)
+ """
+ self.assert_deprecated(function, num=0, ignore_others=True,
+ exceptions=tuple(), args=args, kwargs=kwargs)
+
+
+class TestFloatNonIntegerArgumentDeprecation(_DeprecationTestCase):
"""
- These test that ``DeprecationWarning`` gets raised when you try to use
- scalar indices that are not integers e.g. ``a[0.0]``, ``a[1.5, 0]``.
-
- grep "non-integer scalar" numpy/core/src/multiarray/* for all the calls
- to ``DEPRECATE()``, except the one inside ``_validate_slice_parameter``
- which handles slicing (but see also
- `TestFloatSliceParameterDeprecation`).
+ These test that ``DeprecationWarning`` is given when you try to use
+ non-integers as arguments to for indexing and slicing e.g. ``a[0.0:5]``
+ and ``a[0.5]``, or other functions like ``array.reshape(1., -1)``.
- When 2.4 support is dropped ``PyIndex_Check_Or_Unsupported`` should be
- removed from ``npy_pycompat.h`` and changed to just ``PyIndex_Check``.
+ After deprecation, changes need to be done inside conversion_utils.c
+ in PyArray_PyIntAsIntp and possibly PyArray_IntpConverter.
+ In iterators.c the function slice_GetIndices could be removed in favor
+ of its python equivalent and in mapping.c the function _tuple_of_integers
+ can be simplified (if ``np.array([1]).__index__()`` is also deprecated).
As for the deprecation time-frame: via Ralf Gommers,
@@ -72,31 +132,26 @@ class TestFloatScalarIndexDeprecation(object):
version after 1.8 will be 6 months or 2 years after. I'd say 2
years is reasonable."
- I interpret this to mean 2 years after the 1.8 release.
+ I interpret this to mean 2 years after the 1.8 release. Possibly
+ giving a PendingDeprecationWarning before that (which is visible
+ by default)
"""
+ message = "using a non-integer number instead of an integer " \
+ "will result in an error in the future"
- def setUp(self):
- warnings.filterwarnings("error", message="non-integer scalar index",
- category=DeprecationWarning)
-
-
- def tearDown(self):
- warnings.filterwarnings("default", message="non-integer scalar index",
- category=DeprecationWarning)
-
-
- def test_deprecations(self):
+ def test_indexing(self):
a = np.array([[[5]]])
+ def assert_deprecated(*args, **kwargs):
+ self.assert_deprecated(*args, exceptions=(IndexError,), **kwargs)
assert_deprecated(lambda: a[0.0])
- assert_deprecated(lambda: a[0.0])
assert_deprecated(lambda: a[0, 0.0])
assert_deprecated(lambda: a[0.0, 0])
assert_deprecated(lambda: a[0.0, :])
assert_deprecated(lambda: a[:, 0.0])
assert_deprecated(lambda: a[:, 0.0, :])
- assert_deprecated(lambda: a[0.0, :, :])
+ assert_deprecated(lambda: a[0.0, :, :], num=2) # [1]
assert_deprecated(lambda: a[0, 0, 0.0])
assert_deprecated(lambda: a[0.0, 0, 0])
assert_deprecated(lambda: a[0, 0.0, 0])
@@ -106,18 +161,21 @@ class TestFloatScalarIndexDeprecation(object):
assert_deprecated(lambda: a[-1.4, :])
assert_deprecated(lambda: a[:, -1.4])
assert_deprecated(lambda: a[:, -1.4, :])
- assert_deprecated(lambda: a[-1.4, :, :])
+ assert_deprecated(lambda: a[-1.4, :, :], num=2) # [1]
assert_deprecated(lambda: a[0, 0, -1.4])
assert_deprecated(lambda: a[-1.4, 0, 0])
assert_deprecated(lambda: a[0, -1.4, 0])
+ # [1] These are duplicate because of the _tuple_of_integers quick check
+
# Test that the slice parameter deprecation warning doesn't mask
# the scalar index warning.
- assert_deprecated(lambda: a[0.0:, 0.0])
- assert_deprecated(lambda: a[0.0:, 0.0, :])
+ assert_deprecated(lambda: a[0.0:, 0.0], num=2)
+ assert_deprecated(lambda: a[0.0:, 0.0, :], num=2)
- def test_valid_not_deprecated(self):
+ def test_valid_indexing(self):
a = np.array([[[5]]])
+ assert_not_deprecated = self.assert_not_deprecated
assert_not_deprecated(lambda: a[np.array([0])])
assert_not_deprecated(lambda: a[[0, 0]])
@@ -126,40 +184,10 @@ class TestFloatScalarIndexDeprecation(object):
assert_not_deprecated(lambda: a[:, :, :])
-class TestFloatSliceParameterDeprecation(object):
- """
- These test that ``DeprecationWarning`` gets raised when you try to use
- non-integers for slicing, e.g. ``a[0.0:5]``, ``a[::1.5]``, etc.
-
- When this is changed to an error, ``slice_GetIndices`` and
- ``_validate_slice_parameter`` should probably be removed. Calls to
- ``slice_GetIndices`` should be replaced by the standard Python API call
- ``PySlice_GetIndicesEx``, since ``slice_GetIndices`` implements the
- same thing but with int coercion and Python < 2.3 backwards
- compatibility (which we have long since dropped as of this writing).
-
- As for the deprecation time-frame: via Ralf Gommers,
-
- "Hard to put that as a version number, since we don't know if the
- version after 1.8 will be 6 months or 2 years after. I'd say 2 years is
- reasonable."
-
- I interpret this to mean 2 years after the 1.8 release.
-
- """
-
- def setUp(self):
- warnings.filterwarnings("error", message="non-integer slice param",
- category=DeprecationWarning)
-
-
- def tearDown(self):
- warnings.filterwarnings("default", message="non-integer slice param",
- category=DeprecationWarning)
-
-
- def test_deprecations(self):
+ def test_slicing(self):
a = np.array([[5]])
+ def assert_deprecated(*args, **kwargs):
+ self.assert_deprecated(*args, exceptions=(IndexError,), **kwargs)
# start as float.
assert_deprecated(lambda: a[0.0:])
@@ -180,18 +208,19 @@ class TestFloatSliceParameterDeprecation(object):
assert_deprecated(lambda: a[::5.0, :])
assert_deprecated(lambda: a[:, 0:4:2.0])
# mixed.
- assert_deprecated(lambda: a[1.0:2:2.0])
- assert_deprecated(lambda: a[1.0::2.0])
- assert_deprecated(lambda: a[0:, :2.0:2.0])
- assert_deprecated(lambda: a[1.0:1:4.0, :0])
- assert_deprecated(lambda: a[1.0:5.0:5.0, :])
- assert_deprecated(lambda: a[:, 0.4:4.0:2.0])
+ assert_deprecated(lambda: a[1.0:2:2.0], num=2)
+ assert_deprecated(lambda: a[1.0::2.0], num=2)
+ assert_deprecated(lambda: a[0:, :2.0:2.0], num=2)
+ assert_deprecated(lambda: a[1.0:1:4.0, :0], num=2)
+ assert_deprecated(lambda: a[1.0:5.0:5.0, :], num=3)
+ assert_deprecated(lambda: a[:, 0.4:4.0:2.0], num=3)
# should still get the DeprecationWarning if step = 0.
- assert_deprecated(lambda: a[::0.0])
+ assert_deprecated(lambda: a[::0.0], function_fails=True)
- def test_valid_not_deprecated(self):
+ def test_valid_slicing(self):
a = np.array([[[5]]])
+ assert_not_deprecated = self.assert_not_deprecated
assert_not_deprecated(lambda: a[::])
assert_not_deprecated(lambda: a[0:])
@@ -203,5 +232,61 @@ class TestFloatSliceParameterDeprecation(object):
assert_not_deprecated(lambda: a[1:2:2])
+ def test_non_integer_argument_deprecations(self):
+ a = np.array([[5]])
+
+ self.assert_deprecated(np.reshape, args=(a, (1., 1., -1)), num=2)
+ self.assert_deprecated(np.reshape, args=(a, (np.array(1.), -1)))
+ self.assert_deprecated(np.take, args=(a, [0], 1.))
+ self.assert_deprecated(np.take, args=(a, [0], np.float64(1.)))
+
+
+class TestBooleanArgumentDeprecation(_DeprecationTestCase):
+ """This tests that using a boolean as integer argument/indexing is
+ deprecated.
+
+ This should be kept in sync with TestFloatNonIntegerArgumentDeprecation
+ and like it is handled in PyArray_PyIntAsIntp.
+ """
+ message = "using a boolean instead of an integer " \
+ "will result in an error in the future"
+
+ def test_bool_as_int_argument(self):
+ a = np.array([[[1]]])
+
+ self.assert_deprecated(np.reshape, args=(a, (True, -1)))
+ self.assert_deprecated(np.reshape, args=(a, (np.bool_(True), -1)))
+ # Note that operator.index(np.array(True)) does not work, a boolean
+ # array is thus also deprecated, but not with the same message:
+ assert_raises(TypeError, operator.index, np.array(True))
+ self.assert_deprecated(np.take, args=(a, [0], False))
+ self.assert_deprecated(lambda: a[False:True:True], exceptions=IndexError, num=3)
+ self.assert_deprecated(lambda: a[False,0], exceptions=IndexError)
+ self.assert_deprecated(lambda: a[False,0,0], exceptions=IndexError)
+
+
+class TestArrayToIndexDeprecation(_DeprecationTestCase):
+ """This tests that creating an an index from an array is deprecated
+ if the array is not 0d.
+
+ This can probably be deprecated somewhat faster then the integer
+ deprecations. The deprecation period started with NumPy 1.8.
+ For deprecation this needs changing of array_index in number.c
+ """
+ message = "converting an array with ndim \> 0 to an index will result " \
+ "in an error in the future"
+
+ def test_array_to_index_deprecation(self):
+ # This drops into the non-integer deprecation, which is ignored here,
+ # so no exception is expected. The raising is effectively tested above.
+ a = np.array([[[1]]])
+
+ self.assert_deprecated(operator.index, args=(np.array([1]),))
+ self.assert_deprecated(np.reshape, args=(a, (a, -1)), exceptions=())
+ self.assert_deprecated(np.take, args=(a, [0], a), exceptions=())
+ # Check slicing. Normal indexing checks arrays specifically.
+ self.assert_deprecated(lambda: a[a:a:a], exceptions=(), num=3)
+
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py
index 0a81a70d0..6d498b81f 100644
--- a/numpy/core/tests/test_indexing.py
+++ b/numpy/core/tests/test_indexing.py
@@ -73,8 +73,9 @@ class TestIndexing(TestCase):
[7, 8, 9]])
# Python boolean converts to integer
- assert_equal(a[True], a[1])
- assert_equal(a[False], a[0])
+ # These are being deprecated (and test in test_deprecations)
+ #assert_equal(a[True], a[1])
+ #assert_equal(a[False], a[0])
# Same with NumPy boolean scalar
assert_equal(a[np.array(True)], a[1])
diff --git a/numpy/lib/index_tricks.py b/numpy/lib/index_tricks.py
index b3c9b72bc..ca3d60869 100644
--- a/numpy/lib/index_tricks.py
+++ b/numpy/lib/index_tricks.py
@@ -157,7 +157,7 @@ class nd_grid(object):
size.append(int(abs(step)))
typ = float
else:
- size.append(math.ceil((key[k].stop - start)/(step*1.0)))
+ size.append(int(math.ceil((key[k].stop - start)/(step*1.0))))
if isinstance(step, float) or \
isinstance(start, float) or \
isinstance(key[k].stop, float):
diff --git a/numpy/lib/shape_base.py b/numpy/lib/shape_base.py
index e81bae5fc..c63f8140d 100644
--- a/numpy/lib/shape_base.py
+++ b/numpy/lib/shape_base.py
@@ -830,5 +830,5 @@ def tile(A, reps):
dim_in = shape[i]
dim_out = dim_in*nrep
shape[i] = dim_out
- n /= max(dim_in,1)
+ n //= max(dim_in, 1)
return c.reshape(shape)
diff --git a/numpy/random/tests/test_regression.py b/numpy/random/tests/test_regression.py
index 9f7455fe5..1bba5d91d 100644
--- a/numpy/random/tests/test_regression.py
+++ b/numpy/random/tests/test_regression.py
@@ -72,7 +72,7 @@ class TestRegression(TestCase):
np.random.seed(i)
m.seed(4321)
# If m.state is not honored, the result will change
- assert_array_equal(m.choice(10, size=10, p=np.ones(10.)/10), res)
+ assert_array_equal(m.choice(10, size=10, p=np.ones(10)/10.), res)
def test_multivariate_normal_size_types(self):
# Test for multivariate_normal issue with 'size' argument.