From e7586727d90ce703c2c3aa141245680575521e34 Mon Sep 17 00:00:00 2001 From: seljaks <33955366+seljaks@users.noreply.github.com> Date: Tue, 20 Sep 2022 01:08:21 +0200 Subject: [PATCH] ENH: added finalize to binary operators on DataFrame, GH28283 (#48551) * ENH/TST/DOC: Added finalize to DataFrame binary ops, GH28283 * ENH/TST/DOC: Added finalize to DataFrame binary ops, GH28283 * TST: fix not implemented tests * DOC: moved mention to whatsnew 1.6 --- doc/source/whatsnew/v1.6.0.rst | 1 + pandas/core/frame.py | 2 +- pandas/tests/generic/test_duplicate_labels.py | 4 +--- pandas/tests/generic/test_finalize.py | 20 +++++++------------ 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/doc/source/whatsnew/v1.6.0.rst b/doc/source/whatsnew/v1.6.0.rst index 70a06c25686d92..75c2933ed27dee 100644 --- a/doc/source/whatsnew/v1.6.0.rst +++ b/doc/source/whatsnew/v1.6.0.rst @@ -32,6 +32,7 @@ Other enhancements - :meth:`Series.add_suffix`, :meth:`DataFrame.add_suffix`, :meth:`Series.add_prefix` and :meth:`DataFrame.add_prefix` support an ``axis`` argument. If ``axis`` is set, the default behaviour of which axis to consider can be overwritten (:issue:`47819`) - :func:`assert_frame_equal` now shows the first element where the DataFrames differ, analogously to ``pytest``'s output (:issue:`47910`) - Added ``index`` parameter to :meth:`DataFrame.to_dict` (:issue:`46398`) +- Added metadata propagation for binary operators on :class:`DataFrame` (:issue:`28283`) - .. --------------------------------------------------------------------------- diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 8b3ca54e38786a..79e8b2ed806c87 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -7711,7 +7711,7 @@ def _construct_result(self, result) -> DataFrame: ------- DataFrame """ - out = self._constructor(result, copy=False) + out = self._constructor(result, copy=False).__finalize__(self) # Pin columns instead of passing to constructor for compat with # non-unique columns case out.columns = self.columns diff --git a/pandas/tests/generic/test_duplicate_labels.py b/pandas/tests/generic/test_duplicate_labels.py index 0546534d913995..c9036958cbd74b 100644 --- a/pandas/tests/generic/test_duplicate_labels.py +++ b/pandas/tests/generic/test_duplicate_labels.py @@ -68,9 +68,7 @@ def test_to_frame(self): assert ser.to_frame().flags.allows_duplicate_labels is False @pytest.mark.parametrize("func", ["add", "sub"]) - @pytest.mark.parametrize( - "frame", [False, pytest.param(True, marks=not_implemented)] - ) + @pytest.mark.parametrize("frame", [False, True]) @pytest.mark.parametrize("other", [1, pd.Series([1, 2], name="A")]) def test_binops(self, func, other, frame): df = pd.Series([1, 2], name="A", index=["a", "b"]).set_flags( diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index dddab05af7341e..af1a76a6263c71 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -109,13 +109,10 @@ (pd.DataFrame, frame_data, operator.methodcaller("nlargest", 1, "A")), (pd.DataFrame, frame_data, operator.methodcaller("nsmallest", 1, "A")), (pd.DataFrame, frame_mi_data, operator.methodcaller("swaplevel")), - pytest.param( - ( - pd.DataFrame, - frame_data, - operator.methodcaller("add", pd.DataFrame(*frame_data)), - ), - marks=not_implemented_mark, + ( + pd.DataFrame, + frame_data, + operator.methodcaller("add", pd.DataFrame(*frame_data)), ), # TODO: div, mul, etc. pytest.param( @@ -539,21 +536,18 @@ def test_finalize_called_eval_numexpr(): (pd.DataFrame({"A": [1]}), pd.Series([1])), ], ) -def test_binops(request, args, annotate, all_arithmetic_functions): - # This generates 326 tests... Is that needed? +def test_binops(request, args, annotate, all_binary_operators): + # This generates 624 tests... Is that needed? left, right = args if annotate == "both" and isinstance(left, int) or isinstance(right, int): return - if isinstance(left, pd.DataFrame) or isinstance(right, pd.DataFrame): - request.node.add_marker(pytest.mark.xfail(reason="not implemented")) - if annotate in {"left", "both"} and not isinstance(left, int): left.attrs = {"a": 1} if annotate in {"left", "both"} and not isinstance(right, int): right.attrs = {"a": 1} - result = all_arithmetic_functions(left, right) + result = all_binary_operators(left, right) assert result.attrs == {"a": 1}