From fad31288a2909e0befcb82f2ab06786490fe1565 Mon Sep 17 00:00:00 2001 From: mbyt Date: Sun, 9 Mar 2014 18:12:11 +0100 Subject: [PATCH] BUG: non supported structured array assignments Raising an error for non supported operations. Also adapting related statement in test. Resolves #3126 and #3561. --- numpy/core/src/multiarray/scalartypes.c.src | 16 +++++++ numpy/core/tests/test_multiarray.py | 51 ++++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index afae70fd548b..697d3b006f95 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -1672,6 +1672,22 @@ voidtype_setfield(PyVoidScalarObject *self, PyObject *args, PyObject *kwds) Py_DECREF(typecode); } else { + /* method voidtype_setfield sets per definition a void field, + * not an array or a broadcast to an array. */ + if ((typecode->subarray != NULL) || +#if defined(NPY_PY3K) + (!PyUString_Check(value) && +#else + (!PyBytes_Check(value) && !PyUnicode_Check(value) && +#endif + PySequence_Check(value) && + PySequence_Length(value) > 1)) { + PyErr_Format(PyExc_ValueError, + "Incompatible assignment of sequence to numpy scalar. " \ + "Left hand [:] for slice assignment might be missing."); + return NULL; + } + /* Copy data from value to correct place in dptr */ src = (PyArrayObject *)PyArray_FromAny(value, typecode, 0, 0, NPY_ARRAY_CARRAY, NULL); diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 655ac3748041..5160e620fdfd 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -567,7 +567,8 @@ def test_subarray_comparison(self): assert_equal(a==b, [True, False]) assert_equal(a!=b, [False, True]) for i in range(3): - b[0].a = a[0].a + b[0].a[:] = a[0].a + assert_equal(b[0].a, a[0].a) b[0].a[i] = 5 assert_equal(a==b, [False, False]) assert_equal(a!=b, [True, True]) @@ -2873,6 +2874,54 @@ def test_record_no_hash(self): a = np.array([(1, 2), (1, 2)], dtype='i1,i2') self.assertRaises(TypeError, hash, a[0]) + def test_structured_array_assignment(self): + # see also #3126 + struct_dt = np.dtype([('elem', 'i4', 5)]) + dt = np.dtype([ + ('field', 'i4', 10), + ('struct', struct_dt), + ('field_of_struct', struct_dt, 3), + ('elem', 'i4'), + ]) + # correct slice assignments + x = np.zeros(1, dt) + x[0]['field'][:] = np.ones(10, dtype='i4') + assert_array_equal(x[0]['field'], 1) + fos = np.ones(3, dtype=struct_dt) + x[0]['field_of_struct'][:] = fos + assert_array_equal(x[0]['field_of_struct'], fos) + # incorrect slice assignment + def f(): + x[0]['field'][:] = np.ones(9, dtype='i4') + self.assertRaises(ValueError, f) + # no slice assignment + x = np.zeros(1, dt) + s = np.ones(1, dtype=struct_dt) + x[0]['struct'] = s + assert_array_equal(x[0]['struct'], s) + x['elem'] = 2 + self.assertEqual(x['elem'], 2) + x[0]['elem'] = 3 + self.assertEqual(x['elem'], 3) + # incorrect no slice assignment, #3126 + def f(): + x[0]['field'] = np.ones(10, dtype='i4') + self.assertRaises(ValueError, f) + def f(): + x[0]['field'] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + self.assertRaises(ValueError, f) + # see #3561 + def f(): + x[0]['field'] = 1 + self.assertRaises(ValueError, f) + def f(): + x[0]['struct'] = np.ones(3, dtype=struct_dt) + self.assertRaises(ValueError, f) + y = x.copy() + def f(): + x[0]['field'] = y[0]['field'] + self.assertRaises(ValueError, f) + class TestView(TestCase): def test_basic(self): x = np.array([(1, 2, 3, 4), (5, 6, 7, 8)], dtype=[('r', np.int8), ('g', np.int8),