Skip to content

Commit 6a11b76

Browse files
committed
CoW: Fix deprecation warning for chained assignment
1 parent 24fdde6 commit 6a11b76

File tree

5 files changed

+67
-7
lines changed

5 files changed

+67
-7
lines changed

pandas/core/generic.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
SettingWithCopyWarning,
102102
_chained_assignment_method_msg,
103103
_chained_assignment_warning_method_msg,
104+
_check_cacher,
104105
)
105106
from pandas.util._decorators import (
106107
deprecate_nonkeyword_arguments,
@@ -7195,7 +7196,7 @@ def fillna(
71957196
elif not PYPY and not using_copy_on_write():
71967197
ctr = sys.getrefcount(self)
71977198
ref_count = REF_COUNT
7198-
if isinstance(self, ABCSeries) and hasattr(self, "_cacher"):
7199+
if isinstance(self, ABCSeries) and _check_cacher(self):
71997200
# see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221
72007201
ref_count += 1
72017202
if ctr <= ref_count:
@@ -7477,7 +7478,7 @@ def ffill(
74777478
elif not PYPY and not using_copy_on_write():
74787479
ctr = sys.getrefcount(self)
74797480
ref_count = REF_COUNT
7480-
if isinstance(self, ABCSeries) and hasattr(self, "_cacher"):
7481+
if isinstance(self, ABCSeries) and _check_cacher(self):
74817482
# see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221
74827483
ref_count += 1
74837484
if ctr <= ref_count:
@@ -7660,7 +7661,7 @@ def bfill(
76607661
elif not PYPY and not using_copy_on_write():
76617662
ctr = sys.getrefcount(self)
76627663
ref_count = REF_COUNT
7663-
if isinstance(self, ABCSeries) and hasattr(self, "_cacher"):
7664+
if isinstance(self, ABCSeries) and _check_cacher(self):
76647665
# see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221
76657666
ref_count += 1
76667667
if ctr <= ref_count:
@@ -7826,12 +7827,12 @@ def replace(
78267827
elif not PYPY and not using_copy_on_write():
78277828
ctr = sys.getrefcount(self)
78287829
ref_count = REF_COUNT
7829-
if isinstance(self, ABCSeries) and hasattr(self, "_cacher"):
7830+
if isinstance(self, ABCSeries) and _check_cacher(self):
78307831
# in non-CoW mode, chained Series access will populate the
78317832
# `_item_cache` which results in an increased ref count not below
78327833
# the threshold, while we still need to warn. We detect this case
78337834
# of a Series derived from a DataFrame through the presence of
7834-
# `_cacher`
7835+
# checking the `_cacher`
78357836
ref_count += 1
78367837
if ctr <= ref_count:
78377838
warnings.warn(
@@ -8267,7 +8268,7 @@ def interpolate(
82678268
elif not PYPY and not using_copy_on_write():
82688269
ctr = sys.getrefcount(self)
82698270
ref_count = REF_COUNT
8270-
if isinstance(self, ABCSeries) and hasattr(self, "_cacher"):
8271+
if isinstance(self, ABCSeries) and _check_cacher(self):
82718272
# see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221
82728273
ref_count += 1
82738274
if ctr <= ref_count:

pandas/core/series.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
_chained_assignment_method_msg,
4646
_chained_assignment_msg,
4747
_chained_assignment_warning_method_msg,
48+
_check_cacher,
4849
)
4950
from pandas.util._decorators import (
5051
Appender,
@@ -3564,7 +3565,7 @@ def update(self, other: Series | Sequence | Mapping) -> None:
35643565
elif not PYPY and not using_copy_on_write():
35653566
ctr = sys.getrefcount(self)
35663567
ref_count = REF_COUNT
3567-
if hasattr(self, "_cacher"):
3568+
if _check_cacher(self):
35683569
# see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221
35693570
ref_count += 1
35703571
if ctr <= ref_count:

pandas/errors/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,21 @@ class ChainedAssignmentError(Warning):
516516
)
517517

518518

519+
def _check_cacher(obj):
520+
# This is a mess, selection paths that return a view set the _cacher attribute
521+
# on the Series; most of them also set _item_cache which adds 1 to our relevant
522+
# reference count, but iloc does not, so we have to check if we are actually
523+
# in the item cache
524+
if hasattr(obj, "_cacher"):
525+
parent = obj._cacher[1]()
526+
# parent could be dead
527+
if parent is None:
528+
return False
529+
if hasattr(parent, "_item_cache"):
530+
return obj._cacher[0] in parent._item_cache
531+
return False
532+
533+
519534
class NumExprClobberingError(NameError):
520535
"""
521536
Exception raised when trying to use a built-in numexpr name as a variable name.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import pytest
2+
3+
from pandas import DataFrame
4+
import pandas._testing as tm
5+
6+
7+
def test_methods_iloc_warn():
8+
df = DataFrame({"a": [1, 2, 3], "b": 1})
9+
with tm.assert_cow_warning(match="A value"):
10+
df.iloc[:, 0].replace(1, 5, inplace=True)
11+
12+
with tm.assert_cow_warning(match="A value"):
13+
df.iloc[:, 0].fillna(1, inplace=True)
14+
15+
with tm.assert_cow_warning(match="A value"):
16+
df.iloc[:, 0].interpolate(inplace=True)
17+
18+
with tm.assert_cow_warning(match="A value"):
19+
df.iloc[:, 0].ffill(inplace=True)
20+
21+
with tm.assert_cow_warning(match="A value"):
22+
df.iloc[:, 0].bfill(inplace=True)
23+
24+
25+
@pytest.mark.parametrize(
26+
"func, args",
27+
[
28+
("replace", (1, 5)),
29+
("fillna", (1,)),
30+
("interpolate", ()),
31+
("bfill", ()),
32+
("ffill", ()),
33+
],
34+
)
35+
def test_methods_iloc_getitem_dont_warn(func, args):
36+
df = DataFrame({"a": [1, 2, 3], "b": 1})
37+
ser = df.iloc[:, 0]
38+
getattr(ser, func)(*args, inplace=True)
39+
40+
# parent that holds item_cache is dead, so don't increase ref count
41+
ser = df.copy()["a"]
42+
getattr(ser, func)(*args, inplace=True)

scripts/validate_unwanted_patterns.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"_chained_assignment_msg",
5252
"_chained_assignment_method_msg",
5353
"_chained_assignment_warning_method_msg",
54+
"_check_cacher",
5455
"_version_meson",
5556
# The numba extensions need this to mock the iloc object
5657
"_iLocIndexer",

0 commit comments

Comments
 (0)