summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2014-07-06 10:06:50 -0600
committerCharles Harris <charlesr.harris@gmail.com>2014-07-06 10:06:50 -0600
commit8dba040fcc26c21c982d162b03948a0b21b65535 (patch)
tree45a923ecf86d899054a62a0dba515de2d99d4443
parent81242f627582e04c000b73e52bc9b4067b0f478d (diff)
parent9c4d48c3c27584e8a555b5e55d1634089db7a01a (diff)
downloadnumpy-8dba040fcc26c21c982d162b03948a0b21b65535.tar.gz
Merge pull request #4804 from seberg/fancy-ass-1d
WIP: Fix matplotlib, etc. errors
-rw-r--r--numpy/core/src/multiarray/mapping.c89
-rw-r--r--numpy/core/tests/test_indexing.py10
-rw-r--r--numpy/core/tests/test_regression.py8
3 files changed, 101 insertions, 6 deletions
diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c
index e2b8ef700..bf4851519 100644
--- a/numpy/core/src/multiarray/mapping.c
+++ b/numpy/core/src/multiarray/mapping.c
@@ -1656,6 +1656,58 @@ array_assign_item(PyArrayObject *self, Py_ssize_t i, PyObject *op)
/*
+ * This fallback takes the old route of `arr.flat[index] = values`
+ * for one dimensional `arr`. The route can sometimes fail slightly
+ * different (ValueError instead of IndexError), in which case we
+ * warn users about the change. But since it does not actually care *at all*
+ * about shapes, it should only fail for out of bound indexes or
+ * casting errors.
+ */
+NPY_NO_EXPORT int
+attempt_1d_fallback(PyArrayObject *self, PyObject *ind, PyObject *op)
+{
+ PyObject *err = PyErr_Occurred();
+ PyArrayIterObject *self_iter = NULL;
+
+ Py_INCREF(err);
+ PyErr_Clear();
+
+ self_iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
+ if (self_iter == NULL) {
+ goto fail;
+ }
+ if (iter_ass_subscript(self_iter, ind, op) < 0) {
+ goto fail;
+ }
+
+ Py_XDECREF((PyObject *)self_iter);
+ Py_DECREF(err);
+
+ if (DEPRECATE(
+ "assignment will raise an error in the future, most likely "
+ "because your index result shape does not match the value array "
+ "shape. You can use `arr.flat[index] = values` to keep the old "
+ "behaviour.") < 0) {
+ return -1;
+ }
+ return 0;
+
+ fail:
+ if (!PyErr_ExceptionMatches(err)) {
+ PyObject *err, *val, *tb;
+ PyErr_Fetch(&err, &val, &tb);
+ DEPRECATE_FUTUREWARNING(
+ "assignment exception type will change in the future");
+ PyErr_Restore(err, val, tb);
+ }
+
+ Py_XDECREF((PyObject *)self_iter);
+ Py_DECREF(err);
+ return -1;
+}
+
+
+/*
* General assignment with python indexing objects.
*/
static int
@@ -1746,9 +1798,20 @@ array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op)
Py_INCREF(op);
tmp_arr = (PyArrayObject *)op;
}
+
if (array_assign_boolean_subscript(self,
(PyArrayObject *)indices[0].object,
tmp_arr, NPY_CORDER) < 0) {
+ /*
+ * Deprecated case. The old boolean indexing seemed to have some
+ * check to allow wrong dimensional boolean arrays in all cases.
+ */
+ if (PyArray_NDIM(tmp_arr) > 1) {
+ if (attempt_1d_fallback(self, indices[0].object, tmp_arr) < 0) {
+ goto fail;
+ }
+ goto success;
+ }
goto fail;
}
goto success;
@@ -1899,14 +1962,36 @@ array_assign_subscript(PyArrayObject *self, PyObject *ind, PyObject *op)
tmp_arr, descr);
if (mit == NULL) {
- goto fail;
+ /*
+ * This is a deprecated special case to allow non-matching shapes
+ * for the index and value arrays.
+ */
+ if (index_type != HAS_FANCY || index_num != 1) {
+ /* This is not a "flat like" 1-d special case */
+ goto fail;
+ }
+ if (attempt_1d_fallback(self, indices[0].object, op) < 0) {
+ goto fail;
+ }
+ goto success;
}
if (tmp_arr == NULL) {
/* Fill extra op */
if (PyArray_CopyObject(mit->extra_op, op) < 0) {
- goto fail;
+ /*
+ * This is a deprecated special case to allow non-matching shapes
+ * for the index and value arrays.
+ */
+ if (index_type != HAS_FANCY || index_num != 1) {
+ /* This is not a "flat like" 1-d special case */
+ goto fail;
+ }
+ if (attempt_1d_fallback(self, indices[0].object, op) < 0) {
+ goto fail;
+ }
+ goto success;
}
}
diff --git a/numpy/core/tests/test_indexing.py b/numpy/core/tests/test_indexing.py
index 6b0b0a0b5..44928b264 100644
--- a/numpy/core/tests/test_indexing.py
+++ b/numpy/core/tests/test_indexing.py
@@ -402,8 +402,14 @@ class TestBroadcastedAssignments(TestCase):
# Too large and not only ones.
assert_raises(ValueError, assign, a, s_[...], np.ones((2, 1)))
- assert_raises(ValueError, assign, a, s_[[1, 2, 3],], np.ones((2, 1)))
- assert_raises(ValueError, assign, a, s_[[[1], [2]],], np.ones((2,2,1)))
+
+ with warnings.catch_warnings():
+ # Will be a ValueError as well.
+ warnings.simplefilter("error", DeprecationWarning)
+ assert_raises(DeprecationWarning, assign, a, s_[[1, 2, 3],],
+ np.ones((2, 1)))
+ assert_raises(DeprecationWarning, assign, a, s_[[[1], [2]],],
+ np.ones((2,2,1)))
def test_simple_broadcasting_errors(self):
diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py
index 9f40d7b54..316ee33d3 100644
--- a/numpy/core/tests/test_regression.py
+++ b/numpy/core/tests/test_regression.py
@@ -756,8 +756,12 @@ class TestRegression(TestCase):
s = np.ones(10, dtype=float)
x = np.array((15,), dtype=float)
def ia(x, s, v): x[(s>0)]=v
- self.assertRaises(ValueError, ia, x, s, np.zeros(9, dtype=float))
- self.assertRaises(ValueError, ia, x, s, np.zeros(11, dtype=float))
+ # After removing deprecation, the following is are ValueErrors.
+ # This might seem odd as compared to the value error below. This
+ # is due to the fact that the new code always use "nonzero" logic
+ # and the boolean special case is not taken.
+ self.assertRaises(IndexError, ia, x, s, np.zeros(9, dtype=float))
+ self.assertRaises(IndexError, ia, x, s, np.zeros(11, dtype=float))
# Old special case (different code path):
self.assertRaises(ValueError, ia, x.flat, s, np.zeros(9, dtype=float))