diff options
author | Matti Picus <matti.picus@gmail.com> | 2019-05-12 09:27:12 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-12 09:27:12 -0700 |
commit | d2d589703d5ee743251fbc6ea045f28e1c5e9e71 (patch) | |
tree | df60e9574f8a2af7ad29cfbde2ad68b8a2ed405a | |
parent | 798dce7d2f4d661eef2604bbd68fbe068c8d1ad6 (diff) | |
parent | 599dbade766ad3fecc82afa308803a2e0082c149 (diff) | |
download | numpy-d2d589703d5ee743251fbc6ea045f28e1c5e9e71.tar.gz |
Merge pull request #10308 from eric-wieser/mask-attr-is-view
API: Make MaskedArray.mask return a view, rather than the underlying mask
-rw-r--r-- | doc/release/1.17.0-notes.rst | 10 | ||||
-rw-r--r-- | numpy/lib/tests/test_function_base.py | 2 | ||||
-rw-r--r-- | numpy/ma/core.py | 4 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 11 | ||||
-rw-r--r-- | numpy/ma/tests/test_old_ma.py | 14 |
5 files changed, 30 insertions, 11 deletions
diff --git a/doc/release/1.17.0-notes.rst b/doc/release/1.17.0-notes.rst index dcadc009b..4f9134e0b 100644 --- a/doc/release/1.17.0-notes.rst +++ b/doc/release/1.17.0-notes.rst @@ -66,6 +66,16 @@ zero:: >>> np.zeros(10)//1 array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) +``MaskedArray.mask`` now returns a view of the mask, not the mask itself +------------------------------------------------------------------------ +Returning the mask itself was unsafe, as it could be reshaped in place which +would violate expectations of the masked array code. It's behavior is now +consistent with the ``.data`` attribute, which also returns a view. + +The underlying mask can still be accessed with ``._mask`` if it is needed. +Tests that contain ``assert x.mask is not y.mask`` or similar will need to be +updated. + Do not lookup ``__buffer__`` attribute in `numpy.frombuffer` ------------------------------------------------------------ Looking up ``__buffer__`` attribute in `numpy.frombuffer` was undocumented and diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index a5ae2eeed..a3d4c6efb 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -948,7 +948,7 @@ class TestGradient(object): assert_equal(type(out), type(x)) # And make sure that the output and input don't have aliased mask # arrays - assert_(x.mask is not out.mask) + assert_(x._mask is not out._mask) # Also check that edge_order=2 doesn't alter the original mask x2 = np.ma.arange(5) x2[2] = np.ma.masked diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 7ed099722..93eb4d87a 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -3449,7 +3449,9 @@ class MaskedArray(ndarray): # We could try to force a reshape, but that wouldn't work in some # cases. - return self._mask + # Return a view so that the dtype and shape cannot be changed in place + # This still preserves nomask by identity + return self._mask.view() @mask.setter def mask(self, value): diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index 1f80ba26d..fb3f1a810 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -374,12 +374,12 @@ class TestMaskedArray(object): y2a = array(x1, mask=m, copy=1) assert_(y2a._data.__array_interface__ != x1.__array_interface__) - #assert_( y2a.mask is not m) + #assert_( y2a._mask is not m) assert_(y2a._mask.__array_interface__ != m.__array_interface__) assert_(y2a[2] is masked) y2a[2] = 9 assert_(y2a[2] is not masked) - #assert_( y2a.mask is not m) + #assert_( y2a._mask is not m) assert_(y2a._mask.__array_interface__ != m.__array_interface__) assert_(allequal(y2a.mask, 0)) @@ -5203,3 +5203,10 @@ def test_fieldless_void(): mx = np.ma.array(x, mask=x) assert_equal(mx.dtype, x.dtype) assert_equal(mx.shape, x.shape) + + +def test_mask_shape_assignment_does_not_break_masked(): + a = np.ma.masked + b = np.ma.array(1, mask=a.mask) + b.shape = (1,) + assert_equal(a.mask.shape, ()) diff --git a/numpy/ma/tests/test_old_ma.py b/numpy/ma/tests/test_old_ma.py index 07bfb613f..1c523768d 100644 --- a/numpy/ma/tests/test_old_ma.py +++ b/numpy/ma/tests/test_old_ma.py @@ -270,7 +270,7 @@ class TestMa(object): y1 = array(x1, mask=m) assert_(y1._data is not x1) assert_(allequal(x1, y1._data)) - assert_(y1.mask is m) + assert_(y1._mask is m) y1a = array(y1, copy=0) # For copy=False, one might expect that the array would just @@ -280,19 +280,19 @@ class TestMa(object): y1._mask.__array_interface__) y2 = array(x1, mask=m3, copy=0) - assert_(y2.mask is m3) + assert_(y2._mask is m3) assert_(y2[2] is masked) y2[2] = 9 assert_(y2[2] is not masked) - assert_(y2.mask is m3) + assert_(y2._mask is m3) assert_(allequal(y2.mask, 0)) y2a = array(x1, mask=m, copy=1) - assert_(y2a.mask is not m) + assert_(y2a._mask is not m) assert_(y2a[2] is masked) y2a[2] = 9 assert_(y2a[2] is not masked) - assert_(y2a.mask is not m) + assert_(y2a._mask is not m) assert_(allequal(y2a.mask, 0)) y3 = array(x1 * 1.0, mask=m) @@ -318,14 +318,14 @@ class TestMa(object): assert_(x[3] is masked) assert_(x[4] is masked) x[[1, 4]] = [10, 40] - assert_(x.mask is m) + assert_(x._mask is m) assert_(x[3] is masked) assert_(x[4] is not masked) assert_(eq(x, [0, 10, 2, -1, 40])) x = array(d, mask=m2, copy=True) x.put([0, 1, 2], [-1, 100, 200]) - assert_(x.mask is not m2) + assert_(x._mask is not m2) assert_(x[3] is masked) assert_(x[4] is masked) assert_(eq(x, [-1, 100, 200, 0, 0])) |