diff options
-rw-r--r-- | doc/release/1.14.0-notes.rst | 8 | ||||
-rw-r--r-- | numpy/ma/core.py | 27 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 31 |
3 files changed, 47 insertions, 19 deletions
diff --git a/doc/release/1.14.0-notes.rst b/doc/release/1.14.0-notes.rst index 45227ae2b..bc7950257 100644 --- a/doc/release/1.14.0-notes.rst +++ b/doc/release/1.14.0-notes.rst @@ -100,6 +100,14 @@ This is for pytest compatibility in the case of duplicate test file names in the different directories. As a result, ``run_module_suite`` no longer works, i.e., ``python <path-to-test-file>`` results in an error. +``MaskedArray.squeeze`` never returns ``np.ma.masked`` +------------------------------------------------------ +``np.squeeze`` is documented as returning a view, but the masked variant would +sometimes return ``masked``, which is not a view. This has been fixed, so that +the result is always a view on the original masked array. +This breaks any code that used ``masked_arr.squeeze() is np.ma.masked``, but +fixes code that writes to the result of `.squeeze()`. + C API changes ============= diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 8da68ff9c..8efe45eed 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -2555,14 +2555,10 @@ def _arraymethod(funcname, onmask=True): result = result.view(type(self)) result._update_from(self) mask = self._mask - if result.ndim: - if not onmask: - result.__setmask__(mask) - elif mask is not nomask: - result.__setmask__(getattr(mask, funcname)(*args, **params)) - else: - if mask.ndim and (not mask.dtype.names and mask.all()): - return masked + if not onmask: + result.__setmask__(mask) + elif mask is not nomask: + result.__setmask__(getattr(mask, funcname)(*args, **params)) return result methdoc = getattr(ndarray, funcname, None) or getattr(np, funcname, None) if methdoc is not None: @@ -4410,8 +4406,6 @@ class MaskedArray(ndarray): return (~m).sum(axis=axis, dtype=np.intp, **kwargs) - flatten = _arraymethod('flatten') - def ravel(self, order='C'): """ Returns a 1D version of self, as a view. @@ -4457,8 +4451,6 @@ class MaskedArray(ndarray): r._mask = nomask return r - repeat = _arraymethod('repeat') - def reshape(self, *s, **kwargs): """ @@ -5745,14 +5737,15 @@ class MaskedArray(ndarray): return out[()] # Array methods - copy = _arraymethod('copy') - diagonal = _arraymethod('diagonal') - transpose = _arraymethod('transpose') - T = property(fget=lambda self: self.transpose()) - swapaxes = _arraymethod('swapaxes') clip = _arraymethod('clip', onmask=False) copy = _arraymethod('copy') + diagonal = _arraymethod('diagonal') + flatten = _arraymethod('flatten') + repeat = _arraymethod('repeat') squeeze = _arraymethod('squeeze') + swapaxes = _arraymethod('swapaxes') + T = property(fget=lambda self: self.transpose()) + transpose = _arraymethod('transpose') def tolist(self, fill_value=None): """ diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index a8b5ed466..5da19f9ca 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -445,6 +445,12 @@ class TestMaskedArray(object): assert_not_equal(y._data.ctypes.data, x._data.ctypes.data) assert_not_equal(y._mask.ctypes.data, x._mask.ctypes.data) + def test_copy_0d(self): + # gh-9430 + x = np.ma.array(43, mask=True) + xc = x.copy() + assert_equal(xc.mask, True) + def test_copy_on_python_builtins(self): # Tests copy works on python builtins (issue#8019) assert_(isMaskedArray(np.ma.copy([1,2,3]))) @@ -3204,8 +3210,23 @@ class TestMaskedArrayMethods(object): data = masked_array([[1, 2, 3]], mask=[[1, 1, 1]]) assert_equal(data.squeeze(), [1, 2, 3]) assert_equal(data.squeeze()._mask, [1, 1, 1]) - data = masked_array([[1]], mask=True) - assert_(data.squeeze() is masked) + + # normal ndarrays return a view + arr = np.array([[1]]) + arr_sq = arr.squeeze() + assert_equal(arr_sq, 1) + arr_sq[...] = 2 + assert_equal(arr[0,0], 2) + + # so maskedarrays should too + m_arr = masked_array([[1]], mask=True) + m_arr_sq = m_arr.squeeze() + assert_(m_arr_sq is not np.ma.masked) + assert_equal(m_arr_sq.mask, True) + m_arr_sq[...] = 2 + # TODO: mask isn't copied to/from views yet in maskedarray, so we can + # only check the data + assert_equal(m_arr.data[0,0], 2) def test_swapaxes(self): # Tests swapaxes on MaskedArrays. @@ -3388,6 +3409,12 @@ class TestMaskedArrayMethods(object): assert_equal(MaskedArray.cumsum(marray.T, 0), control.cumsum(0)) + def test_arraymethod_0d(self): + # gh-9430 + x = np.ma.array(42, mask=True) + assert_equal(x.T.mask, x.mask) + assert_equal(x.T.data, x.data) + class TestMaskedArrayMathMethods(object): |