Skip to content

Commit 6c2a9d8

Browse files
Backport PR #36051: BUG: frame._item_cache not cleared when Series is altered (#36072)
Co-authored-by: jbrockmendel <[email protected]>
1 parent 9bc223e commit 6c2a9d8

File tree

4 files changed

+31
-4
lines changed

4 files changed

+31
-4
lines changed

doc/source/whatsnew/v1.1.2.rst

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Bug fixes
3131
- Bug in :meth:`DataFrame.apply` with ``result_type="reduce"`` returning with incorrect index (:issue:`35683`)
3232
- Bug in :meth:`DateTimeIndex.format` and :meth:`PeriodIndex.format` with ``name=True`` setting the first item to ``"None"`` where it should bw ``""`` (:issue:`35712`)
3333
- Bug in :meth:`Float64Index.__contains__` incorrectly raising ``TypeError`` instead of returning ``False`` (:issue:`35788`)
34+
- Bug in :class:`DataFrame` indexing returning an incorrect :class:`Series` in some cases when the series has been altered and a cache not invalidated (:issue:`36051`)
3435

3536
.. ---------------------------------------------------------------------------
3637

pandas/core/generic.py

+4
Original file line numberDiff line numberDiff line change
@@ -3233,6 +3233,10 @@ def _maybe_update_cacher(
32333233
if len(self) == len(ref):
32343234
# otherwise, either self or ref has swapped in new arrays
32353235
ref._maybe_cache_changed(cacher[0], self)
3236+
else:
3237+
# GH#33675 we have swapped in a new array, so parent
3238+
# reference to self is now invalid
3239+
ref._item_cache.pop(cacher[0], None)
32363240

32373241
if verify_is_copy:
32383242
self._check_setitem_copy(stacklevel=5, t="referant")

pandas/tests/frame/test_missing.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,20 @@ def test_drop_and_dropna_caching(self):
135135
df2 = df.copy()
136136
df["A"].dropna()
137137
tm.assert_series_equal(df["A"], original)
138-
return_value = df["A"].dropna(inplace=True)
139-
tm.assert_series_equal(df["A"], expected)
138+
139+
ser = df["A"]
140+
return_value = ser.dropna(inplace=True)
141+
tm.assert_series_equal(ser, expected)
142+
tm.assert_series_equal(df["A"], original)
140143
assert return_value is None
144+
141145
df2["A"].drop([1])
142146
tm.assert_series_equal(df2["A"], original)
143-
return_value = df2["A"].drop([1], inplace=True)
144-
tm.assert_series_equal(df2["A"], original.drop([1]))
147+
148+
ser = df2["A"]
149+
return_value = ser.drop([1], inplace=True)
150+
tm.assert_series_equal(ser, original.drop([1]))
151+
tm.assert_series_equal(df2["A"], original)
145152
assert return_value is None
146153

147154
def test_dropna_corner(self, float_frame):

pandas/tests/indexing/test_chaining_and_caching.py

+15
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,21 @@ def test_setitem_cache_updating(self):
8181
tm.assert_frame_equal(out, expected)
8282
tm.assert_series_equal(out["A"], expected["A"])
8383

84+
def test_altering_series_clears_parent_cache(self):
85+
# GH #33675
86+
df = pd.DataFrame([[1, 2], [3, 4]], index=["a", "b"], columns=["A", "B"])
87+
ser = df["A"]
88+
89+
assert "A" in df._item_cache
90+
91+
# Adding a new entry to ser swaps in a new array, so "A" needs to
92+
# be removed from df._item_cache
93+
ser["c"] = 5
94+
assert len(ser) == 3
95+
assert "A" not in df._item_cache
96+
assert df["A"] is not ser
97+
assert len(df["A"]) == 2
98+
8499

85100
class TestChaining:
86101
def test_setitem_chained_setfault(self):

0 commit comments

Comments
 (0)