diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 544a48a96b955..bed8dcd22a2d4 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -645,6 +645,7 @@ def copy(self, *, deep: bool) -> Self: values = values.copy() refs = None else: + values = values.view() refs = self.refs return type(self)(values, placement=self._mgr_locs, ndim=self.ndim, refs=refs) @@ -652,9 +653,9 @@ def copy(self, *, deep: bool) -> Self: # Copy-on-Write Helpers def _maybe_copy(self, inplace: bool) -> Self: - if inplace: - deep = self.refs.has_reference() - return self.copy(deep=deep) + if inplace and not self.refs.has_reference(): + # TODO(CoW) should we avoid the view taken in a shallow copy? + return self.copy(deep=False) return self.copy(deep=True) @final diff --git a/pandas/tests/copy_view/test_replace.py b/pandas/tests/copy_view/test_replace.py index d4838a5e68ab8..3313eecc32987 100644 --- a/pandas/tests/copy_view/test_replace.py +++ b/pandas/tests/copy_view/test_replace.py @@ -61,7 +61,9 @@ def test_replace_regex_inplace(): arr = get_array(df, "a") df.replace(to_replace=r"^a.*$", value="new", inplace=True, regex=True) assert df._mgr._has_no_reference(0) - assert tm.shares_memory(arr, get_array(df, "a")) + # ArrowExtensionArray __setitem__ swaps in a new array, so changes are not + # preserved across views -> original array not updated + assert not tm.shares_memory(arr, get_array(df, "a")) df_orig = df.copy() df2 = df.replace(to_replace=r"^b.*$", value="new", regex=True) diff --git a/pandas/tests/extension/date/array.py b/pandas/tests/extension/date/array.py index b97c20ad24f32..f0c0140f8ebff 100644 --- a/pandas/tests/extension/date/array.py +++ b/pandas/tests/extension/date/array.py @@ -167,6 +167,9 @@ def __repr__(self) -> str: def copy(self) -> DateArray: return DateArray((self._year.copy(), self._month.copy(), self._day.copy())) + def view(self) -> DateArray: + return DateArray((self._year.view(), self._month.view(), self._day.view())) + def isna(self) -> np.ndarray: return np.logical_and( np.logical_and( diff --git a/pandas/tests/extension/decimal/array.py b/pandas/tests/extension/decimal/array.py index 7d055e2143112..7223a1196013a 100644 --- a/pandas/tests/extension/decimal/array.py +++ b/pandas/tests/extension/decimal/array.py @@ -180,7 +180,7 @@ def __getitem__(self, item): else: # array, slice. item = pd.api.indexers.check_array_indexer(self, item) - result = type(self)(self._data[item]) + result = type(self)(self._data[item], context=self.dtype.context) if getitem_returns_view(self, item): result._readonly = self._readonly return result diff --git a/pandas/tests/frame/methods/test_select_dtypes.py b/pandas/tests/frame/methods/test_select_dtypes.py index c6aff45582dd7..7c2065f67236d 100644 --- a/pandas/tests/frame/methods/test_select_dtypes.py +++ b/pandas/tests/frame/methods/test_select_dtypes.py @@ -35,7 +35,7 @@ def __init__(self, data, dtype) -> None: self._dtype = dtype def __array__(self, dtype=None, copy=None): - return self.data + return np.asarray(self.data, dtype=dtype) @property def dtype(self): @@ -50,6 +50,9 @@ def __getitem__(self, item): def copy(self): return self + def view(self): + return self + class TestSelectDtypes: def test_select_dtypes_include_using_list_like(self, using_infer_string): diff --git a/pandas/tests/internals/test_internals.py b/pandas/tests/internals/test_internals.py index 7203082c077b9..db778b39369fa 100644 --- a/pandas/tests/internals/test_internals.py +++ b/pandas/tests/internals/test_internals.py @@ -489,7 +489,7 @@ def test_copy(self, mgr): # view assertion tm.assert_equal(cp_blk.values, blk.values) if isinstance(blk.values, np.ndarray): - assert cp_blk.values.base is blk.values.base + assert cp_blk.values.base.base is blk.values.base else: # DatetimeTZBlock has DatetimeIndex values assert cp_blk.values._ndarray.base is blk.values._ndarray.base