Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def _init_mgr(

# make a copy if explicitly requested
if copy:
mgr = mgr.copy()
mgr = mgr.copy(deep=True)
if dtype is not None:
# avoid further copies if we can
if (
Expand Down
8 changes: 4 additions & 4 deletions pandas/core/internals/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ def get_values_for_csv(
return self.make_block(result)

@final
def copy(self, deep: bool = True) -> Self:
def copy(self, *, deep: bool) -> Self:
"""copy constructor"""
values = self.values
refs: BlockValuesRefs | None
Expand All @@ -656,7 +656,7 @@ def _maybe_copy(self, inplace: bool) -> Self:
if inplace:
deep = self.refs.has_reference()
return self.copy(deep=deep)
return self.copy()
return self.copy(deep=True)

@final
def _get_refs_and_copy(self, inplace: bool):
Expand Down Expand Up @@ -923,10 +923,10 @@ def _replace_coerce(
has_ref = self.refs.has_reference()
nb = self.astype(np.dtype(object))
if not inplace:
nb = nb.copy()
nb = nb.copy(deep=True)
elif inplace and has_ref and nb.refs.has_reference():
# no copy in astype and we had refs before
nb = nb.copy()
nb = nb.copy(deep=True)
putmask_inplace(nb.values, mask, value)
return [nb]
return [self.copy(deep=False)]
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/internals/concat.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,14 @@ def _maybe_reindex_columns_na_proxy(
for i, indexer in indexers.items():
mgr = mgr.reindex_indexer(
axes[i],
indexers[i],
indexer,
axis=i,
only_slice=True, # only relevant for i==0
allow_dups=True,
use_na_proxy=True, # only relevant for i==0
)
if needs_copy and not indexers:
mgr = mgr.copy()
mgr = mgr.copy(deep=True)

new_mgrs.append(mgr)
return new_mgrs
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/internals/construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def rec_array_to_mgr(
mgr = arrays_to_mgr(arrays, columns, index, dtype=dtype)

if copy:
mgr = mgr.copy()
mgr = mgr.copy(deep=True)
return mgr


Expand Down
16 changes: 4 additions & 12 deletions pandas/core/internals/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ def setitem(self, indexer, value) -> Self:
return self
# No need to split if we either set all columns or on a single block
# manager
self = self.copy()
self = self.copy(deep=True)

return self.apply("setitem", indexer=indexer, value=value)

Expand Down Expand Up @@ -712,7 +712,7 @@ def _combine(self, blocks: list[Block], index: Index | None = None) -> Self:
def nblocks(self) -> int:
return len(self.blocks)

def copy(self, deep: bool | Literal["all"] = True) -> Self:
def copy(self, *, deep: bool) -> Self:
"""
Make deep or shallow copy of BlockManager

Expand All @@ -727,15 +727,7 @@ def copy(self, deep: bool | Literal["all"] = True) -> Self:
BlockManager
"""
# this preserves the notion of view copying of axes
if deep:
# hit in e.g. tests.io.json.test_pandas

def copy_func(ax):
return ax.copy(deep=True) if deep == "all" else ax.view()

new_axes = [copy_func(ax) for ax in self.axes]
else:
new_axes = [ax.view() for ax in self.axes]
new_axes = [ax.view() for ax in self.axes]
Copy link
Member

Choose a reason for hiding this comment

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

Reason that this is removed?

I know that an Index is generally immutable so the difference between view or actual copy is not relevant when it comes to the data, but we still some mutable attributes

Copy link
Member Author

Choose a reason for hiding this comment

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

deep="all" is not passed anymore AFAICT, so copy_func also becomes [ax.view() for ax in self.axes]. Should I change the view to copy to be safe?

Copy link
Member

Choose a reason for hiding this comment

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

Ah, sorry, missed the fact that the copy() call was only done for deep="all" ..

Yes, I would expect that we actually copy the indices in case of a deep=True

Copy link
Member

Choose a reason for hiding this comment

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

Hmm, it seems we have some tests that verify the shallow-ness of the copy (checking identity)

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah darn. I'll leave a TODO comment here and just swap back to the existing behavior since this PR is just meant to not change behavior.


res = self.apply("copy", deep=deep)
res.axes = new_axes
Expand Down Expand Up @@ -2192,7 +2184,7 @@ def setitem_inplace(self, indexer, value) -> None:
the dtype.
"""
if not self._has_no_reference(0):
self.blocks = (self._block.copy(),)
self.blocks = (self._block.copy(deep=True),)
self._reset_cache()

arr = self.array
Expand Down
6 changes: 2 additions & 4 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@ def __init__(
if dtype is not None:
data = data.astype(dtype=dtype)
elif copy:
data = data.copy()
data = data.copy(deep=True)
else:
data = sanitize_array(data, index, dtype, copy)
data = SingleBlockManager.from_array(data, index, refs=refs)
Expand Down Expand Up @@ -1833,9 +1833,7 @@ def to_frame(self, name: Hashable = lib.no_default) -> DataFrame:
df = self._constructor_expanddim_from_mgr(mgr, axes=mgr.axes)
return df.__finalize__(self, method="to_frame")

def _set_name(
self, name, inplace: bool = False, deep: bool | None = None
) -> Series:
def _set_name(self, name, inplace: bool = False) -> Series:
"""
Set the Series name.

Expand Down
10 changes: 5 additions & 5 deletions pandas/tests/internals/test_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,12 @@ def test_attrs(self, fblock):
assert len(fblock) == len(fblock.values)

def test_copy(self, fblock):
cop = fblock.copy()
cop = fblock.copy(deep=True)
assert cop is not fblock
assert_block_equal(fblock, cop)

def test_delete(self, fblock):
newb = fblock.copy()
newb = fblock.copy(deep=True)
locs = newb.mgr_locs
nb = newb.delete(0)[0]
assert newb.mgr_locs is locs
Expand All @@ -295,7 +295,7 @@ def test_delete(self, fblock):
assert not (newb.values[0] == 1).all()
assert (nb.values[0] == 1).all()

newb = fblock.copy()
newb = fblock.copy(deep=True)
locs = newb.mgr_locs
nb = newb.delete(1)
assert len(nb) == 2
Expand All @@ -310,15 +310,15 @@ def test_delete(self, fblock):
assert not (newb.values[1] == 2).all()
assert (nb[1].values[0] == 2).all()

newb = fblock.copy()
newb = fblock.copy(deep=True)
nb = newb.delete(2)
assert len(nb) == 1
tm.assert_numpy_array_equal(
nb[0].mgr_locs.as_array, np.array([0, 2], dtype=np.intp)
)
assert (nb[0].values[1] == 1).all()

newb = fblock.copy()
newb = fblock.copy(deep=True)

with pytest.raises(IndexError, match=None):
newb.delete(3)
Expand Down
Loading