Skip to content

Commit 23a2699

Browse files
authored
Backport PR pandas-dev#50685 on branch 1.5.x (BUG: Fix bug in putmask for CoW) (pandas-dev#50726)
BUG: Fix bug in putmask for CoW (pandas-dev#50630)
1 parent 476ce03 commit 23a2699

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
@@ -26,6 +26,7 @@ Fixed regressions
2626

2727
Bug fixes
2828
~~~~~~~~~
29+
- Bug in the Copy-on-Write implementation losing track of views when indexing a :class:`DataFrame` with another :class:`DataFrame` (:issue:`50630`)
2930
- Bug in :meth:`.Styler.to_excel` leading to error when unrecognized ``border-style`` (e.g. ``"hair"``) provided to Excel writers (:issue:`48649`)
3031
- Bug in :meth:`Series.quantile` emitting warning from NumPy when :class:`Series` has only ``NA`` values (:issue:`50681`)
3132
- 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
@@ -393,10 +393,8 @@ def setitem(self: T, indexer, value) -> T:
393393
return self.apply("setitem", indexer=indexer, value=value)
394394

395395
def putmask(self, mask, new, align: bool = True):
396-
if (
397-
_using_copy_on_write()
398-
and self.refs is not None
399-
and not all(ref is None for ref in self.refs)
396+
if _using_copy_on_write() and any(
397+
not self._has_no_reference_block(i) for i in range(len(self.blocks))
400398
):
401399
# some reference -> copy full dataframe
402400
# 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
@@ -214,3 +214,18 @@ def test_chained_methods(request, method, idx, using_copy_on_write):
214214
df.iloc[0, 0] = 0
215215
if not df2_is_view:
216216
tm.assert_frame_equal(df2.iloc[:, idx:], df_orig)
217+
218+
219+
def test_putmask(using_copy_on_write):
220+
df = DataFrame({"a": [1, 2], "b": 1, "c": 2})
221+
view = df[:]
222+
df_orig = df.copy()
223+
df[df == df] = 5
224+
225+
if using_copy_on_write:
226+
assert not np.shares_memory(get_array(view, "a"), get_array(df, "a"))
227+
tm.assert_frame_equal(view, df_orig)
228+
else:
229+
# Without CoW the original will be modified
230+
assert np.shares_memory(get_array(view, "a"), get_array(df, "a"))
231+
assert view.iloc[0, 0] == 5

0 commit comments

Comments
 (0)