Skip to content

Commit 838b04f

Browse files
REGR: fix eval with inplace=True to correctly update column values inplace (#47550)
* fix pre-commit issues * fix linting errors * add inplace argument to isetitem and use in eval * changes due to PR discussions * fix issues * update eval * update whatsnew * add PR suggestions * update imports in eval.py * check inplace and use NDFrame + small update to test * update test to use using_copy_on_write * skip test for array manager Co-authored-by: Joris Van den Bossche <[email protected]>
1 parent 065b51c commit 838b04f

File tree

3 files changed

+26
-1
lines changed

3 files changed

+26
-1
lines changed

doc/source/whatsnew/v1.4.4.rst

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Fixed regressions
1919
- Fixed regression in :meth:`DataFrame.loc` not updating the cache correctly after values were set (:issue:`47867`)
2020
- Fixed regression in :meth:`DataFrame.loc` not aligning index in some cases when setting a :class:`DataFrame` (:issue:`47578`)
2121
- Fixed regression in setting ``None`` or non-string value into a ``string``-dtype Series using a mask (:issue:`47628`)
22+
- Fixed regression in :meth:`DataFrame.eval` creating a copy when updating inplace (:issue:`47449`)
2223
-
2324

2425
.. ---------------------------------------------------------------------------

pandas/core/computation/eval.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
)
2020
from pandas.core.computation.parsing import tokenize_string
2121
from pandas.core.computation.scope import ensure_scope
22+
from pandas.core.generic import NDFrame
2223

2324
from pandas.io.formats.printing import pprint_thing
2425

@@ -387,7 +388,10 @@ def eval(
387388
try:
388389
with warnings.catch_warnings(record=True):
389390
# TODO: Filter the warnings we actually care about here.
390-
target[assigner] = ret
391+
if inplace and isinstance(target, NDFrame):
392+
target.loc[:, assigner] = ret
393+
else:
394+
target[assigner] = ret
391395
except (TypeError, IndexError) as err:
392396
raise ValueError("Cannot assign expression output to target") from err
393397

pandas/tests/computation/test_eval.py

+20
Original file line numberDiff line numberDiff line change
@@ -1912,6 +1912,26 @@ def test_eval_no_support_column_name(request, column):
19121912
tm.assert_frame_equal(result, expected)
19131913

19141914

1915+
@td.skip_array_manager_not_yet_implemented
1916+
def test_set_inplace(using_copy_on_write):
1917+
# https://github.com/pandas-dev/pandas/issues/47449
1918+
# Ensure we don't only update the DataFrame inplace, but also the actual
1919+
# column values, such that references to this column also get updated
1920+
df = DataFrame({"A": [1, 2, 3], "B": [4, 5, 6], "C": [7, 8, 9]})
1921+
result_view = df[:]
1922+
ser = df["A"]
1923+
df.eval("A = B + C", inplace=True)
1924+
expected = DataFrame({"A": [11, 13, 15], "B": [4, 5, 6], "C": [7, 8, 9]})
1925+
tm.assert_frame_equal(df, expected)
1926+
if not using_copy_on_write:
1927+
tm.assert_series_equal(ser, expected["A"])
1928+
tm.assert_series_equal(result_view["A"], expected["A"])
1929+
else:
1930+
expected = Series([1, 2, 3], name="A")
1931+
tm.assert_series_equal(ser, expected)
1932+
tm.assert_series_equal(result_view["A"], expected)
1933+
1934+
19151935
class TestValidate:
19161936
@pytest.mark.parametrize("value", [1, "True", [1, 2, 3], 5.0])
19171937
def test_validate_bool_args(self, value):

0 commit comments

Comments
 (0)