diff --git a/doc/source/reference/maskedarray.generic.rst b/doc/source/reference/maskedarray.generic.rst index f753a56f9730..4ea936dea7af 100644 --- a/doc/source/reference/maskedarray.generic.rst +++ b/doc/source/reference/maskedarray.generic.rst @@ -379,8 +379,8 @@ is masked. When accessing a slice, the output is a masked array whose :attr:`~MaskedArray.data` attribute is a view of the original data, and whose mask is either :attr:`nomask` (if there was no invalid entries in the original -array) or a copy of the corresponding slice of the original mask. The copy is -required to avoid propagation of any modification of the mask to the original. +array) or a view of the corresponding slice of the original mask. The view is +required to ensure propagation of any modification of the mask to the original. >>> x = ma.array([1, 2, 3, 4, 5], mask=[0, 1, 0, 0, 1]) >>> mx = x[:3] diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 4466dc0afad1..20515c827bb8 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -3259,8 +3259,6 @@ def __setitem__(self, indx, value): _mask[indx] = tuple([True] * nbfields) else: _mask[indx] = True - if not self._isfield: - self._sharedmask = False return # Get the _data part of the new value @@ -3276,27 +3274,6 @@ def __setitem__(self, indx, value): _mask = self._mask = make_mask_none(self.shape, _dtype) _mask[indx] = mval elif not self._hardmask: - # Unshare the mask if necessary to avoid propagation - # We want to remove the unshare logic from this place in the - # future. Note that _sharedmask has lots of false positives. - if not self._isfield: - notthree = getattr(sys, 'getrefcount', False) and (sys.getrefcount(_mask) != 3) - if self._sharedmask and not ( - # If no one else holds a reference (we have two - # references (_mask and self._mask) -- add one for - # getrefcount) and the array owns its own data - # copying the mask should do nothing. - (not notthree) and _mask.flags.owndata): - # 2016.01.15 -- v1.11.0 - warnings.warn( - "setting an item on a masked array which has a shared " - "mask will not copy the mask and also change the " - "original mask array in the future.\n" - "Check the NumPy 1.11 release notes for more " - "information.", - MaskedArrayFutureWarning, stacklevel=2) - self.unshare_mask() - _mask = self._mask # Set the data, then the mask _data[indx] = dval _mask[indx] = mval @@ -4575,7 +4552,7 @@ def put(self, indices, values, mode='raise'): if self._mask is nomask and getmask(values) is nomask: return - m = getmaskarray(self).copy() + m = getmaskarray(self) if getmask(values) is nomask: m.put(indices, False, mode=mode) diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index b5be24b3161a..ce677053d07b 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -394,15 +394,26 @@ def test_copy(self): y1._data.__array_interface__) self.assertTrue(y1a.mask is y1.mask) - y2 = array(x1, mask=m) + y2 = array(x1, mask=m3) self.assertTrue(y2._data.__array_interface__ == x1.__array_interface__) - self.assertTrue(y2._mask.__array_interface__ == m.__array_interface__) + self.assertTrue(y2._mask.__array_interface__ == m3.__array_interface__) self.assertTrue(y2[2] is masked) y2[2] = 9 self.assertTrue(y2[2] is not masked) - self.assertTrue(y2._mask.__array_interface__ != m.__array_interface__) + self.assertTrue(y2._mask.__array_interface__ == m3.__array_interface__) self.assertTrue(allequal(y2.mask, 0)) + y2a = array(x1, mask=m, copy=1) + self.assertTrue(y2a._data.__array_interface__ != x1.__array_interface__) + #self.assertTrue( y2a.mask is not m) + self.assertTrue(y2a._mask.__array_interface__ != m.__array_interface__) + self.assertTrue(y2a[2] is masked) + y2a[2] = 9 + self.assertTrue(y2a[2] is not masked) + #self.assertTrue( y2a.mask is not m) + self.assertTrue(y2a._mask.__array_interface__ != m.__array_interface__) + self.assertTrue(allequal(y2a.mask, 0)) + y3 = array(x1 * 1.0, mask=m) self.assertTrue(filled(y3).dtype is (x1 * 1.0).dtype) diff --git a/numpy/ma/tests/test_old_ma.py b/numpy/ma/tests/test_old_ma.py index 2ea53683d1ae..18bb533ec847 100644 --- a/numpy/ma/tests/test_old_ma.py +++ b/numpy/ma/tests/test_old_ma.py @@ -5,8 +5,7 @@ import numpy as np import numpy.core.umath as umath import numpy.core.fromnumeric as fromnumeric -from numpy.testing import ( - TestCase, run_module_suite, assert_, suppress_warnings) +from numpy.testing import TestCase, run_module_suite, assert_ from numpy.ma.testutils import assert_array_equal from numpy.ma import ( MaskType, MaskedArray, absolute, add, all, allclose, allequal, alltrue, @@ -258,73 +257,98 @@ def test_testCI(self): def test_testCopySize(self): # Tests of some subtle points of copying and sizing. - with suppress_warnings() as sup: - sup.filter( - np.ma.core.MaskedArrayFutureWarning, - "setting an item on a masked array which has a " - "shared mask will not copy") - - n = [0, 0, 1, 0, 0] - m = make_mask(n) - m2 = make_mask(m) - self.assertTrue(m is m2) - m3 = make_mask(m, copy=1) - self.assertTrue(m is not m3) - - x1 = np.arange(5) - y1 = array(x1, mask=m) - self.assertTrue(y1._data is not x1) - self.assertTrue(allequal(x1, y1._data)) - self.assertTrue(y1.mask is m) - - y1a = array(y1, copy=0) - self.assertTrue(y1a.mask is y1.mask) - - y2 = array(x1, mask=m, copy=0) - self.assertTrue(y2.mask is m) - self.assertTrue(y2[2] is masked) - y2[2] = 9 - self.assertTrue(y2[2] is not masked) - self.assertTrue(y2.mask is not m) - self.assertTrue(allequal(y2.mask, 0)) - - y3 = array(x1 * 1.0, mask=m) - self.assertTrue(filled(y3).dtype is (x1 * 1.0).dtype) - - x4 = arange(4) - x4[2] = masked - y4 = resize(x4, (8,)) - self.assertTrue(eq(concatenate([x4, x4]), y4)) - self.assertTrue(eq(getmask(y4), [0, 0, 1, 0, 0, 0, 1, 0])) - y5 = repeat(x4, (2, 2, 2, 2), axis=0) - self.assertTrue(eq(y5, [0, 0, 1, 1, 2, 2, 3, 3])) - y6 = repeat(x4, 2, axis=0) - self.assertTrue(eq(y5, y6)) + n = [0, 0, 1, 0, 0] + m = make_mask(n) + m2 = make_mask(m) + self.assertTrue(m is m2) + m3 = make_mask(m, copy=1) + self.assertTrue(m is not m3) + + x1 = np.arange(5) + y1 = array(x1, mask=m) + self.assertTrue(y1._data is not x1) + self.assertTrue(allequal(x1, y1._data)) + self.assertTrue(y1.mask is m) + + y1a = array(y1, copy=0) + self.assertTrue(y1a.mask is y1.mask) + + y2 = array(x1, mask=m3, copy=0) + self.assertTrue(y2.mask is m3) + self.assertTrue(y2[2] is masked) + y2[2] = 9 + self.assertTrue(y2[2] is not masked) + self.assertTrue(y2.mask is m3) + self.assertTrue(allequal(y2.mask, 0)) + + y2a = array(x1, mask=m, copy=1) + self.assertTrue(y2a.mask is not m) + self.assertTrue(y2a[2] is masked) + y2a[2] = 9 + self.assertTrue(y2a[2] is not masked) + self.assertTrue(y2a.mask is not m) + self.assertTrue(allequal(y2a.mask, 0)) + + y3 = array(x1 * 1.0, mask=m) + self.assertTrue(filled(y3).dtype is (x1 * 1.0).dtype) + + x4 = arange(4) + x4[2] = masked + y4 = resize(x4, (8,)) + self.assertTrue(eq(concatenate([x4, x4]), y4)) + self.assertTrue(eq(getmask(y4), [0, 0, 1, 0, 0, 0, 1, 0])) + y5 = repeat(x4, (2, 2, 2, 2), axis=0) + self.assertTrue(eq(y5, [0, 0, 1, 1, 2, 2, 3, 3])) + y6 = repeat(x4, 2, axis=0) + self.assertTrue(eq(y5, y6)) def test_testPut(self): # Test of put - with suppress_warnings() as sup: - sup.filter( - np.ma.core.MaskedArrayFutureWarning, - "setting an item on a masked array which has a " - "shared mask will not copy") - d = arange(5) - n = [0, 0, 0, 1, 1] - m = make_mask(n) - x = array(d, mask=m) - self.assertTrue(x[3] is masked) - self.assertTrue(x[4] is masked) - x[[1, 4]] = [10, 40] - self.assertTrue(x.mask is not m) - self.assertTrue(x[3] is masked) - self.assertTrue(x[4] is not masked) - self.assertTrue(eq(x, [0, 10, 2, -1, 40])) - - x = array(d, mask=m) - x.put([0, 1, 2], [-1, 100, 200]) - self.assertTrue(eq(x, [-1, 100, 200, 0, 0])) - self.assertTrue(x[3] is masked) - self.assertTrue(x[4] is masked) + d = arange(5) + n = [0, 0, 0, 1, 1] + m = make_mask(n) + m2 = m.copy() + x = array(d, mask=m) + self.assertTrue(x[3] is masked) + self.assertTrue(x[4] is masked) + x[[1, 4]] = [10, 40] + self.assertTrue(x.mask is m) + self.assertTrue(x[3] is masked) + self.assertTrue(x[4] is not masked) + self.assertTrue(eq(x, [0, 10, 2, -1, 40])) + + x = array(d, mask=m2, copy=True) + x.put([0, 1, 2], [-1, 100, 200]) + self.assertTrue(x.mask is not m2) + self.assertTrue(x[3] is masked) + self.assertTrue(x[4] is masked) + self.assertTrue(eq(x, [-1, 100, 200, 0, 0])) + + def test_testPut2(self): + # Test of put + d = arange(5) + x = array(d, mask=[0, 0, 0, 0, 0]) + z = array([10, 40], mask=[1, 0]) + self.assertTrue(x[2] is not masked) + self.assertTrue(x[3] is not masked) + x[2:4] = z + self.assertTrue(x[2] is masked) + self.assertTrue(x[3] is not masked) + self.assertTrue(eq(x, [0, 1, 10, 40, 4])) + + d = arange(5) + x = array(d, mask=[0, 0, 0, 0, 0]) + y = x[2:4] + z = array([10, 40], mask=[1, 0]) + self.assertTrue(x[2] is not masked) + self.assertTrue(x[3] is not masked) + y[:] = z + self.assertTrue(y[0] is masked) + self.assertTrue(y[1] is not masked) + self.assertTrue(eq(y, [10, 40])) + self.assertTrue(x[2] is masked) + self.assertTrue(x[3] is not masked) + self.assertTrue(eq(x, [0, 1, 10, 40, 4])) def test_testMaPut(self): (x, y, a10, m1, m2, xm, ym, z, zm, xf, s) = self.d