Description
While working on #56402 (ensuring full test coverage for the warning we raise when you do chained inplace methods), we ran into another corner case where the refcount differs, and mixes up the refcount-based inference about whether we are being called in a "chained" context and thus have to raise the ChainedAssignment warning.
(a previous case we discovered was when the setitem call is coming from cython code: #51315)
Specifically, when passing *args
or **kwargs
to the inplace method call, it takes a different execution path in the Python interpreter compared to calling it with manually specified arguments. And starting from Python 3.11, this other execution path gives one reference less.
Example (with CoW, the df
will never be updated with such chained method call):
>>> pd.options.mode.copy_on_write = True
>>> df = DataFrame({"a": [1, 2, np.nan], "b": 1})
>>> df["a"].fillna(0, inplace=True)
ChainedAssignmentError: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.
When using the Copy-on-Write mode, such inplace method never works to update the original DataFrame or Series, because the intermediate object on which we are setting values always behaves as a copy.
For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' instead, to perform the operation inplace on the original object.
That warning works for all tested Python versions. However, when passing the args
or kwargs
, the warning doesn't work on Python >= 3.11:
>>> pd.options.mode.copy_on_write = True
>>> df = DataFrame({"a": [1, 2, np.nan], "b": 1})
>>> args = (0, )
>>> df["a"].fillna(*args, inplace=True)
# no warning
For now we decided to punt on this specific corner case, but creating this issue to we keep track of what we learned and have something to reference to when this might come up later.