Skip to content

Commit 69472f9

Browse files
CLN/DEPR: remove setter for MultiIndex levels/labels properties (#18256)
1 parent 7495e9a commit 69472f9

File tree

3 files changed

+24
-30
lines changed

3 files changed

+24
-30
lines changed

doc/source/whatsnew/v0.22.0.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Removal of prior version deprecations/changes
6262
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6363

6464
- 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`)
65-
-
65+
- The ``levels`` and ``labels`` attributes of a ``MultiIndex`` can no longer be set directly (:issue:`4039`).
6666
-
6767

6868
.. _whatsnew_0220.performance:

pandas/core/indexes/multi.py

+5-19
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
# pylint: disable=E1101,E1103,W0232
33
import datetime
44
import warnings
5-
from functools import partial
65
from sys import getsizeof
76

87
import numpy as np
@@ -28,8 +27,7 @@
2827
is_true_slices)
2928

3029
import pandas.core.base as base
31-
from pandas.util._decorators import (Appender, cache_readonly,
32-
deprecate, deprecate_kwarg)
30+
from pandas.util._decorators import Appender, cache_readonly, deprecate_kwarg
3331
import pandas.core.common as com
3432
import pandas.core.missing as missing
3533
import pandas.core.algorithms as algos
@@ -177,7 +175,8 @@ def _verify_integrity(self, labels=None, levels=None):
177175
" inconsistent state" % (i, label.max(),
178176
len(level)))
179177

180-
def _get_levels(self):
178+
@property
179+
def levels(self):
181180
return self._levels
182181

183182
def _set_levels(self, levels, level=None, copy=False, validate=True,
@@ -279,14 +278,8 @@ def set_levels(self, levels, level=None, inplace=False,
279278
if not inplace:
280279
return idx
281280

282-
# remove me in 0.14 and change to read only property
283-
__set_levels = deprecate("setting `levels` directly",
284-
partial(set_levels, inplace=True,
285-
verify_integrity=True),
286-
alt_name="set_levels")
287-
levels = property(fget=_get_levels, fset=__set_levels)
288-
289-
def _get_labels(self):
281+
@property
282+
def labels(self):
290283
return self._labels
291284

292285
def _set_labels(self, labels, level=None, copy=False, validate=True,
@@ -379,13 +372,6 @@ def set_labels(self, labels, level=None, inplace=False,
379372
if not inplace:
380373
return idx
381374

382-
# remove me in 0.14 and change to readonly property
383-
__set_labels = deprecate("setting labels directly",
384-
partial(set_labels, inplace=True,
385-
verify_integrity=True),
386-
alt_name="set_labels")
387-
labels = property(fget=_get_labels, fset=__set_labels)
388-
389375
def copy(self, names=None, dtype=None, levels=None, labels=None,
390376
deep=False, _set_identity=False, **kwargs):
391377
"""

pandas/tests/indexes/test_multi.py

+18-10
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,24 @@ def test_set_name_methods(self):
158158
assert res is None
159159
assert ind.names == new_names2
160160

161+
def test_set_levels_labels_directly(self):
162+
# setting levels/labels directly raises AttributeError
163+
164+
levels = self.index.levels
165+
new_levels = [[lev + 'a' for lev in level] for level in levels]
166+
167+
labels = self.index.labels
168+
major_labels, minor_labels = labels
169+
major_labels = [(x + 1) % 3 for x in major_labels]
170+
minor_labels = [(x + 1) % 1 for x in minor_labels]
171+
new_labels = [major_labels, minor_labels]
172+
173+
with pytest.raises(AttributeError):
174+
self.index.levels = new_levels
175+
176+
with pytest.raises(AttributeError):
177+
self.index.labels = new_labels
178+
161179
def test_set_levels(self):
162180
# side note - you probably wouldn't want to use levels and labels
163181
# directly like this - but it is possible.
@@ -578,16 +596,6 @@ def test_constructor_mismatched_label_levels(self):
578596
with tm.assert_raises_regex(ValueError, label_error):
579597
self.index.copy().set_labels([[0, 0, 0, 0], [0, 0]])
580598

581-
# deprecated properties
582-
with warnings.catch_warnings():
583-
warnings.simplefilter('ignore')
584-
585-
with tm.assert_raises_regex(ValueError, length_error):
586-
self.index.copy().levels = [['a'], ['b']]
587-
588-
with tm.assert_raises_regex(ValueError, label_error):
589-
self.index.copy().labels = [[0, 0, 0, 0], [0, 0]]
590-
591599
def assert_multiindex_copied(self, copy, original):
592600
# Levels should be (at least, shallow copied)
593601
tm.assert_copy(copy.levels, original.levels)

0 commit comments

Comments
 (0)