summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2015-09-10 12:02:38 -0600
committerCharles Harris <charlesr.harris@gmail.com>2015-09-10 12:02:38 -0600
commit0b0206c1617841ed2e5324de752ee8ede2cce791 (patch)
treee06fbf8d42e288be9ca5f205884acc0381f867ee
parent438cdd3d75a0bb606e7ab7f96e59744c9b78d748 (diff)
parentdbe5cef95dcaa3c48dad1093084b7d2b65cf889b (diff)
downloadnumpy-0b0206c1617841ed2e5324de752ee8ede2cce791.tar.gz
Merge pull request #6271 from charris/change-deprecated-indexes-to-error
DEP,MAINT: Change deprecated indexing to errors.
-rw-r--r--doc/release/1.11.0-notes.rst14
-rw-r--r--numpy/core/src/multiarray/conversion_utils.c94
-rw-r--r--numpy/core/src/multiarray/mapping.c126
-rw-r--r--numpy/core/src/multiarray/number.c13
-rw-r--r--numpy/core/tests/test_deprecations.py231
-rw-r--r--numpy/core/tests/test_indexing.py243
-rw-r--r--numpy/lib/tests/test_function_base.py18
7 files changed, 259 insertions, 480 deletions
diff --git a/doc/release/1.11.0-notes.rst b/doc/release/1.11.0-notes.rst
index 33bc24e30..9afe6e866 100644
--- a/doc/release/1.11.0-notes.rst
+++ b/doc/release/1.11.0-notes.rst
@@ -20,6 +20,20 @@ Future Changes:
Compatibility notes
===================
+Deprecated to error
+~~~~~~~~~~~~~~~~~~~
+
+* Indexing with floats raises IndexError,
+ e.g., a[0, 0.0].
+* Indexing with non-integer array_like raises IndexError,
+ e.g., a['1', '2']
+* Indexing with multiple ellipsis raises IndexError,
+ e.g., a[..., ...].
+* Indexing with boolean where integer expected raises IndexError,
+ e.g., a[False:True:True].
+* Non-integers used as index values raise TypeError,
+ e.g., in reshape, take, and specifying reduce axis.
+
New Features
============
diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c
index 3b9a10da5..88064c1d6 100644
--- a/numpy/core/src/multiarray/conversion_utils.c
+++ b/numpy/core/src/multiarray/conversion_utils.c
@@ -777,20 +777,16 @@ PyArray_PyIntAsIntp_ErrMsg(PyObject *o, const char * msg)
#endif
PyObject *obj, *err;
- if (!o) {
+ /*
+ * Be a bit stricter and not allow bools.
+ * np.bool_ is also disallowed as Boolean arrays do not currently
+ * support index.
+ */
+ if (!o || PyBool_Check(o) || PyArray_IsScalar(o, Bool)) {
PyErr_SetString(PyExc_TypeError, msg);
return -1;
}
- /* Be a bit stricter and not allow bools, np.bool_ is handled later */
- if (PyBool_Check(o)) {
- /* 2013-04-13, 1.8 */
- if (DEPRECATE("using a boolean instead of an integer"
- " will result in an error in the future") < 0) {
- return -1;
- }
- }
-
/*
* Since it is the usual case, first check if o is an integer. This is
* an exact check, since otherwise __index__ is used.
@@ -816,84 +812,22 @@ PyArray_PyIntAsIntp_ErrMsg(PyObject *o, const char * msg)
return (npy_intp)long_value;
}
- /* Disallow numpy.bool_. Boolean arrays do not currently support index. */
- if (PyArray_IsScalar(o, Bool)) {
- /* 2013-06-09, 1.8 */
- if (DEPRECATE("using a boolean instead of an integer"
- " will result in an error in the future") < 0) {
- return -1;
- }
- }
-
/*
* 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 (obj == NULL) {
+ return -1;
+ }
#if (NPY_SIZEOF_LONG < NPY_SIZEOF_INTP)
- long_value = PyLong_AsLongLong(obj);
+ long_value = PyLong_AsLongLong(obj);
#else
- long_value = PyLong_AsLong(obj);
+ 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();
- }
+ Py_DECREF(obj);
- /*
- * 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;
- }
- #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)
- 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;
- }
- #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_TypeError, msg);
- return -1;
- }
- /* Give a deprecation warning, unless there was already an error */
- if (!error_converting(long_value)) {
- /* 2013-04-13, 1.8 */
- 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)) {
err = PyErr_Occurred();
/* Only replace TypeError's here, which are the normal errors. */
@@ -902,9 +836,9 @@ PyArray_PyIntAsIntp_ErrMsg(PyObject *o, const char * msg)
}
return -1;
}
-
goto overflow_check; /* silence unused warning */
- overflow_check:
+
+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)) {
diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c
index b6e831498..42a12db14 100644
--- a/numpy/core/src/multiarray/mapping.c
+++ b/numpy/core/src/multiarray/mapping.c
@@ -285,35 +285,13 @@ prepare_index(PyArrayObject *self, PyObject *index,
/* Index is an ellipsis (`...`) */
if (obj == Py_Ellipsis) {
- /*
- * If there is more then one Ellipsis, it is replaced. Deprecated,
- * since it is hard to imagine anyone using two Ellipsis and
- * actually planning on all but the first being automatically
- * replaced with a slice.
- */
+ /* At most one ellipsis in an index */
if (index_type & HAS_ELLIPSIS) {
- /* 2013-04-14, 1.8 */
- if (DEPRECATE(
- "an index can only have a single Ellipsis (`...`); "
- "replace all but one with slices (`:`).") < 0) {
- goto failed_building_indices;
- }
- index_type |= HAS_SLICE;
-
- indices[curr_idx].type = HAS_SLICE;
- indices[curr_idx].object = PySlice_New(NULL, NULL, NULL);
-
- if (indices[curr_idx].object == NULL) {
- goto failed_building_indices;
- }
-
- used_ndim += 1;
- new_ndim += 1;
- curr_idx += 1;
- continue;
+ PyErr_Format(PyExc_IndexError,
+ "an index can only have a single ellipsis ('...')");
+ goto failed_building_indices;
}
index_type |= HAS_ELLIPSIS;
-
indices[curr_idx].type = HAS_ELLIPSIS;
indices[curr_idx].object = NULL;
/* number of slices it is worth, won't update if it is 0: */
@@ -415,102 +393,8 @@ prepare_index(PyArrayObject *self, PyObject *index,
goto failed_building_indices;
}
}
- /*
- * Special case to allow 0-d boolean indexing with
- * scalars. Should be removed after boolean-array
- * like as integer-array like deprecation.
- * (does not cover ufunc.at, because it does not use the
- * boolean special case, but that should not matter...)
- * Since all but strictly boolean indices are invalid,
- * there is no need for any further conversion tries.
- */
- else if (PyArray_NDIM(self) == 0) {
- arr = tmp_arr;
- }
else {
- /*
- * These Checks can be removed after deprecation, since
- * they should then be either correct already or error out
- * later just like a normal array.
- */
- if (PyArray_ISBOOL(tmp_arr)) {
- /* 2013-04-14, 1.8 */
- if (DEPRECATE_FUTUREWARNING(
- "in the future, boolean array-likes will be "
- "handled as a boolean array index") < 0) {
- Py_DECREF(tmp_arr);
- goto failed_building_indices;
- }
- if (PyArray_NDIM(tmp_arr) == 0) {
- /*
- * Need to raise an error here, since the
- * DeprecationWarning before was not triggered.
- * TODO: A `False` triggers a Deprecation *not* a
- * a FutureWarning.
- */
- PyErr_SetString(PyExc_IndexError,
- "in the future, 0-d boolean arrays will be "
- "interpreted as a valid boolean index");
- Py_DECREF(tmp_arr);
- goto failed_building_indices;
- }
- else {
- arr = tmp_arr;
- }
- }
- /*
- * Note: Down the road, the integers will be cast to intp.
- * The user has to make sure they can be safely cast.
- * If not, we might index wrong instead of an giving
- * an error.
- */
- else if (!PyArray_ISINTEGER(tmp_arr)) {
- if (PyArray_NDIM(tmp_arr) == 0) {
- /* match integer deprecation warning */
- /* 2013-09-25, 1.8 */
- if (DEPRECATE(
- "using a non-integer number instead of an "
- "integer will result in an error in the "
- "future") < 0) {
-
- /* The error message raised in the future */
- PyErr_SetString(PyExc_IndexError,
- "only integers, slices (`:`), ellipsis (`...`), "
- "numpy.newaxis (`None`) and integer or boolean "
- "arrays are valid indices");
- Py_DECREF((PyObject *)tmp_arr);
- goto failed_building_indices;
- }
- }
- else {
- /* 2013-09-25, 1.8 */
- if (DEPRECATE(
- "non integer (and non boolean) array-likes "
- "will not be accepted as indices in the "
- "future") < 0) {
-
- /* Error message to be raised in the future */
- PyErr_SetString(PyExc_IndexError,
- "non integer (and non boolean) array-likes will "
- "not be accepted as indices in the future");
- Py_DECREF((PyObject *)tmp_arr);
- goto failed_building_indices;
- }
- }
- }
-
- arr = (PyArrayObject *)PyArray_FromArray(tmp_arr,
- PyArray_DescrFromType(NPY_INTP),
- NPY_ARRAY_FORCECAST);
-
- if (arr == NULL) {
- /* Since this will be removed, handle this later */
- PyErr_Clear();
- arr = tmp_arr;
- }
- else {
- Py_DECREF((PyObject *)tmp_arr);
- }
+ arr = tmp_arr;
}
}
else {
diff --git a/numpy/core/src/multiarray/number.c b/numpy/core/src/multiarray/number.c
index 953a84eef..fec015a30 100644
--- a/numpy/core/src/multiarray/number.c
+++ b/numpy/core/src/multiarray/number.c
@@ -1025,18 +1025,11 @@ _array_copy_nice(PyArrayObject *self)
static PyObject *
array_index(PyArrayObject *v)
{
- if (!PyArray_ISINTEGER(v) || PyArray_SIZE(v) != 1) {
- PyErr_SetString(PyExc_TypeError, "only integer arrays with " \
- "one element can be converted to an index");
+ if (!PyArray_ISINTEGER(v) || PyArray_NDIM(v) != 0) {
+ PyErr_SetString(PyExc_TypeError,
+ "only integer scalar arrays can be converted to a scalar index");
return NULL;
}
- if (PyArray_NDIM(v) != 0) {
- /* 2013-04-20, 1.8 */
- 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);
}
diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py
index 8ec0f5e7f..3e76409c5 100644
--- a/numpy/core/tests/test_deprecations.py
+++ b/numpy/core/tests/test_deprecations.py
@@ -115,237 +115,6 @@ class _DeprecationTestCase(object):
exceptions=tuple(), args=args, kwargs=kwargs)
-class TestFloatNonIntegerArgumentDeprecation(_DeprecationTestCase):
- """
- 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)``.
-
- 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,
-
- "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. 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 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.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, 0.0])
- assert_deprecated(lambda: a[0.0, 0, 0])
- assert_deprecated(lambda: a[0, 0.0, 0])
- assert_deprecated(lambda: a[-1.4])
- assert_deprecated(lambda: a[0, -1.4])
- assert_deprecated(lambda: a[-1.4, 0])
- 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[0, 0, -1.4])
- assert_deprecated(lambda: a[-1.4, 0, 0])
- assert_deprecated(lambda: a[0, -1.4, 0])
-
- # Test that the slice parameter deprecation warning doesn't mask
- # the scalar index warning.
- assert_deprecated(lambda: a[0.0:, 0.0], num=2)
- assert_deprecated(lambda: a[0.0:, 0.0,:], num=2)
-
- 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]])
- assert_not_deprecated(lambda: a[:, [0, 0]])
- assert_not_deprecated(lambda: a[:, 0,:])
- assert_not_deprecated(lambda: a[:,:,:])
-
- 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:])
- assert_deprecated(lambda: a[0:, 0.0:2])
- assert_deprecated(lambda: a[0.0::2, :0])
- assert_deprecated(lambda: a[0.0:1:2,:])
- assert_deprecated(lambda: a[:, 0.0:])
- # stop as float.
- assert_deprecated(lambda: a[:0.0])
- assert_deprecated(lambda: a[:0, 1:2.0])
- assert_deprecated(lambda: a[:0.0:2, :0])
- assert_deprecated(lambda: a[:0.0,:])
- assert_deprecated(lambda: a[:, 0:4.0:2])
- # step as float.
- assert_deprecated(lambda: a[::1.0])
- assert_deprecated(lambda: a[0:, :2:2.0])
- assert_deprecated(lambda: a[1::4.0, :0])
- assert_deprecated(lambda: a[::5.0,:])
- assert_deprecated(lambda: a[:, 0:4:2.0])
- # mixed.
- 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], function_fails=True)
-
- 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:])
- assert_not_deprecated(lambda: a[:2])
- assert_not_deprecated(lambda: a[0:2])
- assert_not_deprecated(lambda: a[::2])
- assert_not_deprecated(lambda: a[1::2])
- assert_not_deprecated(lambda: a[:2:2])
- 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.)))
-
- def test_non_integer_sequence_multiplication(self):
- # Numpy scalar sequence multiply should not work with non-integers
- def mult(a, b):
- return a * b
-
- self.assert_deprecated(mult, args=([1], np.float_(3)))
- self.assert_not_deprecated(mult, args=([1], np.int_(3)))
-
- def test_reduce_axis_float_index(self):
- d = np.zeros((3,3,3))
- self.assert_deprecated(np.min, args=(d, 0.5))
- self.assert_deprecated(np.min, num=1, args=(d, (0.5, 1)))
- self.assert_deprecated(np.min, num=1, args=(d, (1, 2.2)))
- self.assert_deprecated(np.min, num=2, args=(d, (.2, 1.2)))
-
-
-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)
-
-class TestNonIntegerArrayLike(_DeprecationTestCase):
- """Tests that array likes, i.e. lists give a deprecation warning
- when they cannot be safely cast to an integer.
- """
- message = "non integer \(and non boolean\) array-likes will not be " \
- "accepted as indices in the future"
-
- def test_basic(self):
- a = np.arange(10)
- self.assert_deprecated(a.__getitem__, args=([0.5, 1.5],),
- exceptions=IndexError)
- self.assert_deprecated(a.__getitem__, args=((['1', '2'],),),
- exceptions=IndexError)
-
- self.assert_not_deprecated(a.__getitem__, ([],))
-
- def test_boolean_futurewarning(self):
- a = np.arange(10)
- with warnings.catch_warnings():
- warnings.filterwarnings('always')
- assert_warns(FutureWarning, a.__getitem__, [True])
- # Unfortunatly, the deprecation warning takes precedence:
- #assert_warns(FutureWarning, a.__getitem__, True)
-
- with warnings.catch_warnings():
- warnings.filterwarnings('error')
- assert_raises(FutureWarning, a.__getitem__, [True])
- #assert_raises(FutureWarning, a.__getitem__, True)
-
-
-class TestMultipleEllipsisDeprecation(_DeprecationTestCase):
- message = "an index can only have a single Ellipsis \(`...`\); replace " \
- "all but one with slices \(`:`\)."
-
- def test_basic(self):
- a = np.arange(10)
- self.assert_deprecated(a.__getitem__, args=((Ellipsis, Ellipsis),))
-
- with warnings.catch_warnings():
- warnings.filterwarnings('ignore', '', DeprecationWarning)
- # Just check that this works:
- b = a[...,...]
- assert_array_equal(a, b)
- assert_raises(IndexError, a.__getitem__, ((Ellipsis, ) * 3,))
-
-
class TestBooleanUnaryMinusDeprecation(_DeprecationTestCase):
"""Test deprecation of unary boolean `-`. While + and * are well
defined, unary - is not and even a corrected form seems to have
diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py
index 4bc937e0b..38280d05e 100644
--- a/numpy/core/tests/test_indexing.py
+++ b/numpy/core/tests/test_indexing.py
@@ -3,6 +3,7 @@ from __future__ import division, absolute_import, print_function
import sys
import warnings
import functools
+import operator
import numpy as np
from numpy.core.multiarray_tests import array_indexing
@@ -21,6 +22,69 @@ except ImportError:
class TestIndexing(TestCase):
+ def test_index_no_floats(self):
+ a = np.array([[[5]]])
+
+ assert_raises(IndexError, lambda: a[0.0])
+ assert_raises(IndexError, lambda: a[0, 0.0])
+ assert_raises(IndexError, lambda: a[0.0, 0])
+ assert_raises(IndexError, lambda: a[0.0,:])
+ assert_raises(IndexError, lambda: a[:, 0.0])
+ assert_raises(IndexError, lambda: a[:, 0.0,:])
+ assert_raises(IndexError, lambda: a[0.0,:,:])
+ assert_raises(IndexError, lambda: a[0, 0, 0.0])
+ assert_raises(IndexError, lambda: a[0.0, 0, 0])
+ assert_raises(IndexError, lambda: a[0, 0.0, 0])
+ assert_raises(IndexError, lambda: a[-1.4])
+ assert_raises(IndexError, lambda: a[0, -1.4])
+ assert_raises(IndexError, lambda: a[-1.4, 0])
+ assert_raises(IndexError, lambda: a[-1.4,:])
+ assert_raises(IndexError, lambda: a[:, -1.4])
+ assert_raises(IndexError, lambda: a[:, -1.4,:])
+ assert_raises(IndexError, lambda: a[-1.4,:,:])
+ assert_raises(IndexError, lambda: a[0, 0, -1.4])
+ assert_raises(IndexError, lambda: a[-1.4, 0, 0])
+ assert_raises(IndexError, lambda: a[0, -1.4, 0])
+ assert_raises(IndexError, lambda: a[0.0:, 0.0])
+ assert_raises(IndexError, lambda: a[0.0:, 0.0,:])
+
+ def test_slicing_no_floats(self):
+ a = np.array([[5]])
+
+ # start as float.
+ assert_raises(IndexError, lambda: a[0.0:])
+ assert_raises(IndexError, lambda: a[0:, 0.0:2])
+ assert_raises(IndexError, lambda: a[0.0::2, :0])
+ assert_raises(IndexError, lambda: a[0.0:1:2,:])
+ assert_raises(IndexError, lambda: a[:, 0.0:])
+ # stop as float.
+ assert_raises(IndexError, lambda: a[:0.0])
+ assert_raises(IndexError, lambda: a[:0, 1:2.0])
+ assert_raises(IndexError, lambda: a[:0.0:2, :0])
+ assert_raises(IndexError, lambda: a[:0.0,:])
+ assert_raises(IndexError, lambda: a[:, 0:4.0:2])
+ # step as float.
+ assert_raises(IndexError, lambda: a[::1.0])
+ assert_raises(IndexError, lambda: a[0:, :2:2.0])
+ assert_raises(IndexError, lambda: a[1::4.0, :0])
+ assert_raises(IndexError, lambda: a[::5.0,:])
+ assert_raises(IndexError, lambda: a[:, 0:4:2.0])
+ # mixed.
+ assert_raises(IndexError, lambda: a[1.0:2:2.0])
+ assert_raises(IndexError, lambda: a[1.0::2.0])
+ assert_raises(IndexError, lambda: a[0:, :2.0:2.0])
+ assert_raises(IndexError, lambda: a[1.0:1:4.0, :0])
+ assert_raises(IndexError, lambda: a[1.0:5.0:5.0,:])
+ assert_raises(IndexError, lambda: a[:, 0.4:4.0:2.0])
+ # should still get the DeprecationWarning if step = 0.
+ assert_raises(IndexError, lambda: a[::0.0])
+
+ def test_index_no_array_to_index(self):
+ # No non-scalar arrays.
+ a = np.array([[[1]]])
+
+ assert_raises(IndexError, lambda: a[a:a:a])
+
def test_none_index(self):
# `None` index adds newaxis
a = np.array([1, 2, 3])
@@ -35,19 +99,9 @@ class TestIndexing(TestCase):
a = np.array(0)
assert_(isinstance(a[()], np.int_))
- # Regression, it needs to fall through integer and fancy indexing
- # cases, so need the with statement to ignore the non-integer error.
- with warnings.catch_warnings():
- warnings.filterwarnings('ignore', '', DeprecationWarning)
- a = np.array([1.])
- assert_(isinstance(a[0.], np.float_))
-
- a = np.array([np.array(1)], dtype=object)
- assert_(isinstance(a[0.], np.ndarray))
-
def test_same_kind_index_casting(self):
- # Indexes should be cast with same-kind and not safe, even if
- # that is somewhat unsafe. So test various different code paths.
+ # Indexes should be cast with same-kind and not safe, even if that
+ # is somewhat unsafe. So test various different code paths.
index = np.arange(5)
u_index = index.astype(np.uintp)
arr = np.arange(10)
@@ -85,7 +139,8 @@ class TestIndexing(TestCase):
[4, 5, 6],
[7, 8, 9]])
assert_equal(a[...], a)
- assert_(a[...].base is a) # `a[...]` was `a` in numpy <1.9.)
+ # `a[...]` was `a` in numpy <1.9.
+ assert_(a[...].base is a)
# Slicing with ellipsis can skip an
# arbitrary number of dimensions
@@ -645,7 +700,8 @@ class TestMultiIndexingAutomated(TestCase):
np.zeros([1]*31, dtype=int), # trigger too large array.
np.array([0., 1.])] # invalid datatype
# Some simpler indices that still cover a bit more
- self.simple_indices = [Ellipsis, None, -1, [1], np.array([True]), 'skip']
+ self.simple_indices = [Ellipsis, None, -1, [1], np.array([True]),
+ 'skip']
# Very simple ones to fill the rest:
self.fill_indices = [slice(None, None), 0]
@@ -719,16 +775,18 @@ class TestMultiIndexingAutomated(TestCase):
indx = np.array(indx, dtype=np.intp)
in_indices[i] = indx
elif indx.dtype.kind != 'b' and indx.dtype.kind != 'i':
- raise IndexError('arrays used as indices must be of integer (or boolean) type')
+ raise IndexError('arrays used as indices must be of '
+ 'integer (or boolean) type')
if indx.ndim != 0:
no_copy = False
ndim += 1
fancy_dim += 1
if arr.ndim - ndim < 0:
- # we can't take more dimensions then we have, not even for 0-d arrays.
- # since a[()] makes sense, but not a[(),]. We will raise an error
- # later on, unless a broadcasting error occurs first.
+ # we can't take more dimensions then we have, not even for 0-d
+ # arrays. since a[()] makes sense, but not a[(),]. We will
+ # raise an error later on, unless a broadcasting error occurs
+ # first.
raise IndexError
if ndim == 0 and None not in in_indices:
@@ -736,7 +794,8 @@ class TestMultiIndexingAutomated(TestCase):
return arr.copy(), no_copy
if ellipsis_pos is not None:
- in_indices[ellipsis_pos:ellipsis_pos+1] = [slice(None, None)] * (arr.ndim - ndim)
+ in_indices[ellipsis_pos:ellipsis_pos+1] = ([slice(None, None)] *
+ (arr.ndim - ndim))
for ax, indx in enumerate(in_indices):
if isinstance(indx, slice):
@@ -779,21 +838,23 @@ class TestMultiIndexingAutomated(TestCase):
if indx >= arr.shape[ax] or indx < -arr.shape[ax]:
raise IndexError
if indx.ndim == 0:
- # The index is a scalar. This used to be two fold, but if fancy
- # indexing was active, the check was done later, possibly
- # after broadcasting it away (1.7. or earlier). Now it is always
- # done.
+ # The index is a scalar. This used to be two fold, but if
+ # fancy indexing was active, the check was done later,
+ # possibly after broadcasting it away (1.7. or earlier).
+ # Now it is always done.
if indx >= arr.shape[ax] or indx < - arr.shape[ax]:
raise IndexError
- if len(indices) > 0 and indices[-1][0] == 'f' and ax != ellipsis_pos:
+ if (len(indices) > 0 and
+ indices[-1][0] == 'f' and
+ ax != ellipsis_pos):
# NOTE: There could still have been a 0-sized Ellipsis
# between them. Checked that with ellipsis_pos.
indices[-1].append(indx)
else:
# We have a fancy index that is not after an existing one.
- # NOTE: A 0-d array triggers this as well, while
- # one may expect it to not trigger it, since a scalar
- # would not be considered fancy indexing.
+ # NOTE: A 0-d array triggers this as well, while one may
+ # expect it to not trigger it, since a scalar would not be
+ # considered fancy indexing.
num_fancy += 1
indices.append(['f', indx])
@@ -854,13 +915,15 @@ class TestMultiIndexingAutomated(TestCase):
# Work around for a crash or IndexError with 'wrap'
# in some 0-sized cases.
try:
- mi = np.ravel_multi_index(indx[1:], orig_slice, mode='raise')
+ mi = np.ravel_multi_index(indx[1:], orig_slice,
+ mode='raise')
except:
# This happens with 0-sized orig_slice (sometimes?)
# here it is a ValueError, but indexing gives a:
raise IndexError('invalid index into 0-sized')
else:
- mi = np.ravel_multi_index(indx[1:], orig_slice, mode='wrap')
+ mi = np.ravel_multi_index(indx[1:], orig_slice,
+ mode='wrap')
else:
# Maybe never happens...
raise ValueError
@@ -962,9 +1025,12 @@ class TestMultiIndexingAutomated(TestCase):
# it is aligned to the left. This is probably correct for
# consistency with arr[boolean_array,] also no broadcasting
# is done at all
- self._check_multi_index(self.a, (np.zeros_like(self.a, dtype=bool),))
- self._check_multi_index(self.a, (np.zeros_like(self.a, dtype=bool)[..., 0],))
- self._check_multi_index(self.a, (np.zeros_like(self.a, dtype=bool)[None, ...],))
+ self._check_multi_index(
+ self.a, (np.zeros_like(self.a, dtype=bool),))
+ self._check_multi_index(
+ self.a, (np.zeros_like(self.a, dtype=bool)[..., 0],))
+ self._check_multi_index(
+ self.a, (np.zeros_like(self.a, dtype=bool)[None, ...],))
def test_multidim(self):
# Automatically test combinations with complex indexes on 2nd (or 1st)
@@ -1003,6 +1069,119 @@ class TestMultiIndexingAutomated(TestCase):
for index in self.complex_indices:
self._check_single_index(a, index)
+class TestFloatNonIntegerArgument(TestCase):
+ """
+ These test that ``TypeError`` is raised 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)``.
+
+ """
+ def test_valid_indexing(self):
+ # These should raise no errors.
+ a = np.array([[[5]]])
+
+ a[np.array([0])]
+ a[[0, 0]]
+ a[:, [0, 0]]
+ a[:, 0,:]
+ a[:,:,:]
+
+ def test_valid_slicing(self):
+ # These should raise no errors.
+ a = np.array([[[5]]])
+
+ a[::]
+ a[0:]
+ a[:2]
+ a[0:2]
+ a[::2]
+ a[1::2]
+ a[:2:2]
+ a[1:2:2]
+
+ def test_non_integer_argument_errors(self):
+ a = np.array([[5]])
+
+ assert_raises(TypeError, np.reshape, a, (1., 1., -1))
+ assert_raises(TypeError, np.reshape, a, (np.array(1.), -1))
+ assert_raises(TypeError, np.take, a, [0], 1.)
+ assert_raises(TypeError, np.take, a, [0], np.float64(1.))
+
+ def test_non_integer_sequence_multiplication(self):
+ # Numpy scalar sequence multiply should not work with non-integers
+ def mult(a, b):
+ return a * b
+
+ assert_raises(TypeError, mult, [1], np.float_(3))
+ # following should be OK
+ mult([1], np.int_(3))
+
+ def test_reduce_axis_float_index(self):
+ d = np.zeros((3,3,3))
+ assert_raises(TypeError, np.min, d, 0.5)
+ assert_raises(TypeError, np.min, d, (0.5, 1))
+ assert_raises(TypeError, np.min, d, (1, 2.2))
+ assert_raises(TypeError, np.min, d, (.2, 1.2))
+
+
+class TestBooleanArgumentErrors(TestCase):
+ """Using a boolean as integer argument/indexing is an error.
+
+ """
+ def test_bool_as_int_argument(self):
+ a = np.array([[[1]]])
+
+ assert_raises(TypeError, np.reshape, a, (True, -1))
+ assert_raises(TypeError, np.reshape, 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))
+ assert_raises(TypeError, np.take, args=(a, [0], False))
+ assert_raises(IndexError, lambda: a[False:True:True])
+ assert_raises(IndexError, lambda: a[False, 0])
+ assert_raises(IndexError, lambda: a[False, 0, 0])
+
+
+class TestArrayToIndexDeprecation(TestCase):
+ """Creating an an index from array not 0-D is an error.
+
+ """
+ def test_array_to_index_error(self):
+ # so no exception is expected. The raising is effectively tested above.
+ a = np.array([[[1]]])
+
+ assert_raises(TypeError, operator.index, np.array([1]))
+ assert_raises(TypeError, np.reshape, a, (a, -1))
+ assert_raises(TypeError, np.take, a, [0], a)
+
+
+class TestNonIntegerArrayLike(TestCase):
+ """Tests that array_likes only valid if can safely cast to integer.
+
+ For instance, lists give IndexError when they cannot be safely cast to
+ an integer.
+
+ """
+ def test_basic(self):
+ a = np.arange(10)
+
+ assert_raises(IndexError, a.__getitem__, [0.5, 1.5])
+ assert_raises(IndexError, a.__getitem__, (['1', '2'],))
+
+ # The following is valid
+ a.__getitem__([])
+
+
+class TestMultipleEllipsisError(TestCase):
+ """An index can only have a single ellipsis.
+
+ """
+ def test_basic(self):
+ a = np.arange(10)
+ assert_raises(IndexError, lambda: a[..., ...])
+ assert_raises(IndexError, a.__getitem__, ((Ellipsis,) * 2,))
+ assert_raises(IndexError, a.__getitem__, ((Ellipsis,) * 3,))
+
class TestCApiAccess(TestCase):
def test_getitem(self):
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py
index 6a9d76a27..5e758fb89 100644
--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -1913,19 +1913,25 @@ class TestBincount(TestCase):
def test_with_incorrect_minlength(self):
x = np.array([], dtype=int)
- assert_raises_regex(TypeError, "an integer is required",
+ assert_raises_regex(TypeError,
+ "'str' object cannot be interpreted",
lambda: np.bincount(x, minlength="foobar"))
- assert_raises_regex(ValueError, "must be positive",
+ assert_raises_regex(ValueError,
+ "must be positive",
lambda: np.bincount(x, minlength=-1))
- assert_raises_regex(ValueError, "must be positive",
+ assert_raises_regex(ValueError,
+ "must be positive",
lambda: np.bincount(x, minlength=0))
x = np.arange(5)
- assert_raises_regex(TypeError, "an integer is required",
+ assert_raises_regex(TypeError,
+ "'str' object cannot be interpreted",
lambda: np.bincount(x, minlength="foobar"))
- assert_raises_regex(ValueError, "minlength must be positive",
+ assert_raises_regex(ValueError,
+ "minlength must be positive",
lambda: np.bincount(x, minlength=-1))
- assert_raises_regex(ValueError, "minlength must be positive",
+ assert_raises_regex(ValueError,
+ "minlength must be positive",
lambda: np.bincount(x, minlength=0))