Skip to content

Commit

Permalink
add tm.assert_cow_warning and use everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
jorisvandenbossche committed Oct 27, 2023
1 parent 6e9f3ff commit f7fa78e
Show file tree
Hide file tree
Showing 13 changed files with 59 additions and 42 deletions.
2 changes: 2 additions & 0 deletions pandas/_testing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
get_obj,
)
from pandas._testing.contexts import (
assert_cow_warning,
decompress_file,
ensure_clean,
raises_chained_assignment_error,
Expand Down Expand Up @@ -1097,6 +1098,7 @@ def shares_memory(left, right) -> bool:
"assert_series_equal",
"assert_sp_array_equal",
"assert_timedelta_array_equal",
"assert_cow_warning",
"at",
"BOOL_DTYPES",
"box_expected",
Expand Down
26 changes: 26 additions & 0 deletions pandas/_testing/contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,29 @@ def raises_chained_assignment_error(extra_warnings=(), extra_match=()):
(ChainedAssignmentError, *extra_warnings),
match="|".join((match, *extra_match)),
)


def assert_cow_warning(warn=True, match=None, **kwargs):
"""
Assert that a warning is raised in the CoW warning mode.
Parameters
----------
warn : bool, default True
By default, check that a warning is raised. Can be turned off by passing False.
match : str
The warning message to match against, if different from the default.
kwargs
Passed through to assert_produces_warning
"""
from pandas._testing import assert_produces_warning

if not warn:
from contextlib import nullcontext

return nullcontext()

if not match:
match = "Setting a value on a view"

