From 9c46f57cb37bbad8d7624deeb3c94209aa856098 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 22 Sep 2020 14:36:17 -0500 Subject: [PATCH 1/2] Call finalize in Series.__array_ufunc__ xref 28283 --- doc/source/whatsnew/v1.2.0.rst | 1 + pandas/core/series.py | 6 +++++- pandas/tests/generic/test_finalize.py | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst index 6a5b4b3b9ff16..3721afc9d4446 100644 --- a/doc/source/whatsnew/v1.2.0.rst +++ b/doc/source/whatsnew/v1.2.0.rst @@ -376,6 +376,7 @@ Other - Bug in :meth:`DataFrame.replace` and :meth:`Series.replace` with numeric values and string ``to_replace`` (:issue:`34789`) - Bug in :meth:`Series.transform` would give incorrect results or raise when the argument ``func`` was dictionary (:issue:`35811`) - Bug in :meth:`Index.union` behaving differently depending on whether operand is a :class:`Index` or other list-like (:issue:`36384`) +- Fixed metadata propagation in :meth:`Series.abs` and ufuncs called on Series (:issue:`28283`) .. --------------------------------------------------------------------------- diff --git a/pandas/core/series.py b/pandas/core/series.py index 0984e86a23592..a93852362cf58 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -739,7 +739,11 @@ def construct_return(result): # GH#27198 raise NotImplementedError return result - return self._constructor(result, index=index, name=name, copy=False) + # TODO: When we support multiple values in __finalize__, this should + # pass alignable instead of self. + return self._constructor( + result, index=index, name=name, copy=False + ).__finalize__(self) if type(result) is tuple: # multiple return values diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index 8898619e374ab..16dcd664b3635 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -330,7 +330,8 @@ (pd.DataFrame, frame_data, operator.inv), (pd.Series, [1], operator.inv), (pd.DataFrame, frame_data, abs), - pytest.param((pd.Series, [1], abs), marks=not_implemented_mark), + (pd.Series, [1], abs), + (pd.Series, [1], np.arccos), pytest.param((pd.DataFrame, frame_data, round), marks=not_implemented_mark), (pd.Series, [1], round), (pd.DataFrame, frame_data, operator.methodcaller("take", [0, 0])), From 3a38d36c09ab4a9f92f9308a6fbed765b5c3b7e8 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Wed, 30 Sep 2020 13:54:50 -0500 Subject: [PATCH 2/2] fixup --- pandas/core/series.py | 6 ++++-- pandas/tests/generic/test_finalize.py | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 02639b0009b06..ea04125e28a8c 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -746,8 +746,10 @@ def construct_return(result): # GH#27198 raise NotImplementedError return result - # TODO: When we support multiple values in __finalize__, this should - # pass alignable instead of self. + # TODO: When we support multiple values in __finalize__, this + # should pass alignable as `other` instead of self. + # Then `np.add(a, b)` would consider attrs from both a and b + # when a and b are NDFrames. return self._constructor( result, index=index, name=name, copy=False ).__finalize__(self) diff --git a/pandas/tests/generic/test_finalize.py b/pandas/tests/generic/test_finalize.py index 4d1b0c0792e89..65b077d088847 100644 --- a/pandas/tests/generic/test_finalize.py +++ b/pandas/tests/generic/test_finalize.py @@ -3,6 +3,7 @@ """ import operator import re +from typing import Any, List, Tuple import numpy as np import pytest @@ -29,7 +30,7 @@ # - Tuple: Constructor args # - Callable: pass the constructed value with attrs set to this. -_all_methods = [ +_all_methods: List[Tuple[Any, Any, Any]] = [ ( pd.Series, (np.array([0], dtype="float64")),