Skip to content
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

CLN/DEPR: remove setter for MultiIndex levels/labels properties #18256

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v0.22.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Removal of prior version deprecations/changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- Warnings against the obsolete usage ``Categorical(codes, categories)``, which were emitted for instance when the first two arguments to ``Categorical()`` had different dtypes, and recommended the use of ``Categorical.from_codes``, have now been removed (:issue:`8074`)
-
- The ``levels`` and ``labels`` attributes of a ``MultiIndex`` can no longer be set directly (:issue:`4039`).
-

.. _whatsnew_0220.performance:
Expand Down
24 changes: 5 additions & 19 deletions pandas/core/indexes/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# pylint: disable=E1101,E1103,W0232
import datetime
import warnings
from functools import partial
from sys import getsizeof

import numpy as np
Expand All @@ -28,8 +27,7 @@
is_true_slices)

import pandas.core.base as base
from pandas.util._decorators import (Appender, cache_readonly,
deprecate, deprecate_kwarg)
from pandas.util._decorators import Appender, cache_readonly, deprecate_kwarg
import pandas.core.common as com
import pandas.core.missing as missing
import pandas.core.algorithms as algos
Expand Down Expand Up @@ -177,7 +175,8 @@ def _verify_integrity(self, labels=None, levels=None):
" inconsistent state" % (i, label.max(),
len(level)))

def _get_levels(self):
@property
def levels(self):
return self._levels

def _set_levels(self, levels, level=None, copy=False, validate=True,
Expand Down Expand Up @@ -279,14 +278,8 @@ def set_levels(self, levels, level=None, inplace=False,
if not inplace:
return idx

# remove me in 0.14 and change to read only property
__set_levels = deprecate("setting `levels` directly",
partial(set_levels, inplace=True,
verify_integrity=True),
alt_name="set_levels")
levels = property(fget=_get_levels, fset=__set_levels)

def _get_labels(self):
@property
def labels(self):
return self._labels

def _set_labels(self, labels, level=None, copy=False, validate=True,
Expand Down Expand Up @@ -379,13 +372,6 @@ def set_labels(self, labels, level=None, inplace=False,
if not inplace:
return idx

# remove me in 0.14 and change to readonly property
__set_labels = deprecate("setting labels directly",
partial(set_labels, inplace=True,
verify_integrity=True),
alt_name="set_labels")
labels = property(fget=_get_labels, fset=__set_labels)

def copy(self, names=None, dtype=None, levels=None, labels=None,
deep=False, _set_identity=False, **kwargs):
"""
Expand Down
28 changes: 18 additions & 10 deletions pandas/tests/indexes/test_multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,24 @@ def test_set_name_methods(self):
assert res is None
assert ind.names == new_names2

def test_set_levels_labels_directly(self):
# setting levels/labels directly raises AttributeError

levels = self.index.levels
new_levels = [[lev + 'a' for lev in level] for level in levels]

labels = self.index.labels
major_labels, minor_labels = labels
major_labels = [(x + 1) % 3 for x in major_labels]
minor_labels = [(x + 1) % 1 for x in minor_labels]
new_labels = [major_labels, minor_labels]

with pytest.raises(AttributeError):
self.index.levels = new_levels

with pytest.raises(AttributeError):
self.index.labels = new_labels

def test_set_levels(self):
# side note - you probably wouldn't want to use levels and labels
# directly like this - but it is possible.
Expand Down Expand Up @@ -578,16 +596,6 @@ def test_constructor_mismatched_label_levels(self):
with tm.assert_raises_regex(ValueError, label_error):
self.index.copy().set_labels([[0, 0, 0, 0], [0, 0]])

# deprecated properties
with warnings.catch_warnings():
warnings.simplefilter('ignore')

with tm.assert_raises_regex(ValueError, length_error):
self.index.copy().levels = [['a'], ['b']]

with tm.assert_raises_regex(ValueError, label_error):
self.index.copy().labels = [[0, 0, 0, 0], [0, 0]]

def assert_multiindex_copied(self, copy, original):
# Levels should be (at least, shallow copied)
tm.assert_copy(copy.levels, original.levels)
Expand Down