diff --git a/doc/source/whatsnew/v1.6.0.rst b/doc/source/whatsnew/v1.6.0.rst index 405b8cc0a5ded..ea3ba77dcca0f 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 22ccd1d763769..447feb6986588 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 0546534d91399..c9036958cbd74 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 dddab05af7341..af1a76a6263c7 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}