Skip to content

Commit 8dba040

Browse files
committed
Merge pull request #4804 from seberg/fancy-ass-1d
WIP: Fix matplotlib, etc. errors
2 parents 81242f6 + 9c4d48c commit 8dba040

File tree

3 files changed

+101
-6
lines changed

3 files changed

+101
-6
lines changed

numpy/core/src/multiarray/mapping.c

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,58 @@ array_assign_item(PyArrayObject *self, Py_ssize_t i, PyObject *op)
16551655
}
16561656

16571657

1658+
/*
1659+
* This fallback takes the old route of `arr.flat[index] = values`
1660+
* for one dimensional `arr`. The route can sometimes fail slightly
1661+
* different (ValueError instead of IndexError), in which case we
1662+
* warn users about the change. But since it does not actually care *at all*
1663+
* about shapes, it should only fail for out of bound indexes or
1664+
* casting errors.
1665+
*/
1666+
NPY_NO_EXPORT int
1667+
attempt_1d_fallback(PyArrayObject *self, PyObject *ind, PyObject *op)
1668+
{
1669+
PyObject *err = PyErr_Occurred();
1670+
PyArrayIterObject *self_iter = NULL;
1671+
1672+
Py_INCREF(err);
1673+
PyErr_Clear();
1674+
1675+
self_iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
1676+
if (self_iter == NULL) {
1677+
goto fail;
1678+
}
1679+
if (iter_ass_subscript(self_iter, ind, op) < 0) {
1680+
goto fail;
1681+
}
1682+
1683+
Py_XDECREF((PyObject *)self_iter);
1684+
Py_DECREF(err);
1685+
1686+
if (DEPRECATE(
1687+
"assignment will raise an error in the future, most likely "
1688+
"because your index result shape does not match the value array "
1689+
"shape. You can use `arr.flat[index] = values` to keep the old "
1690+
"behaviour.") < 0) {
1691+
return -1;
1692+
}
1693+
return 0;
1694+
1695+
fail:
1696+
if (!PyErr_ExceptionMatches(err)) {
1697+
PyObject *err, *val, *tb;
1698+
PyErr_Fetch(&err, &val, &tb);
1699+
DEPRECATE_FUTUREWARNING(
1700+
"assignment exception type will change in the future");
1701+
PyErr_Restore(err, val, tb);
1702+
}
1703+
1704+
Py_XDECREF((PyObject *)self_iter);
1705+
Py_DECREF(err);
1706+
return -1;
1707+
}
1708+
1709+
16581710
/*
16591711
* General assignment with python indexing objects.
16601712
*/
@@ -1746,9 +1798,20 @@ array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op)
17461798
Py_INCREF(op);
17471799
tmp_arr = (PyArrayObject *)op;
17481800
}
1801+
17491802
if (array_assign_boolean_subscript(self,
17501803
(PyArrayObject *)indices[0].object,
17511804
tmp_arr, NPY_CORDER) < 0) {
1805+
/*
1806+
* Deprecated case. The old boolean indexing seemed to have some
1807+
* check to allow wrong dimensional boolean arrays in all cases.
1808+
*/
1809+
if (PyArray_NDIM(tmp_arr) > 1) {
1810+
if (attempt_1d_fallback(self, indices[0].object, tmp_arr) < 0) {
1811+
goto fail;
1812+
}
1813+
goto success;
1814+
}
17521815
goto fail;
17531816
}
17541817
goto success;
@@ -1899,14 +1962,36 @@ array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op)
18991962
tmp_arr, descr);
19001963

19011964
if (mit == NULL) {
1902-
goto fail;
1965+
/*
1966+
* This is a deprecated special case to allow non-matching shapes
1967+
* for the index and value arrays.
1968+
*/
1969+
if (index_type != HAS_FANCY || index_num != 1) {
1970+
/* This is not a "flat like" 1-d special case */
1971+
goto fail;
1972+
}
1973+
if (attempt_1d_fallback(self, indices[0].object, op) < 0) {
1974+
goto fail;
1975+
}
1976+
goto success;
19031977
}
19041978

19051979
if (tmp_arr == NULL) {
19061980
/* Fill extra op */
19071981

19081982
if (PyArray_CopyObject(mit->extra_op, op) < 0) {
1909-
goto fail;
1983+
/*
1984+
* This is a deprecated special case to allow non-matching shapes
1985+
* for the index and value arrays.
1986+
*/
1987+
if (index_type != HAS_FANCY || index_num != 1) {
1988+
/* This is not a "flat like" 1-d special case */
1989+
goto fail;
1990+
}
1991+
if (attempt_1d_fallback(self, indices[0].object, op) < 0) {
1992+
goto fail;
1993+
}
1994+
goto success;
19101995
}
19111996
}
19121997

numpy/core/tests/test_indexing.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,14 @@ def test_prepend_not_one(self):
402402

403403
# Too large and not only ones.
404404
assert_raises(ValueError, assign, a, s_[...], np.ones((2, 1)))
405-
assert_raises(ValueError, assign, a, s_[[1, 2, 3],], np.ones((2, 1)))
406-
assert_raises(ValueError, assign, a, s_[[[1], [2]],], np.ones((2,2,1)))
405+
406+
with warnings.catch_warnings():
407+
# Will be a ValueError as well.
408+
warnings.simplefilter("error", DeprecationWarning)
409+
assert_raises(DeprecationWarning, assign, a, s_[[1, 2, 3],],
410+
np.ones((2, 1)))
411+
assert_raises(DeprecationWarning, assign, a, s_[[[1], [2]],],
412+
np.ones((2,2,1)))
407413

408414

409415
def test_simple_broadcasting_errors(self):

numpy/core/tests/test_regression.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,8 +756,12 @@ def test_bool_indexing_invalid_nr_elements(self, level=rlevel):
756756
s = np.ones(10, dtype=float)
757757
x = np.array((15,), dtype=float)
758758
def ia(x, s, v): x[(s>0)]=v
759-
self.assertRaises(ValueError, ia, x, s, np.zeros(9, dtype=float))
760-
self.assertRaises(ValueError, ia, x, s, np.zeros(11, dtype=float))
759+
# After removing deprecation, the following is are ValueErrors.
760+
# This might seem odd as compared to the value error below. This
761+
# is due to the fact that the new code always use "nonzero" logic
762+
# and the boolean special case is not taken.
763+
self.assertRaises(IndexError, ia, x, s, np.zeros(9, dtype=float))
764+
self.assertRaises(IndexError, ia, x, s, np.zeros(11, dtype=float))
761765
# Old special case (different code path):
762766
self.assertRaises(ValueError, ia, x.flat, s, np.zeros(9, dtype=float))
763767

0 commit comments

Comments
 (0)