Skip to content

CoW: change ChainedAssignmentError exception to a warning #51926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions doc/source/user_guide/copy_on_write.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,11 @@ two subsequent indexing operations, e.g.
The column ``foo`` is updated where the column ``bar`` is greater than 5.
This violates the CoW principles though, because it would have to modify the
view ``df["foo"]`` and ``df`` in one step. Hence, chained assignment will
consistently never work and raise a ``ChainedAssignmentError`` with CoW enabled:
consistently never work and raise a ``ChainedAssignmentError`` warning
with CoW enabled:

.. ipython:: python
:okexcept:
:okwarning:

df = pd.DataFrame({"foo": [1, 2, 3], "bar": [4, 5, 6]})
df["foo"][df["bar"] > 5] = 100
Expand Down
4 changes: 2 additions & 2 deletions pandas/_testing/contexts.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ def raises_chained_assignment_error():

return nullcontext()
else:
import pytest
from pandas._testing import assert_produces_warning

return pytest.raises(
return assert_produces_warning(
ChainedAssignmentError,
match=(
"A value is trying to be set on a copy of a DataFrame or Series "
Expand Down
4 changes: 3 additions & 1 deletion pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -3946,7 +3946,9 @@ def isetitem(self, loc, value) -> None:
def __setitem__(self, key, value):
if not PYPY and using_copy_on_write():
if sys.getrefcount(self) <= 3:
raise ChainedAssignmentError(_chained_assignment_msg)
warnings.warn(
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
)

key = com.apply_if_callable(key, self)

Expand Down
5 changes: 4 additions & 1 deletion pandas/core/indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
cast,
final,
)
import warnings

import numpy as np

Expand Down Expand Up @@ -832,7 +833,9 @@ def _ensure_listlike_indexer(self, key, axis=None, value=None) -> None:
def __setitem__(self, key, value) -> None:
if not PYPY and using_copy_on_write():
if sys.getrefcount(self.obj) <= 2:
raise ChainedAssignmentError(_chained_assignment_msg)
warnings.warn(
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
)

check_dict_or_set_indexers(key)
if isinstance(key, tuple):
Expand Down
4 changes: 3 additions & 1 deletion pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,9 @@ def _get_value(self, label, takeable: bool = False):
def __setitem__(self, key, value) -> None:
if not PYPY and using_copy_on_write():
if sys.getrefcount(self) <= 3:
raise ChainedAssignmentError(_chained_assignment_msg)
warnings.warn(
_chained_assignment_msg, ChainedAssignmentError, stacklevel=2
)

check_dict_or_set_indexers(key)
key = com.apply_if_callable(key, self)
Expand Down
4 changes: 2 additions & 2 deletions pandas/errors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,9 @@ class SettingWithCopyWarning(Warning):
"""


class ChainedAssignmentError(ValueError):
class ChainedAssignmentError(Warning):
"""
Exception raised when trying to set using chained assignment.
Warning raised when trying to set using chained assignment.

When the ``mode.copy_on_write`` option is enabled, chained assignment can
never work. In such a situation, we are always setting into a temporary
Expand Down
12 changes: 6 additions & 6 deletions pandas/tests/io/test_spss.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
import numpy as np
import pytest

import pandas.util._test_decorators as td

import pandas as pd
import pandas._testing as tm

pyreadstat = pytest.importorskip("pyreadstat")


@td.skip_copy_on_write_not_yet_implemented
# TODO(CoW) - detection of chained assignment in cython
# https://github.com/pandas-dev/pandas/issues/51315
@pytest.mark.filterwarnings("ignore::pandas.errors.ChainedAssignmentError")
@pytest.mark.parametrize("path_klass", [lambda p: p, Path])
def test_spss_labelled_num(path_klass, datapath):
# test file from the Haven project (https://haven.tidyverse.org/)
Expand All @@ -27,7 +27,7 @@ def test_spss_labelled_num(path_klass, datapath):
tm.assert_frame_equal(df, expected)


@td.skip_copy_on_write_not_yet_implemented
@pytest.mark.filterwarnings("ignore::pandas.errors.ChainedAssignmentError")
def test_spss_labelled_num_na(datapath):
# test file from the Haven project (https://haven.tidyverse.org/)
fname = datapath("io", "data", "spss", "labelled-num-na.sav")
Expand All @@ -42,7 +42,7 @@ def test_spss_labelled_num_na(datapath):
tm.assert_frame_equal(df, expected)


@td.skip_copy_on_write_not_yet_implemented
@pytest.mark.filterwarnings("ignore::pandas.errors.ChainedAssignmentError")
def test_spss_labelled_str(datapath):
# test file from the Haven project (https://haven.tidyverse.org/)
fname = datapath("io", "data", "spss", "labelled-str.sav")
Expand All @@ -57,7 +57,7 @@ def test_spss_labelled_str(datapath):
tm.assert_frame_equal(df, expected)


@td.skip_copy_on_write_not_yet_implemented
@pytest.mark.filterwarnings("ignore::pandas.errors.ChainedAssignmentError")
def test_spss_umlauts(datapath):
# test file from the Haven project (https://haven.tidyverse.org/)
fname = datapath("io", "data", "spss", "umlauts.sav")
Expand Down