diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index fe88cf93886ce..66d9e720153bd 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -679,6 +679,7 @@ Deprecations - Deprecated the ``convert_float`` optional argument in :func:`read_excel` and :meth:`ExcelFile.parse` (:issue:`41127`) - Deprecated behavior of :meth:`DatetimeIndex.union` with mixed timezones; in a future version both will be cast to UTC instead of object dtype (:issue:`39328`) - Deprecated using ``usecols`` with out of bounds indices for ``read_csv`` with ``engine="c"`` (:issue:`25623`) +- Deprecated passing arguments as positional in :meth:`Index.set_names` and :meth:`MultiIndex.set_names` (except for ``names``) (:issue:`41485`) - Deprecated passing arguments as positional in :meth:`DataFrame.clip` and :meth:`Series.clip` (other than ``"upper"`` and ``"lower"``) (:issue:`41485`) - Deprecated special treatment of lists with first element a Categorical in the :class:`DataFrame` constructor; pass as ``pd.DataFrame({col: categorical, ...})`` instead (:issue:`38845`) - Deprecated passing arguments as positional (except for ``"method"``) in :meth:`DataFrame.interpolate` and :meth:`Series.interpolate` (:issue:`41485`) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 2a6f044288fea..2a50ebd959ace 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -1538,7 +1538,7 @@ def _set_names(self, values, level=None) -> None: names = property(fset=_set_names, fget=_get_names) - @final + @deprecate_nonkeyword_arguments(version=None, allowed_args=["self", "names"]) def set_names(self, names, level=None, inplace: bool = False): """ Set Index or MultiIndex name. diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 6a13ffa5a376b..1362679ae0064 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -292,7 +292,6 @@ class MultiIndex(Index): _levels = FrozenList() _codes = FrozenList() _comparables = ["names"] - rename = Index.set_names sortorder: int | None @@ -3585,7 +3584,9 @@ def _get_reconciled_name_object(self, other) -> MultiIndex: """ names = self._maybe_match_names(other) if self.names != names: - return self.rename(names) + # Incompatible return value type (got "Optional[MultiIndex]", expected + # "MultiIndex") + return self.rename(names) # type: ignore[return-value] return self def _maybe_match_names(self, other): @@ -3784,6 +3785,12 @@ def isin(self, values, level=None) -> np.ndarray: return np.zeros(len(levs), dtype=np.bool_) return levs.isin(values) + @deprecate_nonkeyword_arguments(version=None, allowed_args=["self", "names"]) + def set_names(self, names, level=None, inplace: bool = False) -> MultiIndex | None: + return super().set_names(names=names, level=level, inplace=inplace) + + rename = set_names + @deprecate_nonkeyword_arguments(version=None, allowed_args=["self"]) def drop_duplicates(self, keep: str | bool = "first") -> MultiIndex: return super().drop_duplicates(keep=keep) diff --git a/pandas/tests/indexes/multi/test_get_set.py b/pandas/tests/indexes/multi/test_get_set.py index 9657e74c363b9..e756f95bb2bc5 100644 --- a/pandas/tests/indexes/multi/test_get_set.py +++ b/pandas/tests/indexes/multi/test_get_set.py @@ -345,6 +345,23 @@ def test_set_names_with_nlevel_1(inplace): tm.assert_index_equal(result, expected) +def test_multi_set_names_pos_args_deprecation(): + # GH#41485 + idx = MultiIndex.from_product([["python", "cobra"], [2018, 2019]]) + msg = ( + "In a future version of pandas all arguments of MultiIndex.set_names " + "except for the argument 'names' will be keyword-only" + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = idx.set_names(["kind", "year"], None) + expected = MultiIndex( + levels=[["python", "cobra"], [2018, 2019]], + codes=[[0, 0, 1, 1], [0, 1, 0, 1]], + names=["kind", "year"], + ) + tm.assert_index_equal(result, expected) + + @pytest.mark.parametrize("ordered", [True, False]) def test_set_levels_categorical(ordered): # GH13854 diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index f41c79bd09f67..f75e4af888643 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -1740,6 +1740,19 @@ def test_construct_from_memoryview(klass, extra_kwargs): tm.assert_index_equal(result, expected) +def test_index_set_names_pos_args_deprecation(): + # GH#41485 + idx = Index([1, 2, 3, 4]) + msg = ( + "In a future version of pandas all arguments of Index.set_names " + "except for the argument 'names' will be keyword-only" + ) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = idx.set_names("quarter", None) + expected = Index([1, 2, 3, 4], name="quarter") + tm.assert_index_equal(result, expected) + + def test_drop_duplicates_pos_args_deprecation(): # GH#41485 idx = Index([1, 2, 3, 1])