18
18
from pandas ._config import (
19
19
get_option ,
20
20
using_copy_on_write ,
21
+ warn_copy_on_write ,
21
22
)
22
23
23
24
from pandas ._libs import (
136
137
_dtype_obj = np .dtype ("object" )
137
138
138
139
140
+ COW_WARNING_GENERAL_MSG = """\
141
+ Setting a value on a view: behaviour will change in pandas 3.0.
142
+ You are mutating a Series or DataFrame object, and currently this mutation will
143
+ also have effect on other Series or DataFrame objects that share data with this
144
+ object. In pandas 3.0 (with Copy-on-Write), updating one Series or DataFrame object
145
+ will never modify another.
146
+ """
147
+
148
+
149
+ COW_WARNING_SETITEM_MSG = """\
150
+ Setting a value on a view: behaviour will change in pandas 3.0.
151
+ Currently, the mutation will also have effect on the object that shares data
152
+ with this object. For example, when setting a value in a Series that was
153
+ extracted from a column of a DataFrame, that DataFrame will also be updated:
154
+
155
+ ser = df["col"]
156
+ ser[0] = 0 <--- in pandas 2, this also updates `df`
157
+
158
+ In pandas 3.0 (with Copy-on-Write), updating one Series/DataFrame will never
159
+ modify another, and thus in the example above, `df` will not be changed.
160
+ """
161
+
162
+
139
163
def maybe_split (meth : F ) -> F :
140
164
"""
141
165
If we have a multi-column block, split and operate block-wise. Otherwise
@@ -1355,7 +1379,9 @@ def setitem(self, indexer, value, using_cow: bool = False) -> Block:
1355
1379
values [indexer ] = casted
1356
1380
return self
1357
1381
1358
- def putmask (self , mask , new , using_cow : bool = False ) -> list [Block ]:
1382
+ def putmask (
1383
+ self , mask , new , using_cow : bool = False , already_warned = None
1384
+ ) -> list [Block ]:
1359
1385
"""
1360
1386
putmask the data to the block; it is possible that we may create a
1361
1387
new dtype of block
@@ -1388,6 +1414,19 @@ def putmask(self, mask, new, using_cow: bool = False) -> list[Block]:
1388
1414
return [self .copy (deep = False )]
1389
1415
return [self ]
1390
1416
1417
+ if (
1418
+ warn_copy_on_write ()
1419
+ and already_warned is not None
1420
+ and not already_warned .warned_already
1421
+ ):
1422
+ if self .refs .has_reference ():
1423
+ warnings .warn (
1424
+ COW_WARNING_GENERAL_MSG ,
1425
+ FutureWarning ,
1426
+ stacklevel = find_stack_level (),
1427
+ )
1428
+ already_warned .warned_already = True
1429
+
1391
1430
try :
1392
1431
casted = np_can_hold_element (values .dtype , new )
1393
1432
@@ -2020,7 +2059,9 @@ def where(
2020
2059
return [nb ]
2021
2060
2022
2061
@final
2023
- def putmask (self , mask , new , using_cow : bool = False ) -> list [Block ]:
2062
+ def putmask (
2063
+ self , mask , new , using_cow : bool = False , already_warned = None
2064
+ ) -> list [Block ]:
2024
2065
"""
2025
2066
See Block.putmask.__doc__
2026
2067
"""
@@ -2038,6 +2079,19 @@ def putmask(self, mask, new, using_cow: bool = False) -> list[Block]:
2038
2079
return [self .copy (deep = False )]
2039
2080
return [self ]
2040
2081
2082
+ if (
2083
+ warn_copy_on_write ()
2084
+ and already_warned is not None
2085
+ and not already_warned .warned_already
2086
+ ):
2087
+ if self .refs .has_reference ():
2088
+ warnings .warn (
2089
+ COW_WARNING_GENERAL_MSG ,
2090
+ FutureWarning ,
2091
+ stacklevel = find_stack_level (),
2092
+ )
2093
+ already_warned .warned_already = True
2094
+
2041
2095
self = self ._maybe_copy (using_cow , inplace = True )
2042
2096
values = self .values
2043
2097
if values .ndim == 2 :
0 commit comments