Skip to content

Commit 34a69a2

Browse files
[backport 2.3.x] CoW: disable chained assignment detection for Python 3.14 (#62324) (#62375)
Co-authored-by: Nathan Goldbaum <nathan.goldbaum@gmail.com>
1 parent a25f560 commit 34a69a2

18 files changed

+130
-44
lines changed

.github/workflows/unit-tests.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,5 +406,3 @@ jobs:
406406
407407
- name: Run Tests
408408
uses: ./.github/actions/run-tests
409-
# TEMP allow this to fail until we fixed all test failures (related to chained assignment warnings)
410-
continue-on-error: true

pandas/_testing/contexts.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
from pandas._config import using_copy_on_write
1515

16-
from pandas.compat import PYPY
16+
from pandas.compat import (
17+
PYPY,
18+
WARNING_CHECK_DISABLED,
19+
)
1720
from pandas.errors import ChainedAssignmentError
1821

1922
from pandas import set_option
@@ -204,11 +207,11 @@ def raises_chained_assignment_error(warn=True, extra_warnings=(), extra_match=()
204207

205208
return nullcontext()
206209

207-
if PYPY and not extra_warnings:
210+
if (PYPY or WARNING_CHECK_DISABLED) and not extra_warnings:
208211
from contextlib import nullcontext
209212

210213
return nullcontext()
211-
elif PYPY and extra_warnings:
214+
elif (PYPY or WARNING_CHECK_DISABLED) and extra_warnings:
212215
return assert_produces_warning(
213216
extra_warnings,
214217
match="|".join(extra_match),
@@ -247,7 +250,7 @@ def assert_cow_warning(warn=True, match=None, **kwargs):
247250
"""
248251
from pandas._testing import assert_produces_warning
249252

250-
if not warn:
253+
if not warn or WARNING_CHECK_DISABLED:
251254
from contextlib import nullcontext
252255

253256
return nullcontext()

pandas/compat/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
PY312,
2323
PY314,
2424
PYPY,
25+
WARNING_CHECK_DISABLED,
2526
)
2627
import pandas.compat.compressors
2728
from pandas.compat.numpy import is_numpy_dev
@@ -208,4 +209,5 @@ def get_bz2_file() -> type[pandas.compat.compressors.BZ2File]:
208209
"PY312",
209210
"PY314",
210211
"PYPY",
212+
"WARNING_CHECK_DISABLED",
211213
]

pandas/compat/_constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
PYPY = platform.python_implementation() == "PyPy"
2121
ISMUSL = "musl" in (sysconfig.get_config_var("HOST_GNU_TYPE") or "")
2222
REF_COUNT = 2 if PY311 else 3
23+
WARNING_CHECK_DISABLED = PY314
24+
2325

2426
__all__ = [
2527
"IS64",

pandas/core/frame.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@
5454
from pandas._libs.hashtable import duplicated
5555
from pandas._libs.lib import is_range_indexer
5656
from pandas.compat import PYPY
57-
from pandas.compat._constants import REF_COUNT
57+
from pandas.compat._constants import (
58+
REF_COUNT,
59+
WARNING_CHECK_DISABLED,
60+
)
5861
from pandas.compat._optional import import_optional_dependency
5962
from pandas.compat.numpy import function as nv
6063
from pandas.errors import (
@@ -4274,12 +4277,12 @@ def isetitem(self, loc, value) -> None:
42744277
self._iset_item_mgr(loc, arraylike, inplace=False, refs=refs)
42754278

42764279
def __setitem__(self, key, value) -> None:
4277-
if not PYPY and using_copy_on_write():
4280+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
42784281
if sys.getrefcount(self) <= 3:
42794282
warnings.warn(
42804283
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
42814284
)
4282-
elif not PYPY and not using_copy_on_write():
4285+
elif not PYPY and not WARNING_CHECK_DISABLED and not using_copy_on_write():
42834286
if sys.getrefcount(self) <= 3 and (
42844287
warn_copy_on_write()
42854288
or (
@@ -8983,14 +8986,19 @@ def update(
89838986
2 3 6.0
89848987
"""
89858988

8986-
if not PYPY and using_copy_on_write():
8989+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
89878990
if sys.getrefcount(self) <= REF_COUNT:
89888991
warnings.warn(
89898992
_chained_assignment_method_msg,
89908993
ChainedAssignmentError,
89918994
stacklevel=2,
89928995
)
8993-
elif not PYPY and not using_copy_on_write() and self._is_view_after_cow_rules():
8996+
elif (
8997+
not PYPY
8998+
and not WARNING_CHECK_DISABLED
8999+
and not using_copy_on_write()
9000+
and self._is_view_after_cow_rules()
9001+
):
89949002
if sys.getrefcount(self) <= REF_COUNT:
89959003
warnings.warn(
89969004
_chained_assignment_warning_method_msg,

pandas/core/generic.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@
9090
npt,
9191
)
9292
from pandas.compat import PYPY
93-
from pandas.compat._constants import REF_COUNT
93+
from pandas.compat._constants import (
94+
REF_COUNT,
95+
WARNING_CHECK_DISABLED,
96+
)
9497
from pandas.compat._optional import import_optional_dependency
9598
from pandas.compat.numpy import function as nv
9699
from pandas.errors import (
@@ -7285,7 +7288,7 @@ def fillna(
72857288
"""
72867289
inplace = validate_bool_kwarg(inplace, "inplace")
72877290
if inplace:
7288-
if not PYPY and using_copy_on_write():
7291+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
72897292
if sys.getrefcount(self) <= REF_COUNT:
72907293
warnings.warn(
72917294
_chained_assignment_method_msg,
@@ -7294,6 +7297,7 @@ def fillna(
72947297
)
72957298
elif (
72967299
not PYPY
7300+
and not WARNING_CHECK_DISABLED
72977301
and not using_copy_on_write()
72987302
and self._is_view_after_cow_rules()
72997303
):
@@ -7588,7 +7592,7 @@ def ffill(
75887592
downcast = self._deprecate_downcast(downcast, "ffill")
75897593
inplace = validate_bool_kwarg(inplace, "inplace")
75907594
if inplace:
7591-
if not PYPY and using_copy_on_write():
7595+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
75927596
if sys.getrefcount(self) <= REF_COUNT:
75937597
warnings.warn(
75947598
_chained_assignment_method_msg,
@@ -7597,6 +7601,7 @@ def ffill(
75977601
)
75987602
elif (
75997603
not PYPY
7604+
and not WARNING_CHECK_DISABLED
76007605
and not using_copy_on_write()
76017606
and self._is_view_after_cow_rules()
76027607
):
@@ -7792,7 +7797,7 @@ def bfill(
77927797
downcast = self._deprecate_downcast(downcast, "bfill")
77937798
inplace = validate_bool_kwarg(inplace, "inplace")
77947799
if inplace:
7795-
if not PYPY and using_copy_on_write():
7800+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
77967801
if sys.getrefcount(self) <= REF_COUNT:
77977802
warnings.warn(
77987803
_chained_assignment_method_msg,
@@ -7801,6 +7806,7 @@ def bfill(
78017806
)
78027807
elif (
78037808
not PYPY
7809+
and not WARNING_CHECK_DISABLED
78047810
and not using_copy_on_write()
78057811
and self._is_view_after_cow_rules()
78067812
):
@@ -7963,7 +7969,7 @@ def replace(
79637969

79647970
inplace = validate_bool_kwarg(inplace, "inplace")
79657971
if inplace:
7966-
if not PYPY and using_copy_on_write():
7972+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
79677973
if sys.getrefcount(self) <= REF_COUNT:
79687974
warnings.warn(
79697975
_chained_assignment_method_msg,
@@ -7972,6 +7978,7 @@ def replace(
79727978
)
79737979
elif (
79747980
not PYPY
7981+
and not WARNING_CHECK_DISABLED
79757982
and not using_copy_on_write()
79767983
and self._is_view_after_cow_rules()
79777984
):
@@ -8415,7 +8422,7 @@ def interpolate(
84158422
inplace = validate_bool_kwarg(inplace, "inplace")
84168423

84178424
if inplace:
8418-
if not PYPY and using_copy_on_write():
8425+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
84198426
if sys.getrefcount(self) <= REF_COUNT:
84208427
warnings.warn(
84218428
_chained_assignment_method_msg,
@@ -8424,6 +8431,7 @@ def interpolate(
84248431
)
84258432
elif (
84268433
not PYPY
8434+
and not WARNING_CHECK_DISABLED
84278435
and not using_copy_on_write()
84288436
and self._is_view_after_cow_rules()
84298437
):
@@ -9057,7 +9065,7 @@ def clip(
90579065
inplace = validate_bool_kwarg(inplace, "inplace")
90589066

90599067
if inplace:
9060-
if not PYPY and using_copy_on_write():
9068+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
90619069
if sys.getrefcount(self) <= REF_COUNT:
90629070
warnings.warn(
90639071
_chained_assignment_method_msg,
@@ -9066,6 +9074,7 @@ def clip(
90669074
)
90679075
elif (
90689076
not PYPY
9077+
and not WARNING_CHECK_DISABLED
90699078
and not using_copy_on_write()
90709079
and self._is_view_after_cow_rules()
90719080
):
@@ -10975,7 +10984,7 @@ def where(
1097510984
"""
1097610985
inplace = validate_bool_kwarg(inplace, "inplace")
1097710986
if inplace:
10978-
if not PYPY and using_copy_on_write():
10987+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
1097910988
if sys.getrefcount(self) <= REF_COUNT:
1098010989
warnings.warn(
1098110990
_chained_assignment_method_msg,
@@ -10984,6 +10993,7 @@ def where(
1098410993
)
1098510994
elif (
1098610995
not PYPY
10996+
and not WARNING_CHECK_DISABLED
1098710997
and not using_copy_on_write()
1098810998
and self._is_view_after_cow_rules()
1098910999
):
@@ -11058,7 +11068,7 @@ def mask(
1105811068
) -> Self | None:
1105911069
inplace = validate_bool_kwarg(inplace, "inplace")
1106011070
if inplace:
11061-
if not PYPY and using_copy_on_write():
11071+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
1106211072
if sys.getrefcount(self) <= REF_COUNT:
1106311073
warnings.warn(
1106411074
_chained_assignment_method_msg,
@@ -11067,6 +11077,7 @@ def mask(
1106711077
)
1106811078
elif (
1106911079
not PYPY
11080+
and not WARNING_CHECK_DISABLED
1107011081
and not using_copy_on_write()
1107111082
and self._is_view_after_cow_rules()
1107211083
):

pandas/core/indexing.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from pandas._libs.indexing import NDFrameIndexerBase
2222
from pandas._libs.lib import item_from_zerodim
2323
from pandas.compat import PYPY
24+
from pandas.compat._constants import WARNING_CHECK_DISABLED
2425
from pandas.errors import (
2526
AbstractMethodError,
2627
ChainedAssignmentError,
@@ -881,12 +882,12 @@ def _ensure_listlike_indexer(self, key, axis=None, value=None) -> None:
881882

882883
@final
883884
def __setitem__(self, key, value) -> None:
884-
if not PYPY and using_copy_on_write():
885+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
885886
if sys.getrefcount(self.obj) <= 2:
886887
warnings.warn(
887888
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
888889
)
889-
elif not PYPY and not using_copy_on_write():
890+
elif not PYPY and not WARNING_CHECK_DISABLED and not using_copy_on_write():
890891
ctr = sys.getrefcount(self.obj)
891892
ref_count = 2
892893
if not warn_copy_on_write() and _check_cacher(self.obj):
@@ -2575,12 +2576,12 @@ def __getitem__(self, key):
25752576
return super().__getitem__(key)
25762577

25772578
def __setitem__(self, key, value) -> None:
2578-
if not PYPY and using_copy_on_write():
2579+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
25792580
if sys.getrefcount(self.obj) <= 2:
25802581
warnings.warn(
25812582
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
25822583
)
2583-
elif not PYPY and not using_copy_on_write():
2584+
elif not PYPY and not WARNING_CHECK_DISABLED and not using_copy_on_write():
25842585
ctr = sys.getrefcount(self.obj)
25852586
ref_count = 2
25862587
if not warn_copy_on_write() and _check_cacher(self.obj):
@@ -2616,12 +2617,12 @@ def _convert_key(self, key):
26162617
return key
26172618

26182619
def __setitem__(self, key, value) -> None:
2619-
if not PYPY and using_copy_on_write():
2620+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
26202621
if sys.getrefcount(self.obj) <= 2:
26212622
warnings.warn(
26222623
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
26232624
)
2624-
elif not PYPY and not using_copy_on_write():
2625+
elif not PYPY and not WARNING_CHECK_DISABLED and not using_copy_on_write():
26252626
ctr = sys.getrefcount(self.obj)
26262627
ref_count = 2
26272628
if not warn_copy_on_write() and _check_cacher(self.obj):

pandas/core/series.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
)
4040
from pandas._libs.lib import is_range_indexer
4141
from pandas.compat import PYPY
42-
from pandas.compat._constants import REF_COUNT
42+
from pandas.compat._constants import (
43+
REF_COUNT,
44+
WARNING_CHECK_DISABLED,
45+
)
4346
from pandas.compat._optional import import_optional_dependency
4447
from pandas.compat.numpy import function as nv
4548
from pandas.errors import (
@@ -1269,12 +1272,12 @@ def _get_value(self, label, takeable: bool = False):
12691272

12701273
def __setitem__(self, key, value) -> None:
12711274
warn = True
1272-
if not PYPY and using_copy_on_write():
1275+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
12731276
if sys.getrefcount(self) <= 3:
12741277
warnings.warn(
12751278
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
12761279
)
1277-
elif not PYPY and not using_copy_on_write():
1280+
elif not PYPY and not WARNING_CHECK_DISABLED and not using_copy_on_write():
12781281
ctr = sys.getrefcount(self)
12791282
ref_count = 3
12801283
if not warn_copy_on_write() and _check_cacher(self):
@@ -3621,14 +3624,19 @@ def update(self, other: Series | Sequence | Mapping) -> None:
36213624
2 3
36223625
dtype: int64
36233626
"""
3624-
if not PYPY and using_copy_on_write():
3627+
if not PYPY and not WARNING_CHECK_DISABLED and using_copy_on_write():
36253628
if sys.getrefcount(self) <= REF_COUNT:
36263629
warnings.warn(
36273630
_chained_assignment_method_msg,
36283631
ChainedAssignmentError,
36293632
stacklevel=2,
36303633
)
3631-
elif not PYPY and not using_copy_on_write() and self._is_view_after_cow_rules():
3634+
elif (
3635+
not PYPY
3636+
and not WARNING_CHECK_DISABLED
3637+
and not using_copy_on_write()
3638+
and self._is_view_after_cow_rules()
3639+
):
36323640
ctr = sys.getrefcount(self)
36333641
ref_count = REF_COUNT
36343642
if _check_cacher(self):

pandas/tests/copy_view/test_chained_assignment_deprecation.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import numpy as np
22
import pytest
33

4-
from pandas.compat import PY311
4+
from pandas.compat import (
5+
PY311,
6+
WARNING_CHECK_DISABLED,
7+
)
58
from pandas.errors import (
69
ChainedAssignmentError,
710
SettingWithCopyWarning,
@@ -150,6 +153,9 @@ def test_series_setitem(indexer, using_copy_on_write, warn_copy_on_write):
150153

151154
# using custom check instead of tm.assert_produces_warning because that doesn't
152155
# fail if multiple warnings are raised
156+
if WARNING_CHECK_DISABLED:
157+
return
158+
153159
with pytest.warns() as record:
154160
df["a"][indexer] = 0
155161
assert len(record) == 1

0 commit comments

Comments
 (0)