diff options
author | Eric Wieser <wieser.eric@gmail.com> | 2017-06-30 22:29:25 +0100 |
---|---|---|
committer | Eric Wieser <wieser.eric@gmail.com> | 2017-06-30 22:29:25 +0100 |
commit | 4ff8d0aa471c8f2c463e50e24b38e71a94eb7c36 (patch) | |
tree | 5075d48bd5ee448733e739e76ed065f3d45a00cf /numpy/ma | |
parent | a5322429c56fb2f906e49e4ae5b87533269d8150 (diff) | |
download | numpy-4ff8d0aa471c8f2c463e50e24b38e71a94eb7c36.tar.gz |
BUG: Prevent copies of np.ma.MaskedConstant from being created by .view.
This seems to solve the problem everywhere. It's not clear if this works on PyPy.
Fixes gh-9328
Diffstat (limited to 'numpy/ma')
-rw-r--r-- | numpy/ma/core.py | 33 | ||||
-rw-r--r-- | numpy/ma/tests/test_core.py | 18 |
2 files changed, 36 insertions, 15 deletions
diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 5cf859b75..94613ef2f 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -6184,27 +6184,33 @@ isMA = isMaskedArray # backward compatibility class MaskedConstant(MaskedArray): - # We define the masked singleton as a float for higher precedence. - # Note that it can be tricky sometimes w/ type comparison - _data = data = np.array(0.) - _mask = mask = np.array(True) - _baseclass = ndarray __singleton = None def __new__(self): if self.__singleton is None: - self.__singleton = self._data.view(self) + # We define the masked singleton as a float for higher precedence. + # Note that it can be tricky sometimes w/ type comparison + data = np.array(0.) + mask = np.array(True) + self.__singleton = MaskedArray(data, mask=mask).view(self) + return self.__singleton def __array_finalize__(self, obj): - return - - def __array_prepare__(self, obj, context=None): - return self.view(MaskedArray).__array_prepare__(obj, context) + if self.__singleton is None: + # this handles the `.view` in __new__, which we want to copy across + # properties normally + return super(MaskedConstant, self).__array_finalize__(obj) + elif self is self.__singleton: + # not clear how this can happen, play it safe + pass + else: + # everywhere else, we want to downcast to MaskedArray, to prevent a + # duplicate maskedconstant. + self.__class__ = MaskedArray + self.__array_finalize__(obj) - def __array_wrap__(self, obj, context=None): - return self.view(MaskedArray).__array_wrap__(obj, context) def __str__(self): return str(masked_print_option._display) @@ -6216,9 +6222,6 @@ class MaskedConstant(MaskedArray): # something is wrong, make it obvious return object.__repr__(self) - def flatten(self): - return masked_array([self._data], dtype=float, mask=[True]) - def __reduce__(self): """Override of MaskedArray's __reduce__. """ diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index 345666317..bead29d31 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -4748,6 +4748,24 @@ class TestMaskedConstant(TestCase): res = pickle.load(f) assert_(res is np.ma.masked) + def test_write_to_copy(self): + # gh-9328 + x = np.ma.masked.copy() + x[()] = 2 + + # write succeeds + assert_equal(x.data, 2) + assert_equal(x.mask, False) + + # original should be unchanged + assert_equal(np.ma.masked.data, 0) + assert_equal(np.ma.masked.mask, True) + + def test_no_copies(self): + MC = np.ma.core.MaskedConstant + assert_(not isinstance(np.ma.masked[...], MC)) + assert_(not isinstance(np.ma.masked.copy(), MC)) + def test_masked_array(): a = np.ma.array([0, 1, 2, 3], mask=[0, 0, 1, 0]) |