Skip to content

Commit dfbaba2

Browse files
committed
BUG: Fix bug in putmask for CoW (pandas-dev#50630)
1 parent 63052a6 commit dfbaba2

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
@@ -851,6 +851,21 @@ def test_squeeze(using_copy_on_write):
851851
assert df.loc[0, "a"] == 0
852852

853853

854+
def test_putmask(using_copy_on_write):
855+
df = DataFrame({"a": [1, 2], "b": 1, "c": 2})
856+
view = df[:]
857+
df_orig = df.copy()
858+
df[df == df] = 5
859+
860+
if using_copy_on_write:
861+
assert not np.shares_memory(get_array(view, "a"), get_array(df, "a"))
862+
tm.assert_frame_equal(view, df_orig)
863+
else:
864+
# Without CoW the original will be modified
865+
assert np.shares_memory(get_array(view, "a"), get_array(df, "a"))
866+
assert view.iloc[0, 0] == 5
867+
868+
854869
def test_isetitem(using_copy_on_write):
855870
df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})
856871
df_orig = df.copy()

0 commit comments

Comments
 (0)