Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Index error info #296

Merged
merged 4 commits into from

2 participants

@thouis
Owner

Adds a check_and_adjust_index function in common.c that is used to verify indices and adjust them for negative indexing. Invalid indexes produce an IndexError, and the function returns -1. Otherwise, the index is adjusted in-place (for negative indices), and the function returns 0.

The IndexError produced by this function includes information about the invalid value, the array axis where it caused a problem, and the valid range (when this information is available).

Nearly all such indexing adjustment and validation in the numpy source have been replaced by calls to this function, and a few cases of ValueError in indexing have been replaced by IndexError for consistency.

A couple of open questions:

  • In arraytypes.c.src:...fasttake(), there's no way to know the axis in the call to check_and_adjust_index(), so it can't report the axis in the case of an invalid index. Adding an argument to fasttake would allow it to be reported. I wasn't sure this was an acceptable change.

  • In cases of operations that implicitly operate on a flattened array, the IndexError reports that bad indices are out of bound on axis=0, which might be confusing in some cases. One solution would be to add an argument to check_and_adjust_index() indicating whether the array being indexed was 1-dimensional, and not report an axis in this case.

thouis added some commits
@thouis thouis ENH: report bad value and dimenion to IndexError exceptions 4c68a33
@thouis thouis Add check_and_adjust_index(), and replace most index checks with it.
This commit adds a check_and_adjust_index(npy_intp *index, npy_intp max, int axis) function
which checks index against max, setting an IndexError and returning -1 if it's not valid,
and otherwise adjusting index in-place to handle Python's negative indexing, and returning 0.

It also changes most places in the code where indexes were being checked and adjusted with a
call to this function.
56f8659
@thouis thouis Add coverage tests for IndexErrors, fix one bug, clean up two checks
Adds numpy/core/tests/test_indexerrors.py with tests to cover failure cases in indexing not covered
by other tests.

