summaryrefslogtreecommitdiff
path: root/numpy/ma
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2017-06-30 22:29:25 +0100
committerEric Wieser <wieser.eric@gmail.com>2017-06-30 22:29:25 +0100
commit4ff8d0aa471c8f2c463e50e24b38e71a94eb7c36 (patch)
tree5075d48bd5ee448733e739e76ed065f3d45a00cf /numpy/ma
parenta5322429c56fb2f906e49e4ae5b87533269d8150 (diff)
downloadnumpy-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.py33
-rw-r--r--numpy/ma/tests/test_core.py18
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])