diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 09cb024cbd95c..b01df3c693b97 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -591,6 +591,7 @@ Other - Bug in :meth:`DataFrame.replace` and :meth:`Series.replace` incorrectly casting from ``PeriodDtype`` to object dtype (:issue:`34871`) - Fixed bug in metadata propagation incorrectly copying DataFrame columns as metadata when the column name overlaps with the metadata name (:issue:`37037`) - Fixed metadata propagation in the :class:`Series.dt`, :class:`Series.str` accessors, :class:`DataFrame.duplicated`, :class:`DataFrame.stack`, :class:`DataFrame.unstack`, :class:`DataFrame.pivot`, :class:`DataFrame.append`, :class:`DataFrame.diff`, :class:`DataFrame.applymap` and :class:`DataFrame.update` methods (:issue:`28283`) (:issue:`37381`) +- Fixed metadata propagation when selecting columns from a DataFrame with ``DataFrame.__getitem__`` (:issue:`28283`) - Bug in :meth:`Index.union` behaving differently depending on whether operand is a :class:`Index` or other list-like (:issue:`36384`) - Passing an array with 2 or more dimensions to the :class:`Series` constructor now raises the more specific ``ValueError``, from a bare ``Exception`` previously (:issue:`35744`) - Bug in ``accessor.DirNamesMixin``, where ``dir(obj)`` wouldn't show attributes defined on the instance (:issue:`37173`). diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 49e992b14293e..86df327a62b73 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3777,7 +3777,7 @@ def _get_item_cache(self, item): loc = self.columns.get_loc(item) values = self._mgr.iget(loc) - res = self._box_col_values(values, loc) + res = self._box_col_values(values, loc).__finalize__(self) cache[item] = res res._set_as_cached(item, self) diff --git a/pandas/tests/generic/test_duplicate_labels.py b/pandas/tests/generic/test_duplicate_labels.py index 42745d2a69375..3f7bebd86e983 100644 --- a/pandas/tests/generic/test_duplicate_labels.py +++ b/pandas/tests/generic/test_duplicate_labels.py @@ -312,9 +312,7 @@ def test_series_raises(self, func): pytest.param( operator.itemgetter(("a", ["A", "A"])), "loc", marks=not_implemented ), - pytest.param( - operator.itemgetter((["a", "a"], "A")), "loc", marks=not_implemented - ), + (operator.itemgetter((["a", "a"], "A")), "loc"), # iloc (operator.itemgetter([0, 0]), "iloc"), pytest.param( diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index e38936baca758..ecd70bb415334 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -85,18 +85,12 @@ marks=pytest.mark.xfail(reason="Implement binary finalize"), ), (pd.DataFrame, frame_data, operator.methodcaller("transpose")), - pytest.param( - (pd.DataFrame, frame_data, operator.methodcaller("__getitem__", "A")), - marks=not_implemented_mark, - ), + (pd.DataFrame, frame_data, operator.methodcaller("__getitem__", "A")), (pd.DataFrame, frame_data, operator.methodcaller("__getitem__", ["A"])), (pd.DataFrame, frame_data, operator.methodcaller("__getitem__", np.array([True]))), (pd.DataFrame, ({("A", "a"): [1]},), operator.methodcaller("__getitem__", ["A"])), (pd.DataFrame, frame_data, operator.methodcaller("query", "A == 1")), - pytest.param( - (pd.DataFrame, frame_data, operator.methodcaller("eval", "A + 1")), - marks=not_implemented_mark, - ), + (pd.DataFrame, frame_data, operator.methodcaller("eval", "A + 1", engine="python")), (pd.DataFrame, frame_data, operator.methodcaller("select_dtypes", include="int")), (pd.DataFrame, frame_data, operator.methodcaller("assign", b=1)), (pd.DataFrame, frame_data, operator.methodcaller("set_axis", ["A"])), @@ -289,10 +283,7 @@ ), (pd.DataFrame, frame_data, operator.methodcaller("swapaxes", 0, 1)), (pd.DataFrame, frame_mi_data, operator.methodcaller("droplevel", "A")), - pytest.param( - (pd.DataFrame, frame_data, operator.methodcaller("pop", "A")), - marks=not_implemented_mark, - ), + (pd.DataFrame, frame_data, operator.methodcaller("pop", "A")), pytest.param( (pd.DataFrame, frame_data, operator.methodcaller("squeeze")), marks=not_implemented_mark, @@ -317,10 +308,7 @@ (pd.DataFrame, frame_data, operator.methodcaller("take", [0, 0])), (pd.DataFrame, frame_mi_data, operator.methodcaller("xs", "a")), (pd.Series, (1, mi), operator.methodcaller("xs", "a")), - pytest.param( - (pd.DataFrame, frame_data, operator.methodcaller("get", "A")), - marks=not_implemented_mark, - ), + (pd.DataFrame, frame_data, operator.methodcaller("get", "A")), ( pd.DataFrame, frame_data, @@ -532,6 +520,15 @@ def test_finalize_called(ndframe_method): assert result.attrs == {"a": 1} +@not_implemented_mark +def test_finalize_called_eval_numexpr(): + pytest.importorskip("numexpr") + df = pd.DataFrame({"A": [1, 2]}) + df.attrs["A"] = 1 + result = df.eval("A + 1", engine="numexpr") + assert result.attrs == {"A": 1} + + # ---------------------------------------------------------------------------- # Binary operations