Skip to content
16 changes: 8 additions & 8 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,17 +645,17 @@ def copy(self, *, deep: bool) -> Self:
values = values.copy()
refs = None
else:
values = values.view()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the actual change (taking a view of the values when doing a shallow copy), the other changes below in this file are a few fixes to ensure we return self instead of a shallow copy for inplace operations.

refs = self.refs
return type(self)(values, placement=self._mgr_locs, ndim=self.ndim, refs=refs)

# ---------------------------------------------------------------------
# Copy-on-Write Helpers

def _maybe_copy(self, inplace: bool) -> Self:
if inplace:
deep = self.refs.has_reference()
return self.copy(deep=deep)
return self.copy(deep=True)
def _maybe_copy(self, inplace: bool, deep: bool = True) -> Self:
if inplace and not self.refs.has_reference():
return self
return self.copy(deep=deep)

@final
def _get_refs_and_copy(self, inplace: bool):
Expand Down Expand Up @@ -695,14 +695,14 @@ def replace(
# replacing it is a no-op.
# Note: If to_replace were a list, NDFrame.replace would call
# replace_list instead of replace.
return [self.copy(deep=False)]
return [self._maybe_copy(inplace, deep=False)]

if mask is None:
mask = missing.mask_missing(values, to_replace)
if not mask.any():
# Note: we get here with test_replace_extension_other incorrectly
# bc _can_hold_element is incorrect.
return [self.copy(deep=False)]
return [self._maybe_copy(inplace, deep=False)]

elif self._can_hold_element(value) or (self.dtype == "string" and is_re(value)):
# TODO(CoW): Maybe split here as well into columns where mask has True
Expand Down Expand Up @@ -867,7 +867,7 @@ def replace_list(
for b in result:
if b.refs is self.refs:
# We are still sharing memory with self
if id(b) in self_blk_ids:
if id(b) in self_blk_ids and b is not self:
# Remove ourselves from the refs; we are temporary
self.refs.referenced_blocks.pop(self_blk_ids[id(b)])
else:
Expand Down
3 changes: 3 additions & 0 deletions pandas/tests/extension/date/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, dtype: Dtype | None = None) -> DateArray:
return DateArray((self._year.view(), self._month.view(), self._day.view()))

def isna(self) -> np.ndarray:
return np.logical_and(
np.logical_and(
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/extension/decimal/array.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion pandas/tests/frame/methods/test_select_dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this change just to honor the dtype keyword (in which case we should probably honor copy too?)? or is it important that we not return the object self.data? if the latter, is that a requirement for EAs that should be added to the interface tests?


@property
def dtype(self):
Expand All @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/internals/test_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading