Skip to content

ENH: Deprecate non-keyword arguments for Index.set_names. #41551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 27, 2021
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
11 changes: 9 additions & 2 deletions pandas/core/indexes/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,6 @@ class MultiIndex(Index):
_levels = FrozenList()
_codes = FrozenList()
_comparables = ["names"]
rename = Index.set_names

sortorder: int | None

Expand Down Expand Up @@ -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")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try doing assert isinstance(self, MultiIndex) here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would work, but for things that will be fixed in the future (e.g. this one once all the overloads are in, which will come after positional arguments are deprecated) I think we've generally been ignoring the error

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kk, then we can just merge this.

return self.rename(names) # type: ignore[return-value]
return self

def _maybe_match_names(self, other):
Expand Down Expand Up @@ -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)
Expand Down
17 changes: 17 additions & 0 deletions pandas/tests/indexes/multi/test_get_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions pandas/tests/indexes/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down