diff --git a/pandas/core/base.py b/pandas/core/base.py index a28a2c9594341..5945d8a4b432d 100644 --- a/pandas/core/base.py +++ b/pandas/core/base.py @@ -1521,4 +1521,4 @@ def duplicated(self, keep="first"): else: return self._constructor( duplicated(self, keep=keep), index=self.index - ).__finalize__(self) + ).__finalize__(self, method="duplicated") diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 67523facb7b7d..aedbba755227d 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2515,7 +2515,7 @@ def transpose(self, *args, copy: bool = False) -> "DataFrame": new_values, index=self.columns, columns=self.index ) - return result.__finalize__(self) + return result.__finalize__(self, method="transpose") @property def T(self) -> "DataFrame": @@ -4470,7 +4470,7 @@ def _maybe_casted_values(index, labels=None): @Appender(_shared_docs["isna"] % _shared_doc_kwargs) def isna(self) -> "DataFrame": result = self._constructor(self._data.isna(func=isna)) - return result.__finalize__(self) + return result.__finalize__(self, method="isna") @Appender(_shared_docs["isna"] % _shared_doc_kwargs) def isnull(self) -> "DataFrame": @@ -4798,7 +4798,7 @@ def sort_values( if inplace: return self._update_inplace(result) else: - return result.__finalize__(self) + return result.__finalize__(self, method="sort_values") def sort_index( self, @@ -4934,7 +4934,7 @@ def sort_index( if inplace: return self._update_inplace(result) else: - return result.__finalize__(self) + return result.__finalize__(self, method="sort_index") def value_counts( self, diff --git a/pandas/core/generic.py b/pandas/core/generic.py index fac4ca6768ece..16725e72d5df2 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -590,7 +590,9 @@ def swapaxes(self: FrameOrSeries, axis1, axis2, copy=True) -> FrameOrSeries: if copy: new_values = new_values.copy() - return self._constructor(new_values, *new_axes).__finalize__(self) + return self._constructor(new_values, *new_axes).__finalize__( + self, method="swapaxes" + ) def droplevel(self: FrameOrSeries, level, axis=0) -> FrameOrSeries: """ @@ -993,7 +995,7 @@ def rename( self._update_inplace(result) return None else: - return result.__finalize__(self) + return result.__finalize__(self, method="rename") @rewrite_axis_style_signature("mapper", [("copy", True), ("inplace", False)]) def rename_axis(self, mapper=lib.no_default, **kwargs): @@ -1357,7 +1359,7 @@ def __invert__(self): return self new_data = self._mgr.apply(operator.invert) - result = self._constructor(new_data).__finalize__(self) + result = self._constructor(new_data).__finalize__(self, method="__invert__") return result def __nonzero__(self): @@ -1802,7 +1804,9 @@ def __array_wrap__(self, result, context=None): # ptp also requires the item_from_zerodim return result d = self._construct_axes_dict(self._AXIS_ORDERS, copy=False) - return self._constructor(result, **d).__finalize__(self) + return self._constructor(result, **d).__finalize__( + self, method="__array_wrap__" + ) # ideally we would define this to avoid the getattr checks, but # is slower @@ -3361,7 +3365,7 @@ class max_speed new_data = self._mgr.take( indices, axis=self._get_block_manager_axis(axis), verify=True ) - return self._constructor(new_data).__finalize__(self) + return self._constructor(new_data).__finalize__(self, method="take") def _take_with_is_copy(self: FrameOrSeries, indices, axis=0) -> FrameOrSeries: """ @@ -4430,7 +4434,7 @@ def reindex(self: FrameOrSeries, *args, **kwargs) -> FrameOrSeries: # perform the reindex on the axes return self._reindex_axes( axes, level, limit, tolerance, method, fill_value, copy - ).__finalize__(self) + ).__finalize__(self, method="reindex") def _reindex_axes( self: FrameOrSeries, axes, level, limit, tolerance, method, fill_value, copy @@ -5129,7 +5133,7 @@ def pipe(self, func, *args, **kwargs): # Attribute access def __finalize__( - self: FrameOrSeries, other, method=None, **kwargs + self: FrameOrSeries, other, method: Optional[str] = None, **kwargs ) -> FrameOrSeries: """ Propagate metadata from other to self. @@ -5138,9 +5142,14 @@ def __finalize__( ---------- other : the object from which to get the attributes that we are going to propagate - method : optional, a passed method name ; possibly to take different - types of propagation actions based on this + method : str, optional + A passed method name providing context on where ``__finalize__`` + was called. + + .. warning: + The value passed as `method` are not currently considered + stable across pandas releases. """ if isinstance(other, NDFrame): for name in other.attrs: @@ -5293,10 +5302,10 @@ def _check_inplace_setting(self, value) -> bool_t: return True def _get_numeric_data(self): - return self._constructor(self._mgr.get_numeric_data()).__finalize__(self) + return self._constructor(self._mgr.get_numeric_data()).__finalize__(self,) def _get_bool_data(self): - return self._constructor(self._mgr.get_bool_data()).__finalize__(self) + return self._constructor(self._mgr.get_bool_data()).__finalize__(self,) # ---------------------------------------------------------------------- # Internal Interface Methods @@ -5562,8 +5571,8 @@ def astype( else: # else, only a single dtype is given - new_data = self._mgr.astype(dtype=dtype, copy=copy, errors=errors) - return self._constructor(new_data).__finalize__(self) + new_data = self._mgr.astype(dtype=dtype, copy=copy, errors=errors,) + return self._constructor(new_data).__finalize__(self, method="astype") # GH 19920: retain column metadata after concat result = pd.concat(results, axis=1, copy=False) @@ -5677,7 +5686,7 @@ def copy(self: FrameOrSeries, deep: bool_t = True) -> FrameOrSeries: """ data = self._mgr.copy(deep=deep) self._clear_item_cache() - return self._constructor(data).__finalize__(self) + return self._constructor(data).__finalize__(self, method="copy") def __copy__(self: FrameOrSeries, deep: bool_t = True) -> FrameOrSeries: return self.copy(deep=deep) @@ -5783,7 +5792,7 @@ def infer_objects(self: FrameOrSeries) -> FrameOrSeries: self._mgr.convert( datetime=True, numeric=False, timedelta=True, coerce=False, copy=True ) - ).__finalize__(self) + ).__finalize__(self, method="infer_objects") def convert_dtypes( self: FrameOrSeries, @@ -6110,7 +6119,7 @@ def fillna( if inplace: return self._update_inplace(result) else: - return result.__finalize__(self) + return result.__finalize__(self, method="fillna") def ffill( self: FrameOrSeries, @@ -6626,7 +6635,7 @@ def replace( if inplace: return self._update_inplace(result) else: - return result.__finalize__(self) + return result.__finalize__(self, method="replace") _shared_docs[ "interpolate" @@ -6892,7 +6901,7 @@ def interpolate( if inplace: return self._update_inplace(result) else: - return result.__finalize__(self) + return result.__finalize__(self, method="interpolate") # ---------------------------------------------------------------------- # Timeseries methods Methods @@ -7130,11 +7139,11 @@ def asof(self, where, subset=None): @Appender(_shared_docs["isna"] % _shared_doc_kwargs) def isna(self: FrameOrSeries) -> FrameOrSeries: - return isna(self).__finalize__(self) + return isna(self).__finalize__(self, method="isna") @Appender(_shared_docs["isna"] % _shared_doc_kwargs) def isnull(self: FrameOrSeries) -> FrameOrSeries: - return isna(self).__finalize__(self) + return isna(self).__finalize__(self, method="isnull") _shared_docs[ "notna" @@ -7200,11 +7209,11 @@ def isnull(self: FrameOrSeries) -> FrameOrSeries: @Appender(_shared_docs["notna"] % _shared_doc_kwargs) def notna(self: FrameOrSeries) -> FrameOrSeries: - return notna(self).__finalize__(self) + return notna(self).__finalize__(self, method="notna") @Appender(_shared_docs["notna"] % _shared_doc_kwargs) def notnull(self: FrameOrSeries) -> FrameOrSeries: - return notna(self).__finalize__(self) + return notna(self).__finalize__(self, method="notnull") def _clip_with_scalar(self, lower, upper, inplace: bool_t = False): if (lower is not None and np.any(isna(lower))) or ( @@ -8228,7 +8237,7 @@ def ranker(data): pct=pct, ) ranks = self._constructor(ranks, **data._construct_axes_dict()) - return ranks.__finalize__(self) + return ranks.__finalize__(self, method="rank") # if numeric_only is None, and we can't get anything, we try with # numeric_only=True @@ -8435,7 +8444,10 @@ def _align_frame( left.index = join_index right.index = join_index - return left.__finalize__(self), right.__finalize__(other) + return ( + left.__finalize__(self), + right.__finalize__(other), + ) def _align_series( self, @@ -8519,7 +8531,10 @@ def _align_series( left.index = join_index right.index = join_index - return left.__finalize__(self), right.__finalize__(other) + return ( + left.__finalize__(self), + right.__finalize__(other), + ) def _where( self, @@ -8932,7 +8947,7 @@ def shift( else: return self.tshift(periods, freq) - return self._constructor(new_data).__finalize__(self) + return self._constructor(new_data).__finalize__(self, method="shift") def slice_shift(self: FrameOrSeries, periods: int = 1, axis=0) -> FrameOrSeries: """ @@ -8969,7 +8984,7 @@ def slice_shift(self: FrameOrSeries, periods: int = 1, axis=0) -> FrameOrSeries: shifted_axis = self._get_axis(axis)[islicer] new_obj.set_axis(shifted_axis, axis=axis, inplace=True) - return new_obj.__finalize__(self) + return new_obj.__finalize__(self, method="slice_shift") def tshift( self: FrameOrSeries, periods: int = 1, freq=None, axis: Axis = 0 @@ -9029,7 +9044,7 @@ def tshift( result = self.copy() result.set_axis(new_ax, axis, inplace=True) - return result.__finalize__(self) + return result.__finalize__(self, method="tshift") def truncate( self: FrameOrSeries, before=None, after=None, axis=None, copy: bool_t = True @@ -9240,7 +9255,7 @@ def _tz_convert(ax, tz): result = self.copy(deep=copy) result = result.set_axis(ax, axis=axis, inplace=False) - return result.__finalize__(self) + return result.__finalize__(self, method="tz_convert") def tz_localize( self: FrameOrSeries, @@ -9409,7 +9424,7 @@ def _tz_localize(ax, tz, ambiguous, nonexistent): result = self.copy(deep=copy) result = result.set_axis(ax, axis=axis, inplace=False) - return result.__finalize__(self) + return result.__finalize__(self, method="tz_localize") # ---------------------------------------------------------------------- # Numeric Methods @@ -11188,7 +11203,7 @@ def block_accum_func(blk_values): d = self._construct_axes_dict() d["copy"] = False - return self._constructor(result, **d).__finalize__(self) + return self._constructor(result, **d).__finalize__(self, method=name) return set_function_name(cum_func, name, cls) diff --git a/pandas/core/series.py b/pandas/core/series.py index 5ed8241101925..ccb1ec25b5ba4 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -661,7 +661,7 @@ def view(self, dtype=None) -> "Series": """ return self._constructor( self._values.view(dtype), index=self.index - ).__finalize__(self) + ).__finalize__(self, method="view") # ---------------------------------------------------------------------- # NDArray Compat @@ -829,7 +829,7 @@ def take(self, indices, axis=0, is_copy=None, **kwargs) -> "Series": return self._constructor( new_values, index=new_index, fastpath=True - ).__finalize__(self) + ).__finalize__(self, method="take") def _take_with_is_copy(self, indices, axis=0): """ @@ -962,12 +962,12 @@ def _get_values_tuple(self, key): # If key is contained, would have returned by now indexer, new_index = self.index.get_loc_level(key) return self._constructor(self._values[indexer], index=new_index).__finalize__( - self + self, ) def _get_values(self, indexer): try: - return self._constructor(self._mgr.get_slice(indexer)).__finalize__(self) + return self._constructor(self._mgr.get_slice(indexer)).__finalize__(self,) except ValueError: # mpl compat if we look up e.g. ser[:, np.newaxis]; # see tests.series.timeseries.test_mpl_compat_hack @@ -1181,7 +1181,9 @@ def repeat(self, repeats, axis=None) -> "Series": nv.validate_repeat(tuple(), dict(axis=axis)) new_index = self.index.repeat(repeats) new_values = self._values.repeat(repeats) - return self._constructor(new_values, index=new_index).__finalize__(self) + return self._constructor(new_values, index=new_index).__finalize__( + self, method="repeat" + ) def reset_index(self, level=None, drop=False, name=None, inplace=False): """ @@ -1308,7 +1310,7 @@ def reset_index(self, level=None, drop=False, name=None, inplace=False): else: return self._constructor( self._values.copy(), index=new_index - ).__finalize__(self) + ).__finalize__(self, method="reset_index") elif inplace: raise TypeError( "Cannot reset_index inplace on a Series to create a DataFrame" @@ -1707,7 +1709,9 @@ def count(self, level=None): obs = level_codes[notna(self._values)] out = np.bincount(obs, minlength=len(lev) or None) - return self._constructor(out, index=lev, dtype="int64").__finalize__(self) + return self._constructor(out, index=lev, dtype="int64").__finalize__( + self, method="count" + ) def mode(self, dropna=True) -> "Series": """ @@ -2130,7 +2134,9 @@ def round(self, decimals=0, *args, **kwargs) -> "Series": """ nv.validate_round(args, kwargs) result = self._values.round(decimals) - result = self._constructor(result, index=self.index).__finalize__(self) + result = self._constructor(result, index=self.index).__finalize__( + self, method="round" + ) return result @@ -2352,7 +2358,9 @@ def diff(self, periods: int = 1) -> "Series": dtype: float64 """ result = algorithms.diff(self.array, periods) - return self._constructor(result, index=self.index).__finalize__(self) + return self._constructor(result, index=self.index).__finalize__( + self, method="diff" + ) def autocorr(self, lag=1) -> float: """ @@ -2469,7 +2477,7 @@ def dot(self, other): if isinstance(other, ABCDataFrame): return self._constructor( np.dot(lvals, rvals), index=other.columns - ).__finalize__(self) + ).__finalize__(self, method="dot") elif isinstance(other, Series): return np.dot(lvals, rvals) elif isinstance(rvals, np.ndarray): @@ -2994,7 +3002,7 @@ def _try_kind_sort(arr): if inplace: self._update_inplace(result) else: - return result.__finalize__(self) + return result.__finalize__(self, method="sort_values") def sort_index( self, @@ -3172,7 +3180,7 @@ def sort_index( if inplace: self._update_inplace(result) else: - return result.__finalize__(self) + return result.__finalize__(self, method="sort_index") def argsort(self, axis=0, kind="quicksort", order=None) -> "Series": """ @@ -3206,11 +3214,13 @@ def argsort(self, axis=0, kind="quicksort", order=None) -> "Series": result = Series(-1, index=self.index, name=self.name, dtype="int64") notmask = ~mask result[notmask] = np.argsort(values[notmask], kind=kind) - return self._constructor(result, index=self.index).__finalize__(self) + return self._constructor(result, index=self.index).__finalize__( + self, method="argsort" + ) else: return self._constructor( np.argsort(values, kind=kind), index=self.index, dtype="int64" - ).__finalize__(self) + ).__finalize__(self, method="argsort") def nlargest(self, n=5, keep="first") -> "Series": """ @@ -3428,7 +3438,7 @@ def swaplevel(self, i=-2, j=-1, copy=True) -> "Series": assert isinstance(self.index, ABCMultiIndex) new_index = self.index.swaplevel(i, j) return self._constructor(self._values, index=new_index, copy=copy).__finalize__( - self + self, method="swaplevel" ) def reorder_levels(self, order) -> "Series": @@ -3632,7 +3642,9 @@ def map(self, arg, na_action=None) -> "Series": dtype: object """ new_values = super()._map_values(arg, na_action=na_action) - return self._constructor(new_values, index=self.index).__finalize__(self) + return self._constructor(new_values, index=self.index).__finalize__( + self, method="map" + ) def _gotitem(self, key, ndim, subset=None) -> "Series": """ @@ -3819,7 +3831,7 @@ def apply(self, func, convert_dtype=True, args=(), **kwds): """ if len(self) == 0: return self._constructor(dtype=self.dtype, index=self.index).__finalize__( - self + self, method="apply" ) # dispatch to agg @@ -3856,7 +3868,9 @@ def f(x): # so extension arrays can be used return self._constructor_expanddim(pd.array(mapped), index=self.index) else: - return self._constructor(mapped, index=self.index).__finalize__(self) + return self._constructor(mapped, index=self.index).__finalize__( + self, method="apply" + ) def _reduce( self, op, name, axis=0, skipna=True, numeric_only=None, filter_type=None, **kwds @@ -4297,7 +4311,9 @@ def isin(self, values) -> "Series": Name: animal, dtype: bool """ result = algorithms.isin(self, values) - return self._constructor(result, index=self.index).__finalize__(self) + return self._constructor(result, index=self.index).__finalize__( + self, method="isin" + ) def between(self, left, right, inclusive=True) -> "Series": """ @@ -4533,7 +4549,9 @@ def to_timestamp(self, freq=None, how="start", copy=True) -> "Series": assert isinstance(self.index, (ABCDatetimeIndex, ABCPeriodIndex)) new_index = self.index.to_timestamp(freq=freq, how=how) - return self._constructor(new_values, index=new_index).__finalize__(self) + return self._constructor(new_values, index=new_index).__finalize__( + self, method="to_timestamp" + ) def to_period(self, freq=None, copy=True) -> "Series": """ @@ -4558,7 +4576,9 @@ def to_period(self, freq=None, copy=True) -> "Series": assert isinstance(self.index, ABCDatetimeIndex) new_index = self.index.to_period(freq=freq) - return self._constructor(new_values, index=new_index).__finalize__(self) + return self._constructor(new_values, index=new_index).__finalize__( + self, method="to_period" + ) # ---------------------------------------------------------------------- # Add index