Repository: numpy/numpy

Issue:
Bug in masked array indexing.
This simple indexing operation

```
ma = np.ma.zeros(5000, dtype=[('symbol', 'O')])
print(ma[0])
```

fails with a

```
ValueError: Setting void-array with object members using buffer.
```

exception. While the non-masked version just works:

```
arr = np.zeros(5000, dtype=[('symbol', 'O')])
print(arr[0])
```

Numpy version `1.11.0` on python 3.5.1 on arch linux.



Discussion:
Probably caused by #6094.

@ahaldane Does this need a fix?

It is a regression, but the question of what to do is a bit complicated. Here are the facts:
- #6094 fixed a bug for printing structured dtypes, but exposed a long-standing bug that assignment of structured dtypes _with objects_ doesn't work (across all of numpy). The line `np.array([m._data])` in #6094 is what fails, where `m._data = np.array([(0,)], dtype=[('f', 'O')])[0]`.
- the long-standing bug makes it very difficult to use structured-dtypes-with-objects anyway. I suspect @kawing-chiu  would quickly encounter other problems (see example below).
- the assignment bug can be fixed by my PR #6053

I am tempted to leave this alone until we get around to considering #6053. #6094 fixed more cases than it broke: Now all structured dtypes work properly, except structured dtypes with objects.

Here is a demonstration of the assignment bug:

```
arr = np.array([(0,), (1,)], dtype=[('f', 'O')])
arr[0] = arr[1]
ValueError: Setting void-array with object members using buffer.
```

Maybe @astrofrog has more insights into a quick fix?

Hmm actually there is a hack to get around the assignment bug:

```
>>> arr = np.array([(0,), (1,)], dtype=[('f', 'O')])
>>> arr[0] = arr[1]
ValueError: Setting void-array with object members using buffer.
>>> arr[:1] = arr[1]  #works because it goes down the dtype_transfer code path
```

That means a very hacky fix to #6094 may be to replace `res = np.array([m._data], dtype=rdtype)` with

```
res = np.empty(1, rdtype)
res[:1] = m._data
```

@ahaldane Will #6053 fix this, 0r is it just a good starting point?

I just did a quick rebase of #6053 on master to make sure, and it fixes it with no other changes needed.

#6053 is bigger than I want to contemplate for 1.11.1. If you think your workaround is reasonable, could you make a special PR against 1.11.x? If not, I'm inclined to just let this problem be for 1.11 and shoot for 1.12 for the fix.

Sure, as long as we remember to change it later. I'll try it out.


Resolving patch:
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -5954,7 +5954,14 @@ def __str__(self):
             return self._data.__str__()
         printopt = masked_print_option
         rdtype = _recursive_make_descr(self._data.dtype, "O")
-        res = np.array([self._data]).astype(rdtype)
+
+        # temporary hack to fix gh-7493. A more permanent fix
+        # is proposed in gh-6053, after which the next two
+        # lines should be changed to
+        # res = np.array([self._data], dtype=rdtype)
+        res = np.empty(1, rdtype)
+        res[:1] = self._data
+
         _recursive_printoption(res, self._mask, printopt)
         return str(res[0])
 


Test patch:
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -757,6 +757,10 @@ def test_mvoid_print(self):
         finally:
             masked_print_option.set_display(ini_display)
 
+        # also check if there are object datatypes (see gh-7493)
+        mx = array([(1,), (2,)], dtype=[('a', 'O')])
+        assert_equal(str(mx[0]), "(1,)")
+
     def test_mvoid_multidim_print(self):
 
         # regression test for gh-6019