diff --git a/pandas/_typing.py b/pandas/_typing.py index 30244e025e430..35c057df43322 100644 --- a/pandas/_typing.py +++ b/pandas/_typing.py @@ -141,7 +141,7 @@ ] # For functions like rename that convert one label to another -Renamer = Union[Mapping[Hashable, Any], Callable[[Hashable], Hashable]] +Renamer = Union[Mapping[Any, Hashable], Callable[[Any], Hashable]] # to maintain type information across generic functions and parametrization T = TypeVar("T") diff --git a/pandas/core/frame.py b/pandas/core/frame.py index d56e4ef451954..6d4deb79b4898 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -5030,6 +5030,51 @@ def drop( # type: ignore[override] errors=errors, ) + @overload + def rename( + self, + mapper: Renamer | None = ..., + *, + index: Renamer | None = ..., + columns: Renamer | None = ..., + axis: Axis | None = ..., + copy: bool = ..., + inplace: Literal[True], + level: Level | None = ..., + errors: IgnoreRaise = ..., + ) -> None: + ... + + @overload + def rename( + self, + mapper: Renamer | None = ..., + *, + index: Renamer | None = ..., + columns: Renamer | None = ..., + axis: Axis | None = ..., + copy: bool = ..., + inplace: Literal[False] = ..., + level: Level | None = ..., + errors: IgnoreRaise = ..., + ) -> DataFrame: + ... + + @overload + def rename( + self, + mapper: Renamer | None = ..., + *, + index: Renamer | None = ..., + columns: Renamer | None = ..., + axis: Axis | None = ..., + copy: bool = ..., + inplace: bool = ..., + level: Level | None = ..., + errors: IgnoreRaise = ..., + ) -> DataFrame | None: + ... + def rename( self, mapper: Renamer | None = None, @@ -5040,7 +5085,7 @@ def rename( copy: bool = True, inplace: bool = False, level: Level | None = None, - errors: str = "ignore", + errors: IgnoreRaise = "ignore", ) -> DataFrame | None: """ Alter axes labels. diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 700a8f6a39f8d..2e65e3139ffa1 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -984,117 +984,8 @@ def _rename( level: Level | None = None, errors: str = "ignore", ) -> NDFrameT | None: - """ - Alter axes input function or functions. Function / dict values must be - unique (1-to-1). Labels not contained in a dict / Series will be left - as-is. Extra labels listed don't throw an error. Alternatively, change - ``Series.name`` with a scalar value (Series only). - - Parameters - ---------- - %(axes)s : scalar, list-like, dict-like or function, optional - Scalar or list-like will alter the ``Series.name`` attribute, - and raise on DataFrame. - dict-like or functions are transformations to apply to - that axis' values - copy : bool, default True - Also copy underlying data. - inplace : bool, default False - Whether to return a new {klass}. If True then value of copy is - ignored. - level : int or level name, default None - In case of a MultiIndex, only rename labels in the specified - level. - errors : {'ignore', 'raise'}, default 'ignore' - If 'raise', raise a `KeyError` when a dict-like `mapper`, `index`, - or `columns` contains labels that are not present in the Index - being transformed. - If 'ignore', existing keys will be renamed and extra keys will be - ignored. - - Returns - ------- - renamed : {klass} (new object) - - Raises - ------ - KeyError - If any of the labels is not found in the selected axis and - "errors='raise'". + # called by Series.rename and DataFrame.rename - See Also - -------- - NDFrame.rename_axis - - Examples - -------- - >>> s = pd.Series([1, 2, 3]) - >>> s - 0 1 - 1 2 - 2 3 - dtype: int64 - >>> s.rename("my_name") # scalar, changes Series.name - 0 1 - 1 2 - 2 3 - Name: my_name, dtype: int64 - >>> s.rename(lambda x: x ** 2) # function, changes labels - 0 1 - 1 2 - 4 3 - dtype: int64 - >>> s.rename({1: 3, 2: 5}) # mapping, changes labels - 0 1 - 3 2 - 5 3 - dtype: int64 - - Since ``DataFrame`` doesn't have a ``.name`` attribute, - only mapping-type arguments are allowed. - - >>> df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]}) - >>> df.rename(2) - Traceback (most recent call last): - ... - TypeError: 'int' object is not callable - - ``DataFrame.rename`` supports two calling conventions - - * ``(index=index_mapper, columns=columns_mapper, ...)`` - * ``(mapper, axis={'index', 'columns'}, ...)`` - - We *highly* recommend using keyword arguments to clarify your - intent. - - >>> df.rename(index=str, columns={"A": "a", "B": "c"}) - a c - 0 1 4 - 1 2 5 - 2 3 6 - - >>> df.rename(index=str, columns={"A": "a", "C": "c"}) - a B - 0 1 4 - 1 2 5 - 2 3 6 - - Using axis-style parameters - - >>> df.rename(str.lower, axis='columns') - a b - 0 1 4 - 1 2 5 - 2 3 6 - - >>> df.rename({1: 2, 2: 4}, axis='index') - A B - 0 1 4 - 2 2 5 - 4 3 6 - - See the :ref:`user guide ` for more. - """ if mapper is None and index is None and columns is None: raise TypeError("must pass an index to rename") diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 91c35d7555705..f649cce985474 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -2204,8 +2204,7 @@ def size(self) -> DataFrame | Series: result = self._obj_1d_constructor(result) if not self.as_index: - # Item "None" of "Optional[Series]" has no attribute "reset_index" - result = result.rename("size").reset_index() # type: ignore[union-attr] + result = result.rename("size").reset_index() return self._reindex_output(result, fill_value=0) diff --git a/pandas/core/series.py b/pandas/core/series.py index 83c5e8206952c..1d3509cac0edd 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -42,6 +42,7 @@ IndexKeyFunc, Level, NaPosition, + Renamer, SingleManager, SortKind, StorageOptions, @@ -4617,15 +4618,54 @@ def align( broadcast_axis=broadcast_axis, ) + @overload def rename( self, - index=None, + index: Renamer | Hashable | None = ..., *, - axis=None, - copy=True, - inplace=False, - level=None, - errors="ignore", + axis: Axis | None = ..., + copy: bool = ..., + inplace: Literal[True], + level: Level | None = ..., + errors: IgnoreRaise = ..., + ) -> None: + ... + + @overload + def rename( + self, + index: Renamer | Hashable | None = ..., + *, + axis: Axis | None = ..., + copy: bool = ..., + inplace: Literal[False] = ..., + level: Level | None = ..., + errors: IgnoreRaise = ..., + ) -> Series: + ... + + @overload + def rename( + self, + index: Renamer | Hashable | None = ..., + *, + axis: Axis | None = ..., + copy: bool = ..., + inplace: bool = ..., + level: Level | None = ..., + errors: IgnoreRaise = ..., + ) -> Series | None: + ... + + def rename( + self, + index: Renamer | Hashable | None = None, + *, + axis: Axis | None = None, + copy: bool = True, + inplace: bool = False, + level: Level | None = None, + errors: IgnoreRaise = "ignore", ) -> Series | None: """ Alter Series index labels or name. @@ -4691,8 +4731,16 @@ def rename( axis = self._get_axis_number(axis) if callable(index) or is_dict_like(index): + # error: Argument 1 to "_rename" of "NDFrame" has incompatible + # type "Union[Union[Mapping[Any, Hashable], Callable[[Any], + # Hashable]], Hashable, None]"; expected "Union[Mapping[Any, + # Hashable], Callable[[Any], Hashable], None]" return super()._rename( - index, copy=copy, inplace=inplace, level=level, errors=errors + index, # type: ignore[arg-type] + copy=copy, + inplace=inplace, + level=level, + errors=errors, ) else: return self._set_name(index, inplace=inplace) diff --git a/pandas/io/json/_normalize.py b/pandas/io/json/_normalize.py index 4a2e49fd85f45..e77d60d2d4950 100644 --- a/pandas/io/json/_normalize.py +++ b/pandas/io/json/_normalize.py @@ -520,11 +520,7 @@ def _recursive_extract(data, path, seen_meta, level=0): result = DataFrame(records) if record_prefix is not None: - # Incompatible types in assignment (expression has type "Optional[DataFrame]", - # variable has type "DataFrame") - result = result.rename( # type: ignore[assignment] - columns=lambda x: f"{record_prefix}{x}" - ) + result = result.rename(columns=lambda x: f"{record_prefix}{x}") # Data types, a problem for k, v in meta_vals.items():