summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastianb@nvidia.com>2023-02-26 00:26:34 +0100
committerGitHub <noreply@github.com>2023-02-26 00:26:34 +0100
commite141d9074e95bbdaa33ce727e9c9baa33d00875a (patch)
tree792edac50335909a914f2a17c21828a7515ac18e /numpy
parent78221d0dc4cd1c4f44114d85c73d665d6846c090 (diff)
parent284523848164454f8d3f780824c1a827477c9957 (diff)
downloadnumpy-e141d9074e95bbdaa33ce727e9c9baa33d00875a.tar.gz
Merge pull request #23269 from tylerjereddy/treddy_ma_deepcopy_fix
BUG: masked array proper deepcopies
Diffstat (limited to 'numpy')
-rw-r--r--numpy/ma/core.py14
-rw-r--r--numpy/ma/tests/test_core.py45
2 files changed, 58 insertions, 1 deletions
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index b76ff8ea9..9584e56d2 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -2870,7 +2870,13 @@ class MaskedArray(ndarray):
_data._mask = _data._mask.copy()
# Reset the shape of the original mask
if getmask(data) is not nomask:
- data._mask.shape = data.shape
+ # gh-21022 encounters an issue here
+ # because data._mask.shape is not writeable, but
+ # the op was also pointless in that case, because
+ # the shapes were the same, so we can at least
+ # avoid that path
+ if data._mask.shape != data.shape:
+ data._mask.shape = data.shape
else:
# Case 2. : With a mask in input.
# If mask is boolean, create an array of True or False
@@ -6300,6 +6306,12 @@ class MaskedArray(ndarray):
memo[id(self)] = copied
for (k, v) in self.__dict__.items():
copied.__dict__[k] = deepcopy(v, memo)
+ # as clearly documented for np.copy(), you need to use
+ # deepcopy() directly for arrays of object type that may
+ # contain compound types--you cannot depend on normal
+ # copy semantics to do the right thing here
+ if self.dtype.hasobject:
+ copied._data[...] = deepcopy(copied._data)
return copied
diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py
index 7d23e32ec..172a1ee8d 100644
--- a/numpy/ma/tests/test_core.py
+++ b/numpy/ma/tests/test_core.py
@@ -8,6 +8,7 @@ __author__ = "Pierre GF Gerard-Marchant"
import sys
import warnings
+import copy
import operator
import itertools
import textwrap
@@ -5570,3 +5571,47 @@ note
original note"""
assert_equal(np.ma.core.doc_note(method.__doc__, "note"), expected_doc)
+
+
+def test_gh_22556():
+ source = np.ma.array([0, [0, 1, 2]], dtype=object)
+ deepcopy = copy.deepcopy(source)
+ deepcopy[1].append('this should not appear in source')
+ assert len(source[1]) == 3
+
+
+def test_gh_21022():
+ # testing for absence of reported error
+ source = np.ma.masked_array(data=[-1, -1], mask=True, dtype=np.float64)
+ axis = np.array(0)
+ result = np.prod(source, axis=axis, keepdims=False)
+ result = np.ma.masked_array(result,
+ mask=np.ones(result.shape, dtype=np.bool_))
+ array = np.ma.masked_array(data=-1, mask=True, dtype=np.float64)
+ copy.deepcopy(array)
+ copy.deepcopy(result)
+
+
+def test_deepcopy_2d_obj():
+ source = np.ma.array([[0, "dog"],
+ [1, 1],
+ [[1, 2], "cat"]],
+ mask=[[0, 1],
+ [0, 0],
+ [0, 0]],
+ dtype=object)
+ deepcopy = copy.deepcopy(source)
+ deepcopy[2, 0].extend(['this should not appear in source', 3])
+ assert len(source[2, 0]) == 2
+ assert len(deepcopy[2, 0]) == 4
+ assert_equal(deepcopy._mask, source._mask)
+ deepcopy._mask[0, 0] = 1
+ assert source._mask[0, 0] == 0
+
+
+def test_deepcopy_0d_obj():
+ source = np.ma.array(0, mask=[0], dtype=object)
+ deepcopy = copy.deepcopy(source)
+ deepcopy[...] = 17
+ assert_equal(source, 0)
+ assert_equal(deepcopy, 17)