Added a missing check for invalid index in multiarray/iterators.c:iter_ass_sub_int().
Used the new checking code in multiarray/iterators.c:iter_ass_subscript().
Changed a ValueError to an IndexError in multiarray/mapping.c:PyArray_MapIterBind().
330468f
@thouis thouis commented on the diff
numpy/core/src/multiarray/common.c
@@ -506,6 +506,47 @@
return descr;
}
+NPY_NO_EXPORT int
+check_and_adjust_index(npy_intp *index, npy_intp max_item, int axis)
+{
+ /* Check that index is valid, taking into account negative indices */
+ if ((*index < -max_item) || (*index >= max_item)) {
+ /* Try to be as clear as possible about what went wrong. */
+ if (axis >= 0) {
@thouis Owner
thouis added a note

This should be a check against a constant, like NPY_CHECK_UNKNOWN_AXIS (#def'd to -1). That might also allow some future extensions like NPY_CHECK_FLATTENED_AXIS, to allow more informative reports in the case of indexing an implicitly flattened array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@njsmith
Owner

I was going to tweak the error messages as per mailing list discussion and then go ahead and merge this, but something is horribly broken on Python 2.4 (only).

>>> np.arange(3)[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
IndexError: index 91358524231122944 is out of bounds for axis 0 with size 3

This is on 64-bit Linux. Some sort of 32-bit/64-bit sign extension problem maybe?

@thouis
Owner
@thouis
Owner

Fixed. I was able to reproduce it on my Mac. I don't think the signature of array_item_nice() should be changed, as it's exported to Python.

@njsmith
Owner

Right, that would do it...

@njsmith njsmith merged commit a83e212 into numpy:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 6, 2012
  1. @thouis
  2. @thouis

    Add check_and_adjust_index(), and replace most index checks with it.

    thouis authored
    This commit adds a check_and_adjust_index(npy_intp *index, npy_intp max, int axis) function
    which checks index against max, setting an IndexError and returning -1 if it's not valid,
    and otherwise adjusting index in-place to handle Python's negative indexing, and returning 0.
    
    It also changes most places in the code where indexes were being checked and adjusted with a
    call to this function.
  3. @thouis

    Add coverage tests for IndexErrors, fix one bug, clean up two checks

    thouis authored
    Adds numpy/core/tests/test_indexerrors.py with tests to cover failure cases in indexing not covered
    by other tests.
    
    Added a missing check for invalid index in multiarray/iterators.c:iter_ass_sub_int().
    Used the new checking code in multiarray/iterators.c:iter_ass_subscript().
    Changed a ValueError to an IndexError in multiarray/mapping.c:PyArray_MapIterBind().
Commits on Jun 15, 2012
  1. @thouis
This page is out of date. Refresh to see the latest.
View
9 numpy/core/src/multiarray/arraytypes.c.src
@@ -3527,14 +3527,9 @@ static int
for (i = 0; i < n_outer; i++) {
for (j = 0; j < m_middle; j++) {
tmp = indarray[j];
- if (tmp < 0) {
- tmp = tmp + nindarray;
- }
- if ((tmp < 0) || (tmp >= nindarray)) {
- PyErr_SetString(PyExc_IndexError,
- "index out of range for array");
+ /* We don't know what axis we're operating on, so don't report it in case of an error. */
+ if (check_and_adjust_index(&tmp, nindarray, -1) < 0)
return 1;
- }
if (nelem == 1) {
*dest++ = *(src + tmp);
}
View
54 numpy/core/src/multiarray/common.c
@@ -506,6 +506,47 @@ _array_typedescr_fromstr(char *c_str)
return descr;
}
+NPY_NO_EXPORT int
+check_and_adjust_index(npy_intp *index, npy_intp max_item, int axis)
+{
+ /* Check that index is valid, taking into account negative indices */
+ if ((*index < -max_item) || (*index >= max_item)) {
+ /* Try to be as clear as possible about what went wrong. */
+ if (axis >= 0) {
@thouis Owner
thouis added a note

This should be a check against a constant, like NPY_CHECK_UNKNOWN_AXIS (#def'd to -1). That might also allow some future extensions like NPY_CHECK_FLATTENED_AXIS, to allow more informative reports in the case of indexing an implicitly flattened array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ if (max_item > 0) {
+ PyErr_Format(PyExc_IndexError,
+ "index %"NPY_INTP_FMT" is out of bounds for axis %d: "
+ "[%"NPY_INTP_FMT",%"NPY_INTP_FMT")",
+ *index, axis,
+ -max_item, max_item);
+ } else {
+ PyErr_Format(PyExc_IndexError,
+ "index %"NPY_INTP_FMT" is out of bounds for 0-d axis %d",
+ *index, axis);
+ }
+ } else {
+ if (max_item > 0) {
+ PyErr_Format(PyExc_IndexError,
+ "index %"NPY_INTP_FMT" is out of bounds: "
+ "[%"NPY_INTP_FMT",%"NPY_INTP_FMT")",
+ *index,
+ -max_item, max_item);
+ } else {
+ /* I don't believe there are currently any cases where this occurs. */
+ PyErr_Format(PyExc_IndexError,
+ "index %"NPY_INTP_FMT" is out of bounds for 0-d axis",
+ *index);
+ }
+ }
+ return -1;
+ }
+ /* adjust negative indices */
+ if (*index < 0) {
+ *index += max_item;
+ }
+ return 0;
+}
+
NPY_NO_EXPORT char *
index2ptr(PyArrayObject *mp, npy_intp i)
{
@@ -516,17 +557,12 @@ index2ptr(PyArrayObject *mp, npy_intp i)
return NULL;
}
dim0 = PyArray_DIMS(mp)[0];
- if (i < 0) {
- i += dim0;
- }
- if (i == 0 && dim0 > 0) {
+ if (check_and_adjust_index(&i, dim0, 0) < 0)
+ return NULL;
+ if (i == 0) {
return PyArray_DATA(mp);
}
- if (i > 0 && i < dim0) {
- return PyArray_DATA(mp)+i*PyArray_STRIDES(mp)[0];
- }
- PyErr_SetString(PyExc_IndexError,"index out of bounds");
- return NULL;
+ return PyArray_DATA(mp)+i*PyArray_STRIDES(mp)[0];
}
NPY_NO_EXPORT int
View
9 numpy/core/src/multiarray/common.h
@@ -41,6 +41,15 @@ _array_find_python_scalar_type(PyObject *op);
NPY_NO_EXPORT PyArray_Descr *
_array_typedescr_fromstr(char *str);
+/*
+ * Returns -1 and sets an exception if *index is an invalid index for
+ * an array of size max_item, otherwise adjusts it in place to be
+ * 0 <= *index < max_item, and returns 0.
+ * If axis >= 0, it will be reported as part of the exception.
+ */
+NPY_NO_EXPORT int
+check_and_adjust_index(npy_intp *index, npy_intp max_item, int axis);
+
NPY_NO_EXPORT char *
index2ptr(PyArrayObject *mp, npy_intp i);
View
3  numpy/core/src/multiarray/ctors.c
@@ -2925,6 +2925,7 @@ PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags)
{
PyObject *temp1, *temp2;
int n = PyArray_NDIM(arr);
+ int axis_orig = *axis;
if (*axis == NPY_MAXDIMS || n == 0) {
if (n != 1) {
@@ -2967,7 +2968,7 @@ PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags)
}
if ((*axis < 0) || (*axis >= n)) {
PyErr_Format(PyExc_ValueError,
- "axis(=%d) out of bounds", *axis);
+ "axis(=%d) out of bounds", axis_orig);
Py_DECREF(temp2);
return NULL;
}
View
3  numpy/core/src/multiarray/descriptor.c
@@ -3383,6 +3383,7 @@ descr_subscript(PyArray_Descr *self, PyObject *op)
PyObject *name;
int size = PyTuple_GET_SIZE(self->names);
int value = PyArray_PyIntAsInt(op);
+ int orig_value = value;
if (PyErr_Occurred()) {
return NULL;
@@ -3392,7 +3393,7 @@ descr_subscript(PyArray_Descr *self, PyObject *op)
}
if (value < 0 || value >= size) {
PyErr_Format(PyExc_IndexError,
- "Field index out of range.");
+ "Field index %d out of range.", orig_value);
return NULL;
}
name = PyTuple_GET_ITEM(self->names, value);
View
62 numpy/core/src/multiarray/item_selection.c
@@ -174,12 +174,7 @@ PyArray_TakeFrom(PyArrayObject *self0, PyObject *indices0, int axis,
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++) {
tmp = ((npy_intp *)(PyArray_DATA(indices)))[j];
- if (tmp < 0) {
- tmp = tmp + max_item;
- }
- if ((tmp < 0) || (tmp >= max_item)) {
- PyErr_SetString(PyExc_IndexError,
- "index out of range for array");
+ if (check_and_adjust_index(&tmp, max_item, axis) < 0) {
NPY_AUXDATA_FREE(transferdata);
goto fail;
}
@@ -252,13 +247,7 @@ PyArray_TakeFrom(PyArrayObject *self0, PyObject *indices0, int axis,
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++) {
tmp = ((npy_intp *)(PyArray_DATA(indices)))[j];
- if (tmp < 0) {
- tmp = tmp + max_item;
- }
- if ((tmp < 0) || (tmp >= max_item)) {
- PyErr_SetString(PyExc_IndexError,
- "index out of range "\
- "for array");
+ if (check_and_adjust_index(&tmp, max_item, axis) < 0) {
goto fail;
}
memmove(dest, src + tmp*chunk, chunk);
@@ -389,13 +378,7 @@ PyArray_PutTo(PyArrayObject *self, PyObject* values0, PyObject *indices0,
for (i = 0; i < ni; i++) {
src = PyArray_DATA(values) + chunk*(i % nv);
tmp = ((npy_intp *)(PyArray_DATA(indices)))[i];
- if (tmp < 0) {
- tmp = tmp + max_item;
- }
- if ((tmp < 0) || (tmp >= max_item)) {
- PyErr_SetString(PyExc_IndexError,
- "index out of " \
- "range for array");
+ if (check_and_adjust_index(&tmp, max_item, 0) < 0) {
goto fail;
}
PyArray_Item_INCREF(src, PyArray_DESCR(self));
@@ -445,13 +428,7 @@ PyArray_PutTo(PyArrayObject *self, PyObject* values0, PyObject *indices0,
for (i = 0; i < ni; i++) {
src = PyArray_DATA(values) + chunk * (i % nv);
tmp = ((npy_intp *)(PyArray_DATA(indices)))[i];
- if (tmp < 0) {
- tmp = tmp + max_item;
- }
- if ((tmp < 0) || (tmp >= max_item)) {
- PyErr_SetString(PyExc_IndexError,
- "index out of " \
- "range for array");
+ if (check_and_adjust_index(&tmp, max_item, 0) < 0) {
goto fail;
}
memmove(dest + tmp * chunk, src, chunk);
@@ -1102,6 +1079,7 @@ PyArray_Sort(PyArrayObject *op, int axis, NPY_SORTKIND which)
PyArrayObject *ap = NULL, *store_arr = NULL;
char *ip;
int i, n, m, elsize, orign;
+ int axis_orig=axis;
n = PyArray_NDIM(op);
if ((n == 0) || (PyArray_SIZE(op) == 1)) {
@@ -1111,7 +1089,7 @@ PyArray_Sort(PyArrayObject *op, int axis, NPY_SORTKIND which)
axis += n;
}
if ((axis < 0) || (axis >= n)) {
- PyErr_Format(PyExc_ValueError, "axis(=%d) out of bounds", axis);
+ PyErr_Format(PyExc_ValueError, "axis(=%d) out of bounds", axis_orig);
return -1;
}
if (!PyArray_ISWRITEABLE(op)) {
@@ -2526,12 +2504,7 @@ PyArray_MultiIndexGetItem(PyArrayObject *self, npy_intp *multi_index)
npy_intp shapevalue = shape[idim];
npy_intp ind = multi_index[idim];
- if (ind < 0) {
- ind += shapevalue;
- }
-
- if (ind < 0 || ind >= shapevalue) {
- PyErr_SetString(PyExc_ValueError, "index out of bounds");
+ if (check_and_adjust_index(&ind, shapevalue, idim) < 0) {
return NULL;
}
@@ -2555,12 +2528,7 @@ PyArray_MultiIndexGetItem(PyArrayObject *self, npy_intp *multi_index)
npy_intp shapevalue = shape[idim];
npy_intp ind = multi_index[idim];
- if (ind < 0) {
- ind += shapevalue;
- }
-
- if (ind < 0 || ind >= shapevalue) {
- PyErr_SetString(PyExc_ValueError, "index out of bounds");
+ if (check_and_adjust_index(&ind, shapevalue, idim) < 0) {
return NULL;
}
@@ -2603,12 +2571,7 @@ PyArray_MultiIndexSetItem(PyArrayObject *self, npy_intp *multi_index,
npy_intp shapevalue = shape[idim];
npy_intp ind = multi_index[idim];
- if (ind < 0) {
- ind += shapevalue;
- }
-
- if (ind < 0 || ind >= shapevalue) {
- PyErr_SetString(PyExc_ValueError, "index out of bounds");
+ if (check_and_adjust_index(&ind, shapevalue, idim) < 0) {
return -1;
}
@@ -2645,12 +2608,7 @@ PyArray_MultiIndexSetItem(PyArrayObject *self, npy_intp *multi_index,
npy_intp shapevalue = shape[idim];
npy_intp ind = multi_index[idim];
- if (ind < 0) {
- ind += shapevalue;
- }
-
- if (ind < 0 || ind >= shapevalue) {
- PyErr_SetString(PyExc_ValueError, "index out of bounds");
+ if (check_and_adjust_index(&ind, shapevalue, idim) < 0) {
return -1;
}
View
55 numpy/core/src/multiarray/iterators.c
@@ -31,7 +31,8 @@ slice_coerce_index(PyObject *o, npy_intp *v);
*/
NPY_NO_EXPORT npy_intp
parse_index_entry(PyObject *op, npy_intp *step_size,
- npy_intp *n_steps, npy_intp max)
+ npy_intp *n_steps, npy_intp max,
+ int axis, int check_index)
{
npy_intp i;
@@ -69,12 +70,10 @@ parse_index_entry(PyObject *op, npy_intp *step_size,
}
*n_steps = SINGLE_INDEX;
*step_size = 0;
- if (i < 0) {
- i += max;
- }
- if (i >= max || i < 0) {
- PyErr_SetString(PyExc_IndexError, "invalid index");
+ if (check_index) {
+ if (check_and_adjust_index(&i, max, axis) < 0) {
goto fail;
+ }
}
}
return i;
@@ -134,8 +133,9 @@ parse_index(PyArrayObject *self, PyObject *op,
}
}
start = parse_index_entry(op1, &step_size, &n_steps,
- nd_old < PyArray_NDIM(self) ?
- PyArray_DIMS(self)[nd_old] : 0);
+ nd_old < PyArray_NDIM(self) ?
+ PyArray_DIMS(self)[nd_old] : 0,
+ nd_old, nd_old < PyArray_NDIM(self));
Py_DECREF(op1);
if (start == -1) {
break;
@@ -717,14 +717,7 @@ iter_subscript_int(PyArrayIterObject *self, PyArrayObject *ind)
itemsize = PyArray_DESCR(self->ao)->elsize;
if (PyArray_NDIM(ind) == 0) {
num = *((npy_intp *)PyArray_DATA(ind));
- if (num < 0) {
- num += self->size;
- }
- if (num < 0 || num >= self->size) {
- PyErr_Format(PyExc_IndexError,
- "index %"NPY_INTP_FMT" out of bounds" \
- " 0<=index<%"NPY_INTP_FMT,
- num, self->size);
+ if (check_and_adjust_index(&num, self->size, -1) < 0) {
PyArray_ITER_RESET(self);
return NULL;
}
@@ -758,14 +751,7 @@ iter_subscript_int(PyArrayIterObject *self, PyArrayObject *ind)
swap = (PyArray_ISNOTSWAPPED(ret) != PyArray_ISNOTSWAPPED(self->ao));
while (counter--) {
num = *((npy_intp *)(ind_it->dataptr));
- if (num < 0) {
- num += self->size;
- }
- if (num < 0 || num >= self->size) {
- PyErr_Format(PyExc_IndexError,
- "index %"NPY_INTP_FMT" out of bounds" \
- " 0<=index<%"NPY_INTP_FMT,
- num, self->size);
+ if (check_and_adjust_index(&num, self->size, -1) < 0) {
Py_DECREF(ind_it);
Py_DECREF(ret);
PyArray_ITER_RESET(self);
@@ -841,7 +827,7 @@ iter_subscript(PyArrayIterObject *self, PyObject *ind)
/* Check for Integer or Slice */
if (PyLong_Check(ind) || PyInt_Check(ind) || PySlice_Check(ind)) {
start = parse_index_entry(ind, &step_size, &n_steps,
- self->size);
+ self->size, 0, 1);
if (start == -1) {
goto fail;
}
@@ -989,6 +975,9 @@ iter_ass_sub_int(PyArrayIterObject *self, PyArrayObject *ind,
copyswap = PyArray_DESCR(self->ao)->f->copyswap;
if (PyArray_NDIM(ind) == 0) {
num = *((npy_intp *)PyArray_DATA(ind));
+ if (check_and_adjust_index(&num, self->size, -1) < 0) {
+ return -1;
+ }
PyArray_ITER_GOTO1D(self, num);
copyswap(self->dataptr, val->dataptr, swap, self->ao);
return 0;
@@ -1000,14 +989,7 @@ iter_ass_sub_int(PyArrayIterObject *self, PyArrayObject *ind,
counter = ind_it->size;
while (counter--) {
num = *((npy_intp *)(ind_it->dataptr));
- if (num < 0) {
- num += self->size;
- }
- if ((num < 0) || (num >= self->size)) {
- PyErr_Format(PyExc_IndexError,
- "index %"NPY_INTP_FMT" out of bounds" \
- " 0<=index<%"NPY_INTP_FMT, num,
- self->size);
+ if (check_and_adjust_index(&num, self->size, -1) < 0) {
Py_DECREF(ind_it);
return -1;
}
@@ -1081,10 +1063,7 @@ iter_ass_subscript(PyArrayIterObject *self, PyObject *ind, PyObject *val)
PyErr_Clear();
}
else {
- if (start < -self->size || start >= self->size) {
- PyErr_Format(PyExc_ValueError,
- "index (%" NPY_INTP_FMT \
- ") out of range", start);
+ if (check_and_adjust_index(&start, self->size, -1) < 0) {
goto finish;
}
retval = 0;
@@ -1118,7 +1097,7 @@ iter_ass_subscript(PyArrayIterObject *self, PyObject *ind, PyObject *val)
/* Check Slice */
if (PySlice_Check(ind)) {
- start = parse_index_entry(ind, &step_size, &n_steps, self->size);
+ start = parse_index_entry(ind, &step_size, &n_steps, self->size, 0, 0);
if (start == -1) {
goto finish;
}
View
92 numpy/core/src/multiarray/mapping.c
@@ -57,11 +57,7 @@ array_big_item(PyArrayObject *self, npy_intp i)
/* Bounds check and get the data pointer */
dim0 = PyArray_DIM(self, 0);
- if (i < 0) {
- i += dim0;
- }
- if (i < 0 || i >= dim0) {
- PyErr_SetString(PyExc_IndexError,"index out of bounds");
+ if (check_and_adjust_index(&i, dim0, 0) < 0) {
return NULL;
}
item = PyArray_DATA(self) + i * PyArray_STRIDE(self, 0);
@@ -113,19 +109,18 @@ _array_ass_item(PyArrayObject *self, Py_ssize_t i, PyObject *v)
/* contains optimization for 1-d arrays */
NPY_NO_EXPORT PyObject *
-array_item_nice(PyArrayObject *self, Py_ssize_t i)
+array_item_nice(PyArrayObject *self, Py_ssize_t _i)
{
+ /* Workaround Python 2.4: Py_ssize_t not the same as npyint_p */
+ npy_intp i = _i;
+
if (PyArray_NDIM(self) == 1) {
char *item;
npy_intp dim0;
/* Bounds check and get the data pointer */
dim0 = PyArray_DIM(self, 0);
- if (i < 0) {
- i += dim0;
- }
- if (i < 0 || i >= dim0) {
- PyErr_SetString(PyExc_IndexError,"index out of bounds");
+ if (check_and_adjust_index(&i, dim0, 0) < 0) {
return NULL;
}
item = PyArray_DATA(self) + i * PyArray_STRIDE(self, 0);
@@ -202,11 +197,7 @@ array_ass_big_item(PyArrayObject *self, npy_intp i, PyObject *v)
/* Bounds check and get the data pointer */
dim0 = PyArray_DIM(self, 0);
- if (i < 0) {
- i += dim0;
- }
- if (i < 0 || i >= dim0) {
- PyErr_SetString(PyExc_IndexError,"index out of bounds");
+ if (check_and_adjust_index(&i, dim0, 0) < 0) {
return -1;
}
item = PyArray_DATA(self) + i * PyArray_STRIDE(self, 0);
@@ -1604,19 +1595,10 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
if (!PyArray_HASMASKNA(self)) {
for (idim = 0; idim < ndim; idim++) {
npy_intp v = vals[idim];
- if (v < 0) {
- v += shape[idim];
- }
- if (v < 0 || v >= shape[idim]) {
- PyErr_Format(PyExc_IndexError,
- "index (%"NPY_INTP_FMT") out of range "\
- "(0<=index<%"NPY_INTP_FMT") in dimension %d",
- vals[idim], PyArray_DIMS(self)[idim], idim);
+ if (check_and_adjust_index(&v, shape[idim], idim) < 0) {
return -1;
}
- else {
- item += v * strides[idim];
- }
+ item += v * strides[idim];
}
return PyArray_DESCR(self)->f->setitem(op, item, self);
}
@@ -1627,20 +1609,11 @@ array_ass_sub(PyArrayObject *self, PyObject *ind, PyObject *op)
for (idim = 0; idim < ndim; idim++) {
npy_intp v = vals[idim];
- if (v < 0) {
- v += shape[idim];
- }
- if (v < 0 || v >= shape[idim]) {
- PyErr_Format(PyExc_IndexError,
- "index (%"NPY_INTP_FMT") out of range "\
- "(0<=index<%"NPY_INTP_FMT") in dimension %d",
- vals[idim], PyArray_DIMS(self)[idim], idim);
+ if (check_and_adjust_index(&v, shape[idim], idim) < 0) {
return -1;
}
- else {
- item += v * strides[idim];
- maskna_item += v * maskna_strides[idim];
- }
+ item += v * strides[idim];
+ maskna_item += v * maskna_strides[idim];
}
na = NpyNA_FromObject(op, 1);
if (na == NULL) {
@@ -1762,19 +1735,10 @@ array_subscript_nice(PyArrayObject *self, PyObject *op)
if (!PyArray_HASMASKNA(self)) {
for (idim = 0; idim < ndim; idim++) {
npy_intp v = vals[idim];
- if (v < 0) {
- v += shape[idim];
- }
- if (v < 0 || v >= shape[idim]) {
- PyErr_Format(PyExc_IndexError,
- "index (%"NPY_INTP_FMT") out of range "\
- "(0<=index<%"NPY_INTP_FMT") in dimension %d",
- vals[idim], PyArray_DIMS(self)[idim], idim);
+ if (check_and_adjust_index(&v, shape[idim], idim) < 0) {
return NULL;
}
- else {
- item += v * strides[idim];
- }
+ item += v * strides[idim];
}
return PyArray_Scalar(item, PyArray_DESCR(self), (PyObject *)self);
}
@@ -1784,20 +1748,11 @@ array_subscript_nice(PyArrayObject *self, PyObject *op)
for (idim = 0; idim < ndim; idim++) {
npy_intp v = vals[idim];
- if (v < 0) {
- v += shape[idim];
- }
- if (v < 0 || v >= shape[idim]) {
- PyErr_Format(PyExc_IndexError,
- "index (%"NPY_INTP_FMT") out of range "\
- "(0<=index<%"NPY_INTP_FMT") in dimension %d",
- vals[idim], PyArray_DIMS(self)[idim], idim);
+ if (check_and_adjust_index(&v, shape[idim], idim) < 0) {
return NULL;
}
- else {
- item += v * strides[idim];
- maskna_item += v * maskna_strides[idim];
- }
+ item += v * strides[idim];
+ maskna_item += v * maskna_strides[idim];
}
if (NpyMaskValue_IsExposed((npy_mask)*maskna_item)) {
return PyArray_Scalar(item, PyArray_DESCR(self),
@@ -2135,7 +2090,7 @@ PyArray_MapIterBind(PyArrayMapIterObject *mit, PyArrayObject *arr)
subnd = PyArray_NDIM(arr) - mit->numiter;
if (subnd < 0) {
- PyErr_SetString(PyExc_ValueError,
+ PyErr_SetString(PyExc_IndexError,
"too many indices for array");
return;
}
@@ -2251,7 +2206,7 @@ PyArray_MapIterBind(PyArrayMapIterObject *mit, PyArrayObject *arr)
goto fail;
}
if (mit->ait->size == 0 && mit->size != 0) {
- PyErr_SetString(PyExc_ValueError,
+ PyErr_SetString(PyExc_IndexError,
"invalid index into a 0-size array");
goto fail;
}
@@ -2264,14 +2219,7 @@ PyArray_MapIterBind(PyArrayMapIterObject *mit, PyArrayObject *arr)
while (it->index < it->size) {
indptr = ((npy_intp *)it->dataptr);
indval = *indptr;
- if (indval < 0) {
- indval += dimsize;
- }
- if (indval < 0 || indval >= dimsize) {
- PyErr_Format(PyExc_IndexError,
- "index (%"NPY_INTP_FMT") out of range "\
- "(0<=index<%"NPY_INTP_FMT") in dimension %d",
- indval, (dimsize-1), mit->iteraxes[i]);
+ if (check_and_adjust_index(&indval, dimsize, mit->iteraxes[i]) < 0) {
goto fail;
}
PyArray_ITER_NEXT(it);
View
18 numpy/core/src/multiarray/methods.c
@@ -697,14 +697,7 @@ array_toscalar(PyArrayObject *self, PyObject *args)
return NULL;
}
- /* Negative indexing */
- if (value < 0) {
- value += size;
- }
-
- if (value < 0 || value >= size) {
- PyErr_SetString(PyExc_ValueError,
- "index out of bounds");
+ if (check_and_adjust_index(&value, size, -1) < 0) {
return NULL;
}
@@ -783,14 +776,7 @@ array_setscalar(PyArrayObject *self, PyObject *args)
return NULL;
}
- /* Negative indexing */
- if (value < 0) {
- value += size;
- }
-
- if (value < 0 || value >= size) {
- PyErr_SetString(PyExc_ValueError,
- "index out of bounds");
+ if (check_and_adjust_index(&value, size, -1) < 0) {
return NULL;
}
View
3  numpy/core/src/multiarray/multiarraymodule.c
@@ -320,6 +320,7 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis)
PyArrayObject *ret = NULL;
PyArrayObject_fields *sliding_view = NULL;
int has_maskna;
+ int orig_axis = axis;
if (narrays <= 0) {
PyErr_SetString(PyExc_ValueError,
@@ -342,7 +343,7 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis)
}
if (axis < 0 || axis >= ndim) {
PyErr_Format(PyExc_IndexError,
- "axis %d out of bounds [0, %d)", axis, ndim);
+ "axis %d out of bounds [0, %d)", orig_axis, ndim);
return NULL;
}
View
149 numpy/core/tests/test_indexerrors.py
@@ -0,0 +1,149 @@
+import numpy as np
+from numpy.testing import TestCase, run_module_suite, assert_raises, assert_equal, assert_
+import sys
+
+class TestIndexErrors(TestCase):
+ '''Tests to exercise indexerrors not covered by other tests.'''
+
+ def test_arraytypes_fasttake(self):
+ 'take from a 0-length dimension'
+ x = np.empty((2, 3, 0, 4))
+ assert_raises(IndexError, x.take, [0], axis=2)
+ assert_raises(IndexError, x.take, [1], axis=2)
+
+ def test_maskna_take_1D(self):
+ # Check exception taking from masked array
+ a = np.array([1, np.NA, 2, np.NA], maskna=True)
+ assert_raises(IndexError, a.take, [6])
+ a = np.array(np.NA, maskna=True)
+ assert_raises(IndexError, a.take, [6])
+
+ # Check exception taking from masked 0-d array
+ d = np.empty((5, 0), maskna=True)
+ assert_raises(IndexError, d.take, [1], axis=1)
+ assert_raises(IndexError, d.take, [0], axis=1)
+ assert_raises(IndexError, d.take, [0])
+
+ def test_take_from_object(self):
+ # Check exception taking from object array
+ d = np.zeros(5, dtype=object)
+ assert_raises(IndexError, d.take, [6])
+
+ # Check exception taking from 0-d array
+ d = np.zeros((5, 0), dtype=object)
+ assert_raises(IndexError, d.take, [1], axis=1)
+ assert_raises(IndexError, d.take, [0], axis=1)
+ assert_raises(IndexError, d.take, [0])
+
+ def test_multiindex_exceptions(self):
+ a = np.empty(5, dtype=object)
+ assert_raises(IndexError, a.item, 20)
+ a = np.empty((5, 0), dtype=object)
+ assert_raises(IndexError, a.item, (0, 0))
+ a = np.empty(5, dtype=object, maskna=True)
+ assert_raises(IndexError, a.item, 20)
+ a = np.empty((5, 0), dtype=object, maskna=True)
+ assert_raises(IndexError, a.item, (0, 0))
+
+ a = np.empty(5, dtype=object)
+ assert_raises(IndexError, a.itemset, 20, 0)
+ a = np.empty((5, 0), dtype=object)
+ assert_raises(IndexError, a.itemset, (0, 0), 0)
+ a = np.empty(5, dtype=object, maskna=True)
+ assert_raises(IndexError, a.itemset, 20, 0)
+ a = np.empty((5, 0), dtype=object, maskna=True)
+ assert_raises(IndexError, a.itemset, (0, 0), 0)
+
+ def test_put_exceptions(self):
+ a = np.zeros((5, 5))
+ assert_raises(IndexError, a.put, 100, 0)
+ a = np.zeros((5, 5), dtype=object)
+ assert_raises(IndexError, a.put, 100, 0)
+ a = np.zeros((5, 5, 0))
+ assert_raises(IndexError, a.put, 100, 0)
+ a = np.zeros((5, 5, 0), dtype=object)
+ assert_raises(IndexError, a.put, 100, 0)
+
+ def test_iterators_exceptions(self):
+ "cases in iterators.c"
+ def assign(obj, ind, val):
+ obj[ind] = val
+
+ a = np.zeros([1,2,3])
+ assert_raises(IndexError, lambda: a[0,5,None,2])
+ assert_raises(IndexError, lambda: a[0,5,0,2])
+ assert_raises(IndexError, lambda: assign(a, (0,5,None,2), 1))
+ assert_raises(IndexError, lambda: assign(a, (0,5,0,2), 1))
+
+ a = np.zeros([1,0,3])
+ assert_raises(IndexError, lambda: a[0,0,None,2])
+ assert_raises(IndexError, lambda: assign(a, (0,0,None,2), 1))
+
+ a = np.zeros([1,2,3])
+ assert_raises(IndexError, lambda: a.flat[10])
+ assert_raises(IndexError, lambda: assign(a.flat, 10, 5))
+ a = np.zeros([1,0,3])
+ assert_raises(IndexError, lambda: a.flat[10])
+ assert_raises(IndexError, lambda: assign(a.flat, 10, 5))
+
+ a = np.zeros([1,2,3])
+ assert_raises(IndexError, lambda: a.flat[np.array(10)])
+ assert_raises(IndexError, lambda: assign(a.flat, np.array(10), 5))
+ a = np.zeros([1,0,3])
+ assert_raises(IndexError, lambda: a.flat[np.array(10)])
+ assert_raises(IndexError, lambda: assign(a.flat, np.array(10), 5))
+
+ a = np.zeros([1,2,3])
+ assert_raises(IndexError, lambda: a.flat[np.array([10])])
+ assert_raises(IndexError, lambda: assign(a.flat, np.array([10]), 5))
+ a = np.zeros([1,0,3])
+ assert_raises(IndexError, lambda: a.flat[np.array([10])])
+ assert_raises(IndexError, lambda: assign(a.flat, np.array([10]), 5))
+
+ def test_mapping(self):
+ "cases from mapping.c"
+
+ def assign(obj, ind, val):
+ obj[ind] = val
+
+ a = np.zeros((0, 10))
+ assert_raises(IndexError, lambda: a[12])
+
+ a = np.zeros((3,5))
+ assert_raises(IndexError, lambda: a[(10, 20)])
+ assert_raises(IndexError, lambda: assign(a, (10, 20), 1))
+ a = np.zeros((3,0))
+ assert_raises(IndexError, lambda: a[(1, 0)])
+ assert_raises(IndexError, lambda: assign(a, (1, 0), 1))
+
+ a = np.zeros((3,5), maskna=True)
+ assert_raises(IndexError, lambda: a[(10, 20)])
+ assert_raises(IndexError, lambda: assign(a, (10, 20), 1))
+ a = np.zeros((3,0), maskna=True)
+ assert_raises(IndexError, lambda: a[(1, 0)])
+ assert_raises(IndexError, lambda: assign(a, (1, 0), 1))
+
+ a = np.zeros((10,))
+ assert_raises(IndexError, lambda: assign(a, 10, 1))
+ a = np.zeros((0,))
+ assert_raises(IndexError, lambda: assign(a, 10, 1))
+
+ a = np.zeros((3,5))
+ assert_raises(IndexError, lambda: a[(1, [1, 20])])
+ assert_raises(IndexError, lambda: assign(a, (1, [1, 20]), 1))
+ a = np.zeros((3,0))
+ assert_raises(IndexError, lambda: a[(1, [0, 1])])
+ assert_raises(IndexError, lambda: assign(a, (1, [0, 1]), 1))
+
+ def test_methods(self):
+ "cases from methods.c"
+
+ a = np.zeros((3, 3))
+ assert_raises(IndexError, lambda: a.item(100))
+ assert_raises(IndexError, lambda: a.itemset(100, 1))
+ a = np.zeros((0, 3))
+ assert_raises(IndexError, lambda: a.item(100))
+ assert_raises(IndexError, lambda: a.itemset(100, 1))
+
+if __name__ == "__main__":
+ run_module_suite()
Something went wrong with that request. Please try again.