Skip to content

Commit 954cf55

Browse files
authored
BUG: Fix bug in putmask for CoW (#50630)
1 parent 62521da commit 954cf55

File tree

3 files changed

+18
-4
lines changed

3 files changed

+18
-4
lines changed

doc/source/whatsnew/v1.5.3.rst

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Fixed regressions
2727

2828
Bug fixes
2929
~~~~~~~~~
30+
- Bug in the Copy-on-Write implementation losing track of views when indexing a :class:`DataFrame` with another :class:`DataFrame` (:issue:`50630`)
3031
- Bug in :meth:`.Styler.to_excel` leading to error when unrecognized ``border-style`` (e.g. ``"hair"``) provided to Excel writers (:issue:`48649`)
3132
- Bug in :meth:`Series.quantile` emitting warning from NumPy when :class:`Series` has only ``NA`` values (:issue:`50681`)
3233
- Bug when chaining several :meth:`.Styler.concat` calls, only the last styler was concatenated (:issue:`49207`)

pandas/core/internals/managers.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,8 @@ def setitem(self: T, indexer, value) -> T:
384384
return self.apply("setitem", indexer=indexer, value=value)
385385

386386
def putmask(self, mask, new, align: bool = True):
387-
if (
388-
using_copy_on_write()
389-
and self.refs is not None
390-
and not all(ref is None for ref in self.refs)
387+
if using_copy_on_write() and any(
388+
not self._has_no_reference_block(i) for i in range(len(self.blocks))
391389
):
392390
# some reference -> copy full dataframe
393391
# TODO(CoW) this could be optimized to only copy the blocks that would

pandas/tests/copy_view/test_methods.py

+15
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,21 @@ def test_squeeze(using_copy_on_write):
830830
assert df.loc[0, "a"] == 0
831831

832832

833+
def test_putmask(using_copy_on_write):
834+
df = DataFrame({"a": [1, 2], "b": 1, "c": 2})
835+
view = df[:]
836+
df_orig = df.copy()
837+
df[df == df] = 5
838+
839+
if using_copy_on_write:
840+
assert not np.shares_memory(get_array(view, "a"), get_array(df, "a"))
841+
tm.assert_frame_equal(view, df_orig)
842+
else:
843+
# Without CoW the original will be modified
844+
assert np.shares_memory(get_array(view, "a"), get_array(df, "a"))
845+
assert view.iloc[0, 0] == 5
846+
847+
833848
def test_isetitem(using_copy_on_write):
834849
df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})
835850
df_orig = df.copy()

0 commit comments

Comments
 (0)