From 2ae76568f9a65548e4ff50fb13468502604f7e2c Mon Sep 17 00:00:00 2001 From: Neil Gollapudi Date: Sun, 5 Apr 2020 01:04:45 -0400 Subject: [PATCH 1/6] BUG: DataFrame._item_cache not cleared on on .copy() --- pandas/core/generic.py | 1 + pandas/tests/generic/test_generic.py | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index c202bf846047f..be939519014e2 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -5680,6 +5680,7 @@ def copy(self: FrameOrSeries, deep: bool_t = True) -> FrameOrSeries: dtype: object """ data = self._data.copy(deep=deep) + self._clear_item_cache() return self._constructor(data).__finalize__(self) def __copy__(self: FrameOrSeries, deep: bool_t = True) -> FrameOrSeries: diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index 1a4a0b1678aa4..21ea2e358916f 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -910,3 +910,21 @@ def test_axis_classmethods(self, box): assert obj._get_axis_number(v) == box._get_axis_number(v) assert obj._get_axis_name(v) == box._get_axis_name(v) assert obj._get_block_manager_axis(v) == box._get_block_manager_axis(v) + + def test_cache_on_copy(self): + df = DataFrame({"a": [1]}) + + df["x"] = [0] + df["a"] + + df.copy() + + df["a"].values[0] = -1 + + assert df["a"].values[0] == -1 + assert df.equals(DataFrame({"a": [-1], "x": [0]})) + + df["y"] = 0 + + assert df["a"].values[0] == -1 + assert df.equals(DataFrame({"a": [-1], "x": [0], "y": [0]})) From de867c02fc7d94f6f7638257004390b45f696991 Mon Sep 17 00:00:00 2001 From: Neil Gollapudi Date: Sun, 5 Apr 2020 01:22:12 -0400 Subject: [PATCH 2/6] BUG: DataFrame._item_cache not cleared on on .copy() --- doc/source/whatsnew/v1.1.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 8bff34dbdadad..0482b0b74cee4 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -363,6 +363,7 @@ Indexing - Bug in :class:`Index` constructor where an unhelpful error message was raised for ``numpy`` scalars (:issue:`33017`) - Bug in :meth:`DataFrame.lookup` incorrectly raising an ``AttributeError`` when ``frame.index`` or ``frame.columns`` is not unique; this will now raise a ``ValueError`` with a helpful error message (:issue:`33041`) - Bug in :meth:`DataFrame.iloc.__setitem__` creating a new array instead of overwriting ``Categorical`` values in-place (:issue:`32831`) +- Bug in :meth:`DataFrame.copy` _item_cache invalidated after copy performs consolidation (:issue: `31784`) Missing ^^^^^^^ From d2b9181ce42b0a71176efbfabf97da173ec935ee Mon Sep 17 00:00:00 2001 From: Neil Gollapudi Date: Sun, 5 Apr 2020 01:59:54 -0400 Subject: [PATCH 3/6] #33299 updated tests --- pandas/tests/generic/test_generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index 21ea2e358916f..f34e232744311 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -922,9 +922,9 @@ def test_cache_on_copy(self): df["a"].values[0] = -1 assert df["a"].values[0] == -1 - assert df.equals(DataFrame({"a": [-1], "x": [0]})) + tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0]})) df["y"] = 0 assert df["a"].values[0] == -1 - assert df.equals(DataFrame({"a": [-1], "x": [0], "y": [0]})) + tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0], "y": [0]})) From 441a3e00fc500497565cd7592380b9a234079308 Mon Sep 17 00:00:00 2001 From: neilkg <33635204+neilkg@users.noreply.github.com> Date: Sun, 5 Apr 2020 10:53:51 -0400 Subject: [PATCH 4/6] Update doc/source/whatsnew/v1.1.0.rst Co-Authored-By: MomIsBestFriend <50263213+MomIsBestFriend@users.noreply.github.com> --- doc/source/whatsnew/v1.1.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 0482b0b74cee4..3f27ef0677828 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -363,7 +363,7 @@ Indexing - Bug in :class:`Index` constructor where an unhelpful error message was raised for ``numpy`` scalars (:issue:`33017`) - Bug in :meth:`DataFrame.lookup` incorrectly raising an ``AttributeError`` when ``frame.index`` or ``frame.columns`` is not unique; this will now raise a ``ValueError`` with a helpful error message (:issue:`33041`) - Bug in :meth:`DataFrame.iloc.__setitem__` creating a new array instead of overwriting ``Categorical`` values in-place (:issue:`32831`) -- Bug in :meth:`DataFrame.copy` _item_cache invalidated after copy performs consolidation (:issue: `31784`) +- Bug in :meth:`DataFrame.copy` _item_cache invalidated after copy performs consolidation (:issue:`31784`) Missing ^^^^^^^ From dfc63dccc392042602f898c7050c83ab9cf79f97 Mon Sep 17 00:00:00 2001 From: Neil Gollapudi Date: Sun, 5 Apr 2020 12:07:12 -0400 Subject: [PATCH 5/6] BUG: DataFrame._item_cache not cleared on on .copy() (#33299) --- pandas/tests/frame/methods/test_copy.py | 21 +++++++++++++++++++++ pandas/tests/generic/test_generic.py | 18 ------------------ 2 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 pandas/tests/frame/methods/test_copy.py diff --git a/pandas/tests/frame/methods/test_copy.py b/pandas/tests/frame/methods/test_copy.py new file mode 100644 index 0000000000000..d795781e70326 --- /dev/null +++ b/pandas/tests/frame/methods/test_copy.py @@ -0,0 +1,21 @@ +from pandas import DataFrame +import pandas._testing as tm + + +class TestCopy: + def test_cache_on_copy(self): + df = DataFrame({"a": [1]}) + + df["x"] = [0] + df["a"] + + df.copy() + + df["a"].values[0] = -1 + + tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0]})) + + df["y"] = [0] + + assert df["a"].values[0] == -1 + tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0], "y": [0]})) diff --git a/pandas/tests/generic/test_generic.py b/pandas/tests/generic/test_generic.py index f34e232744311..1a4a0b1678aa4 100644 --- a/pandas/tests/generic/test_generic.py +++ b/pandas/tests/generic/test_generic.py @@ -910,21 +910,3 @@ def test_axis_classmethods(self, box): assert obj._get_axis_number(v) == box._get_axis_number(v) assert obj._get_axis_name(v) == box._get_axis_name(v) assert obj._get_block_manager_axis(v) == box._get_block_manager_axis(v) - - def test_cache_on_copy(self): - df = DataFrame({"a": [1]}) - - df["x"] = [0] - df["a"] - - df.copy() - - df["a"].values[0] = -1 - - assert df["a"].values[0] == -1 - tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0]})) - - df["y"] = 0 - - assert df["a"].values[0] == -1 - tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0], "y": [0]})) From f1bafef34fdd1a73a4e095d00de93d64871169e3 Mon Sep 17 00:00:00 2001 From: Neil Gollapudi Date: Sun, 5 Apr 2020 16:02:40 -0400 Subject: [PATCH 6/6] BUG: DataFrame._item_cache not cleared on on .copy() (#33299) --- doc/source/whatsnew/v1.1.0.rst | 2 +- pandas/tests/frame/methods/test_copy.py | 21 --------------------- pandas/tests/frame/test_api.py | 18 ++++++++++++++++++ 3 files changed, 19 insertions(+), 22 deletions(-) delete mode 100644 pandas/tests/frame/methods/test_copy.py diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 3f27ef0677828..d1020ea7091ae 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -363,7 +363,7 @@ Indexing - Bug in :class:`Index` constructor where an unhelpful error message was raised for ``numpy`` scalars (:issue:`33017`) - Bug in :meth:`DataFrame.lookup` incorrectly raising an ``AttributeError`` when ``frame.index`` or ``frame.columns`` is not unique; this will now raise a ``ValueError`` with a helpful error message (:issue:`33041`) - Bug in :meth:`DataFrame.iloc.__setitem__` creating a new array instead of overwriting ``Categorical`` values in-place (:issue:`32831`) -- Bug in :meth:`DataFrame.copy` _item_cache invalidated after copy performs consolidation (:issue:`31784`) +- Bug in :meth:`DataFrame.copy` _item_cache not invalidated after copy causes post-copy value updates to not be reflected (:issue:`31784`) Missing ^^^^^^^ diff --git a/pandas/tests/frame/methods/test_copy.py b/pandas/tests/frame/methods/test_copy.py deleted file mode 100644 index d795781e70326..0000000000000 --- a/pandas/tests/frame/methods/test_copy.py +++ /dev/null @@ -1,21 +0,0 @@ -from pandas import DataFrame -import pandas._testing as tm - - -class TestCopy: - def test_cache_on_copy(self): - df = DataFrame({"a": [1]}) - - df["x"] = [0] - df["a"] - - df.copy() - - df["a"].values[0] = -1 - - tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0]})) - - df["y"] = [0] - - assert df["a"].values[0] == -1 - tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0], "y": [0]})) diff --git a/pandas/tests/frame/test_api.py b/pandas/tests/frame/test_api.py index 91627b46c2fee..4149485be181d 100644 --- a/pandas/tests/frame/test_api.py +++ b/pandas/tests/frame/test_api.py @@ -540,3 +540,21 @@ def test_attrs(self): result = df.rename(columns=str) assert result.attrs == {"version": 1} + + def test_cache_on_copy(self): + # GH 31784 _item_cache not cleared on copy causes incorrect reads after updates + df = DataFrame({"a": [1]}) + + df["x"] = [0] + df["a"] + + df.copy() + + df["a"].values[0] = -1 + + tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0]})) + + df["y"] = [0] + + assert df["a"].values[0] == -1 + tm.assert_frame_equal(df, DataFrame({"a": [-1], "x": [0], "y": [0]}))