Skip to content
Open
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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@ Other Deprecations
- Deprecated backward-compatibility behavior for :meth:`DataFrame.select_dtypes` matching "str" dtype when ``np.object_`` is specified (:issue:`61916`)
- Deprecated option "future.no_silent_downcasting", as it is no longer used. In a future version accessing this option will raise (:issue:`59502`)
- Deprecated passing non-Index types to :meth:`Index.join`; explicitly convert to Index first (:issue:`62897`)
- Deprecated setting the :attr:`MultiIndex.name` attribute, as it is not used. Set :attr:`MultiIndex.names` instead (:issue:`11979`)
- Deprecated silent casting of non-datetime 'other' to datetime in :meth:`Series.combine_first` (:issue:`62931`)
- Deprecated silently casting strings to :class:`Timedelta` in binary operations with :class:`Timedelta` (:issue:`59653`)
- Deprecated slicing on a :class:`Series` or :class:`DataFrame` with a :class:`DatetimeIndex` using a ``datetime.date`` object, explicitly cast to :class:`Timestamp` instead (:issue:`35830`)
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/groupby/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2180,7 +2180,7 @@ def _wrap_applied_output_series(

index = key_index
columns = first_not_none.index.copy()
if columns.name is None:
if columns.name is None and not isinstance(columns, MultiIndex):
# GH6124 - propagate name of Series when it's consistent
names = {v.name for v in values}
if len(names) == 1:
Expand Down
14 changes: 13 additions & 1 deletion pandas/core/indexes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1802,6 +1802,15 @@ def name(self, value: Hashable) -> None:
"Cannot set name on a level of a MultiIndex. Use "
"'MultiIndex.set_names' instead."
)
if self._is_multi:
warnings.warn(
# GH#11979
"Setting .name on a MultiIndex is deprecated and will "
"raise in a future version. Set 'names' instead.",
Pandas4Warning,
stacklevel=find_stack_level(),
)

maybe_extract_name(value, None, type(self))
self._name = value

Expand Down Expand Up @@ -6188,7 +6197,10 @@ def _get_indexer_strict(self, key, axis_name: str_t) -> tuple[Index, np.ndarray]
keyarr = self.take(indexer)
if isinstance(key, Index):
# GH 42790 - Preserve name from an Index
keyarr.name = key.name
if keyarr._is_multi:
keyarr.names = key.names
else:
keyarr.name = key.name
if lib.is_np_dtype(keyarr.dtype, "mM") or isinstance(
keyarr.dtype, DatetimeTZDtype
):
Expand Down
12 changes: 8 additions & 4 deletions pandas/tests/indexes/test_any_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,12 @@ def test_pickle_roundtrip(self, index):
assert index.equal_levels(result)

def test_pickle_preserves_name(self, index):
original_name, index.name = index.name, "foo"
if not index._is_multi:
original_name, index.name = index.name, "foo"
unpickled = tm.round_trip_pickle(index)
assert index.equals(unpickled)
index.name = original_name
if not index._is_multi:
index.name = original_name


class TestIndexing:
Expand Down Expand Up @@ -165,8 +167,10 @@ def test_getitem_error(self, index, item):
class TestRendering:
def test_str(self, index):
# test the string repr
index.name = "foo"
assert "'foo'" in str(index)
if index._is_multi:
pytest.skip(reason=".name does not show up in repr")
index.name = "my_index_name"
assert "'my_index_name'" in str(index)
assert type(index).__name__ in str(index)


Expand Down
6 changes: 4 additions & 2 deletions pandas/tests/indexes/test_setops.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,10 +848,12 @@ def test_difference_name_preservation(self, index, second_name, expected, sort):
def test_difference_empty_arg(self, index, sort):
first = index.copy()
first = first[5:20]
first.name = "name"
if not first._is_multi:
first.name = "name"
result = first.difference([], sort)
expected = index[5:20].unique()
expected.name = "name"
if not index._is_multi:
expected.name = "name"
tm.assert_index_equal(result, expected)

def test_difference_should_not_compare(self):
Expand Down
3 changes: 2 additions & 1 deletion pandas/tests/io/json/test_json_table_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,8 @@ def test_set_names_unset(self, idx, nm, prop):
def test_warns_non_roundtrippable_names(self, idx):
# GH 19130
df = DataFrame(index=idx)
df.index.name = "index"
if not idx._is_multi:
df.index.name = "index"
with tm.assert_produces_warning(UserWarning, match="not round-trippable"):
set_default_names(df)

Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/resample/test_resampler_grouper.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ def test_empty(keys):
.set_index(keys, drop=False)
.set_index(TimedeltaIndex([]), append=True)[expected_columns]
)
if len(keys) == 1:
if len(keys) == 1 and not expected.index._is_multi:
expected.index.name = keys[0]

tm.assert_frame_equal(result, expected)
Expand Down Expand Up @@ -545,7 +545,7 @@ def test_resample_no_index(keys):
expected = DataFrame(columns=["a", "b", "date"]).set_index(keys, drop=False)
expected["date"] = pd.to_datetime(expected["date"])
expected = expected.set_index("date", append=True, drop=True)[expected_columns]
if len(keys) == 1:
if len(keys) == 1 and not expected.index._is_multi:
expected.index.name = keys[0]

tm.assert_frame_equal(result, expected)
Expand Down
Loading