Skip to content

Backport PR #35914 on branch 1.1.x (Make MultiIndex.get_loc raise for unhashable type) #36163

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
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/v1.1.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Fixed regressions
- Regression in :meth:`DatetimeIndex.intersection` incorrectly raising ``AssertionError`` when intersecting against a list (:issue:`35876`)
- Fix regression in updating a column inplace (e.g. using ``df['col'].fillna(.., inplace=True)``) (:issue:`35731`)
- Performance regression for :meth:`RangeIndex.format` (:issue:`35712`)
- Regression where :meth:`MultiIndex.get_loc` would return a slice spanning the full index when passed an empty list (:issue:`35878`)
- Fix regression in invalid cache after an indexing operation; this can manifest when setting which does not update the data (:issue:`35521`)
- Regression in :meth:`DataFrame.replace` where a ``TypeError`` would be raised when attempting to replace elements of type :class:`Interval` (:issue:`35931`)
- Fix regression in pickle roundtrip of the ``closed`` attribute of :class:`IntervalIndex` (:issue:`35658`)
Expand Down
5 changes: 3 additions & 2 deletions pandas/core/indexes/multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2681,6 +2681,8 @@ def get_loc(self, key, method=None):
"currently supported for MultiIndex"
)

hash(key)

def _maybe_to_slice(loc):
"""convert integer indexer to boolean mask or slice if possible"""
if not isinstance(loc, np.ndarray) or loc.dtype != "int64":
Expand All @@ -2695,8 +2697,7 @@ def _maybe_to_slice(loc):
mask[loc] = True
return mask

if not isinstance(key, (tuple, list)):
# not including list here breaks some indexing, xref #30892
if not isinstance(key, tuple):
loc = self._get_level_indexer(key, level=0)
return _maybe_to_slice(loc)

Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/frame/indexing/test_indexing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2111,7 +2111,7 @@ def test_type_error_multiindex(self):
)
dg = df.pivot_table(index="i", columns="c", values=["x", "y"])

with pytest.raises(TypeError, match="is an invalid key"):
with pytest.raises(TypeError, match="unhashable type"):
dg[:, 0]

index = Index(range(2), name="i")
Expand Down
8 changes: 8 additions & 0 deletions pandas/tests/indexing/multiindex/test_multiindex.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import numpy as np
import pytest

import pandas._libs.index as _index
from pandas.errors import PerformanceWarning
Expand Down Expand Up @@ -83,3 +84,10 @@ def test_nested_tuples_duplicates(self):
df3 = df.copy(deep=True)
df3.loc[[(dti[0], "a")], "c2"] = 1.0
tm.assert_frame_equal(df3, expected)

def test_multiindex_get_loc_list_raises(self):
# https://github.com/pandas-dev/pandas/issues/35878
idx = pd.MultiIndex.from_tuples([("a", 1), ("b", 2)])
msg = "unhashable type"
with pytest.raises(TypeError, match=msg):
idx.get_loc([])
11 changes: 10 additions & 1 deletion pandas/tests/series/indexing/test_setitem.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import numpy as np

from pandas import NaT, Series, date_range
from pandas import MultiIndex, NaT, Series, date_range
import pandas.testing as tm


class TestSetitemDT64Values:
Expand All @@ -17,3 +18,11 @@ def test_setitem_none_nan(self):

series[5:7] = np.nan
assert series[6] is NaT

def test_setitem_multiindex_empty_slice(self):
# https://github.com/pandas-dev/pandas/issues/35878
idx = MultiIndex.from_tuples([("a", 1), ("b", 2)])
result = Series([1, 2], index=idx)
expected = result.copy()
result.loc[[]] = 0
tm.assert_series_equal(result, expected)