Skip to content

Commit 564b7cb

Browse files
committed
MAINT: Use the same error message for most C code handling negative axes
1 parent b8769a2 commit 564b7cb

7 files changed

Lines changed: 36 additions & 71 deletions

File tree

‎numpy/core/src/multiarray/common.h‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,28 @@ check_and_adjust_index(npy_intp *index, npy_intp max_item, int axis,
134134
return 0;
135135
}
136136

137+
/*
138+
* Returns -1 and sets an exception if *axis is an invalid axis for
139+
* an array of dimension ndim, otherwise adjusts it in place to be
140+
* 0 <= *axis < ndim, and returns 0.
141+
*/
142+
static NPY_INLINE int
143+
check_and_adjust_axis(int *axis, int ndim)
144+
{
145+
/* Check that index is valid, taking into account negative indices */
146+
if (NPY_UNLIKELY((*axis < -ndim) || (*axis >= ndim))) {
147+
PyErr_Format(PyExc_IndexError,
148+
"axis %d is out of bounds for array of dimension %d",
149+
*axis, ndim);
150+
return -1;
151+
}
152+
/* adjust negative indices */
153+
if (*axis < 0) {
154+
*axis += ndim;
155+
}
156+
return 0;
157+
}
158+
137159

138160
/*
139161
* return true if pointer is aligned to 'alignment'

‎numpy/core/src/multiarray/conversion_utils.c‎

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -259,17 +259,10 @@ PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags)
259259
PyObject *tmp = PyTuple_GET_ITEM(axis_in, i);
260260
int axis = PyArray_PyIntAsInt_ErrMsg(tmp,
261261
"integers are required for the axis tuple elements");
262-
int axis_orig = axis;
263262
if (error_converting(axis)) {
264263
return NPY_FAIL;
265264
}
266-
if (axis < 0) {
267-
axis += ndim;
268-
}
269-
if (axis < 0 || axis >= ndim) {
270-
PyErr_Format(PyExc_ValueError,
271-
"'axis' entry %d is out of bounds [-%d, %d)",
272-
axis_orig, ndim, ndim);
265+
if (check_and_adjust_axis(&axis, ndim) < 0) {
273266
return NPY_FAIL;
274267
}
275268
if (out_axis_flags[axis]) {
@@ -284,20 +277,16 @@ PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags)
284277
}
285278
/* Try to interpret axis as an integer */
286279
else {
287-
int axis, axis_orig;
280+
int axis;
288281

289282
memset(out_axis_flags, 0, ndim);
290283

291284
axis = PyArray_PyIntAsInt_ErrMsg(axis_in,
292285
"an integer is required for the axis");
293-
axis_orig = axis;
294286

295287
if (error_converting(axis)) {
296288
return NPY_FAIL;
297289
}
298-
if (axis < 0) {
299-
axis += ndim;
300-
}
301290
/*
302291
* Special case letting axis={-1,0} slip through for scalars,
303292
* for backwards compatibility reasons.
@@ -306,10 +295,7 @@ PyArray_ConvertMultiAxis(PyObject *axis_in, int ndim, npy_bool *out_axis_flags)
306295
return NPY_SUCCEED;
307296
}
308297

309-
if (axis < 0 || axis >= ndim) {
310-
PyErr_Format(PyExc_ValueError,
311-
"'axis' entry %d is out of bounds [-%d, %d)",
312-
axis_orig, ndim, ndim);
298+
if (check_and_adjust_axis(&axis, ndim) < 0) {
313299
return NPY_FAIL;
314300
}
315301

‎numpy/core/src/multiarray/ctors.c‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,7 +2793,6 @@ PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags)
27932793
{
27942794
PyObject *temp1, *temp2;
27952795
int n = PyArray_NDIM(arr);
2796-
int axis_orig = *axis;
27972796

27982797
if (*axis == NPY_MAXDIMS || n == 0) {
27992798
if (n != 1) {
@@ -2831,12 +2830,7 @@ PyArray_CheckAxis(PyArrayObject *arr, int *axis, int flags)
28312830
temp2 = (PyObject *)temp1;
28322831
}
28332832
n = PyArray_NDIM((PyArrayObject *)temp2);
2834-
if (*axis < 0) {
2835-
*axis += n;
2836-
}
2837-
if ((*axis < 0) || (*axis >= n)) {
2838-
PyErr_Format(PyExc_ValueError,
2839-
"axis(=%d) out of bounds", axis_orig);
2833+
if (check_and_adjust_axis(axis, n) < 0) {
28402834
Py_DECREF(temp2);
28412835
return NULL;
28422836
}

‎numpy/core/src/multiarray/item_selection.c‎

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,16 +1101,12 @@ NPY_NO_EXPORT int
11011101
PyArray_Sort(PyArrayObject *op, int axis, NPY_SORTKIND which)
11021102
{
11031103
PyArray_SortFunc *sort;
1104-
int axis_orig = axis;
1105-
int n = PyArray_NDIM(op);
1104+
int n = PyArray_NDIM(op);
11061105

1107-
if (axis < 0) {
1108-
axis += n;
1109-
}
1110-
if (axis < 0 || axis >= n) {
1111-
PyErr_Format(PyExc_ValueError, "axis(=%d) out of bounds", axis_orig);
1106+
if (check_and_adjust_axis(&axis, n) < 0) {
11121107
return -1;
11131108
}
1109+
11141110
if (PyArray_FailUnlessWriteable(op, "sort array") < 0) {
11151111
return -1;
11161112
}
@@ -1212,17 +1208,13 @@ PyArray_Partition(PyArrayObject *op, PyArrayObject * ktharray, int axis,
12121208
PyArrayObject *kthrvl;
12131209
PyArray_PartitionFunc *part;
12141210
PyArray_SortFunc *sort;
1215-
int axis_orig = axis;
12161211
int n = PyArray_NDIM(op);
12171212
int ret;
12181213

1219-
if (axis < 0) {
1220-
axis += n;
1221-
}
1222-
if (axis < 0 || axis >= n) {
1223-
PyErr_Format(PyExc_ValueError, "axis(=%d) out of bounds", axis_orig);
1214+
if (check_and_adjust_axis(&axis, n) < 0) {
12241215
return -1;
12251216
}
1217+
12261218
if (PyArray_FailUnlessWriteable(op, "partition array") < 0) {
12271219
return -1;
12281220
}
@@ -1455,12 +1447,7 @@ PyArray_LexSort(PyObject *sort_keys, int axis)
14551447
*((npy_intp *)(PyArray_DATA(ret))) = 0;
14561448
goto finish;
14571449
}
1458-
if (axis < 0) {
1459-
axis += nd;
1460-
}
1461-
if ((axis < 0) || (axis >= nd)) {
1462-
PyErr_Format(PyExc_ValueError,
1463-
"axis(=%d) out of bounds", axis);
1450+
if (check_and_adjust_axis(&axis, nd) < 0) {
14641451
goto fail;
14651452
}
14661453

‎numpy/core/src/multiarray/multiarraymodule.c‎

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,6 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis)
327327
PyArray_Descr *dtype = NULL;
328328
PyArrayObject *ret = NULL;
329329
PyArrayObject_fields *sliding_view = NULL;
330-
int orig_axis = axis;
331330

332331
if (narrays <= 0) {
333332
PyErr_SetString(PyExc_ValueError,
@@ -345,13 +344,7 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis)
345344
}
346345

347346
/* Handle standard Python negative indexing */
348-
if (axis < 0) {
349-
axis += ndim;
350-
}
351-
352-
if (axis < 0 || axis >= ndim) {
353-
PyErr_Format(PyExc_IndexError,
354-
"axis %d out of bounds [0, %d)", orig_axis, ndim);
347+
if (check_and_adjust_axis(&axis, ndim) < 0) {
355348
return NULL;
356349
}
357350

‎numpy/core/src/multiarray/shape.c‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -705,12 +705,7 @@ PyArray_Transpose(PyArrayObject *ap, PyArray_Dims *permute)
705705
}
706706
for (i = 0; i < n; i++) {
707707
axis = axes[i];
708-
if (axis < 0) {
709-
axis = PyArray_NDIM(ap) + axis;
710-
}
711-
if (axis < 0 || axis >= PyArray_NDIM(ap)) {
712-
PyErr_SetString(PyExc_ValueError,
713-
"invalid axis for this array");
708+
if (check_and_adjust_axis(&axis, PyArray_NDIM(ap)) < 0) {
714709
return NULL;
715710
}
716711
if (reverse_permutation[axis] != -1) {

‎numpy/core/src/umath/ufunc_object.c‎

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4036,12 +4036,7 @@ PyUFunc_GenericReduction(PyUFuncObject *ufunc, PyObject *args,
40364036
Py_DECREF(mp);
40374037
return NULL;
40384038
}
4039-
if (axis < 0) {
4040-
axis += ndim;
4041-
}
4042-
if (axis < 0 || axis >= ndim) {
4043-
PyErr_SetString(PyExc_ValueError,
4044-
"'axis' entry is out of bounds");
4039+
if (check_and_adjust_axis(&axis, ndim) < 0) {
40454040
Py_XDECREF(otype);
40464041
Py_DECREF(mp);
40474042
return NULL;
@@ -4058,18 +4053,11 @@ PyUFunc_GenericReduction(PyUFuncObject *ufunc, PyObject *args,
40584053
Py_DECREF(mp);
40594054
return NULL;
40604055
}
4061-
if (axis < 0) {
4062-
axis += ndim;
4063-
}
40644056
/* Special case letting axis={0 or -1} slip through for scalars */
40654057
if (ndim == 0 && (axis == 0 || axis == -1)) {
40664058
axis = 0;
40674059
}
4068-
else if (axis < 0 || axis >= ndim) {
4069-
PyErr_SetString(PyExc_ValueError,
4070-
"'axis' entry is out of bounds");
4071-
Py_XDECREF(otype);
4072-
Py_DECREF(mp);
4060+
else if (check_and_adjust_axis(&axis, ndim) < 0) {
40734061
return NULL;
40744062
}
40754063
axes[0] = (int)axis;

0 commit comments

Comments
 (0)