return assert_produces_warning(FutureWarning, match=match, **kwargs)
5 changes: 2 additions & 3 deletions pandas/tests/copy_view/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,7 @@ def test_column_as_series(
s[0] = 0
else:
if warn_copy_on_write:
with tm.assert_produces_warning(FutureWarning):
with tm.assert_cow_warning():
s[0] = 0
else:
warn = SettingWithCopyWarning if dtype_backend == "numpy" else None
Expand Down Expand Up @@ -939,8 +939,7 @@ def test_column_as_series_set_with_upcast(

s = df["a"]
if dtype_backend == "nullable":
warn = FutureWarning if warn_copy_on_write else None
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
with pytest.raises(TypeError, match="Invalid value"):
s[0] = "foo"
expected = Series([1, 2, 3], name="a")
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/copy_view/test_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -1706,8 +1706,7 @@ def test_xs(
if using_copy_on_write or is_view:
result.iloc[0] = 0
elif warn_copy_on_write:
warn = FutureWarning if single_block else None
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(single_block):
result.iloc[0] = 0
else:
with pd.option_context("chained_assignment", "warn"):
Expand Down
4 changes: 1 addition & 3 deletions pandas/tests/copy_view/test_setitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,7 @@ def test_set_column_with_inplace_operator(using_copy_on_write, warn_copy_on_writ
df["a"] += 1

# when it is not in a chain, then it should produce a warning
warn = FutureWarning if warn_copy_on_write else None

df = DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
ser = df["a"]
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
ser += 1
3 changes: 1 addition & 2 deletions pandas/tests/frame/indexing/test_setitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -1292,8 +1292,7 @@ def test_setitem_column_update_inplace(
values = df._mgr.blocks[0].values

if not using_copy_on_write:
warn = FutureWarning if warn_copy_on_write else None
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
for label in df.columns:
df[label][label] = 1

Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/frame/test_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2036,8 +2036,7 @@ def test_inplace_arithmetic_series_update(using_copy_on_write, warn_copy_on_writ
series = df["A"]
vals = series._values

warn = FutureWarning if warn_copy_on_write else None
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
series += 1
if using_copy_on_write:
assert series._values is not vals
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/frame/test_block_internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ def test_stale_cached_series_bug_473(self, using_copy_on_write, warn_copy_on_wri
with tm.raises_chained_assignment_error():
Y["g"]["c"] = np.nan
elif warn_copy_on_write:
with tm.assert_produces_warning(FutureWarning):
with tm.assert_cow_warning():
Y["g"]["c"] = np.nan
else:
Y["g"]["c"] = np.nan
Expand Down
6 changes: 2 additions & 4 deletions pandas/tests/frame/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,7 @@ def test_constructor_dtype_nocast_view_dataframe(
should_be_view.iloc[0, 0] = 99
assert df.values[0, 0] == 1
else:
warn = FutureWarning if warn_copy_on_write else None
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
should_be_view[0][0] = 99
assert df.values[0, 0] == 99

Expand All @@ -313,8 +312,7 @@ def test_constructor_dtype_nocast_view_2d_array(
df = DataFrame([[1, 2], [3, 4]], dtype="int64")
if not using_array_manager and not using_copy_on_write:
should_be_view = DataFrame(df.values, dtype=df[0].dtype)
warn = FutureWarning if warn_copy_on_write else None
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
should_be_view[0][0] = 97
assert df.values[0, 0] == 97
else:
Expand Down
9 changes: 4 additions & 5 deletions pandas/tests/indexing/multiindex/test_setitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,14 +279,13 @@ def test_series_setitem(
ymd = multiindex_year_month_day_dataframe_random_data
s = ymd["A"]

warn = FutureWarning if warn_copy_on_write else None
with tm.assert_produces_warning(warn, match="Setting a value on a view"):
with tm.assert_cow_warning(warn_copy_on_write):
s[2000, 3] = np.nan
assert isna(s.values[42:65]).all()
assert notna(s.values[:42]).all()
assert notna(s.values[65:]).all()

with tm.assert_produces_warning(warn, match="Setting a value on a view"):
with tm.assert_cow_warning(warn_copy_on_write):
s[2000, 3, 10] = np.nan
assert isna(s.iloc[49])

Expand Down Expand Up @@ -541,7 +540,7 @@ def test_frame_setitem_copy_raises(
df["foo"]["one"] = 2
elif warn_copy_on_write:
# TODO(CoW-warn) should warn
with tm.assert_produces_warning(None):
with tm.assert_cow_warning(False):
df["foo"]["one"] = 2
else:
msg = "A value is trying to be set on a copy of a slice from a DataFrame"
Expand All @@ -560,7 +559,7 @@ def test_frame_setitem_copy_no_write(
df["foo"]["one"] = 2
elif warn_copy_on_write:
# TODO(CoW-warn) should warn
with tm.assert_produces_warning(None):
with tm.assert_cow_warning(False):
df["foo"]["one"] = 2
else:
msg = "A value is trying to be set on a copy of a slice from a DataFrame"
Expand Down
29 changes: 14 additions & 15 deletions pandas/tests/indexing/test_chaining_and_caching.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,9 @@ def test_detect_chained_assignment(self, using_copy_on_write, warn_copy_on_write
df["A"][1] = -6
tm.assert_frame_equal(df, df_original)
else:
warn = FutureWarning if warn_copy_on_write else None
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
df["A"][0] = -5
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
df["A"][1] = -6
tm.assert_frame_equal(df, expected)

Expand All @@ -246,9 +245,9 @@ def test_detect_chained_assignment_raises(
df["A"][1] = -6
tm.assert_frame_equal(df, df_original)
elif warn_copy_on_write:
with tm.assert_produces_warning(FutureWarning):
with tm.assert_cow_warning():
df["A"][0] = -5
with tm.assert_produces_warning(FutureWarning):
with tm.assert_cow_warning():
df["A"][1] = np.nan
elif not using_array_manager:
with pytest.raises(SettingWithCopyError, match=msg):
Expand Down Expand Up @@ -283,8 +282,8 @@ def test_detect_chained_assignment_fails(
with tm.raises_chained_assignment_error():
df.loc[0]["A"] = -5
elif warn_copy_on_write:
# TODO(CoW) should warn
with tm.assert_produces_warning(None):
# TODO(CoW-warn) should warn
with tm.assert_cow_warning(False):
df.loc[0]["A"] = -5
else:
with pytest.raises(SettingWithCopyError, match=msg):
Expand All @@ -308,8 +307,8 @@ def test_detect_chained_assignment_doc_example(
with tm.raises_chained_assignment_error():
df[indexer]["c"] = 42
elif warn_copy_on_write:
# TODO(CoW) should warn
with tm.assert_produces_warning(None):
# TODO(CoW-warn) should warn
with tm.assert_cow_warning(False):
df[indexer]["c"] = 42
else:
with pytest.raises(SettingWithCopyError, match=msg):
Expand All @@ -333,7 +332,7 @@ def test_detect_chained_assignment_object_dtype(
tm.assert_frame_equal(df, df_original)
elif warn_copy_on_write:
# TODO(CoW-warn) should give different message
with tm.assert_produces_warning(FutureWarning):
with tm.assert_cow_warning():
df["A"][0] = 111
tm.assert_frame_equal(df, expected)
elif not using_array_manager:
Expand Down Expand Up @@ -463,7 +462,7 @@ def test_detect_chained_assignment_undefined_column(
tm.assert_frame_equal(df, df_original)
elif warn_copy_on_write:
# TODO(CoW-warn) should warn
with tm.assert_produces_warning(None):
with tm.assert_cow_warning(False):
df.iloc[0:5]["group"] = "a"
else:
with pytest.raises(SettingWithCopyError, match=msg):
Expand Down Expand Up @@ -494,10 +493,10 @@ def test_detect_chained_assignment_changing_dtype(
tm.assert_frame_equal(df, df_original)
elif warn_copy_on_write:
# TODO(CoW-warn) should warn
with tm.assert_produces_warning(None):
with tm.assert_cow_warning(False):
df.loc[2]["D"] = "foo"
# TODO(CoW-warn) should give different message
with tm.assert_produces_warning(FutureWarning):
with tm.assert_cow_warning():
df["C"][2] = "foo"
else:
with pytest.raises(SettingWithCopyError, match=msg):
Expand Down Expand Up @@ -529,7 +528,7 @@ def test_setting_with_copy_bug(self, using_copy_on_write, warn_copy_on_write):
tm.assert_frame_equal(df, df_original)
elif warn_copy_on_write:
# TODO(CoW-warn) should warn
with tm.assert_produces_warning(None):
with tm.assert_cow_warning(False):
df[["c"]][mask] = df[["b"]][mask]
else:
with pytest.raises(SettingWithCopyError, match=msg):
Expand All @@ -554,7 +553,7 @@ def test_detect_chained_assignment_warnings_errors(
return
elif warn_copy_on_write:
# TODO(CoW-warn) should warn
with tm.assert_produces_warning(None):
with tm.assert_cow_warning(False):
df.loc[0]["A"] = 111
return

Expand Down
6 changes: 3 additions & 3 deletions pandas/tests/series/accessors/test_dt_accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,9 @@ def test_dt_accessor_not_writeable(self, using_copy_on_write, warn_copy_on_write
with tm.raises_chained_assignment_error():
ser.dt.hour[0] = 5
elif warn_copy_on_write:
# TODO should warn
# with tm.assert_produces_warning(FutureWarning):
ser.dt.hour[0] = 5
# TODO(CoW-warn) should warn
with tm.assert_cow_warning(False):
ser.dt.hour[0] = 5
else:
with pytest.raises(SettingWithCopyError, match=msg):
ser.dt.hour[0] = 5
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/series/methods/test_rename.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,7 @@ def test_rename_copy_false(self, using_copy_on_write, warn_copy_on_write):
ser = Series(["foo", "bar"])
ser_orig = ser.copy()
shallow_copy = ser.rename({1: 9}, copy=False)
warn = FutureWarning if warn_copy_on_write else None
with tm.assert_produces_warning(warn):
with tm.assert_cow_warning(warn_copy_on_write):
ser[0] = "foobar"
if using_copy_on_write:
assert ser_orig[0] == shallow_copy[0]
Expand Down

0 comments on commit f7fa78e

Please sign in to comment.