Skip to content

Commit 46ddb8e

Browse files
authored
BUG: Index.get_loc always raise InvalidIndexError on listlike (pandas-dev#45181)
1 parent 336fcc1 commit 46ddb8e

File tree

10 files changed

+52
-13
lines changed

10 files changed

+52
-13
lines changed

pandas/core/frame.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -3464,7 +3464,8 @@ def __getitem__(self, key):
34643464
key = lib.item_from_zerodim(key)
34653465
key = com.apply_if_callable(key, self)
34663466

3467-
if is_hashable(key):
3467+
if is_hashable(key) and not is_iterator(key):
3468+
# is_iterator to exclude generator e.g. test_getitem_listlike
34683469
# shortcut if the key is in columns
34693470
if self.columns.is_unique and key in self.columns:
34703471
if isinstance(self.columns, MultiIndex):

pandas/core/indexes/base.py

+6
Original file line numberDiff line numberDiff line change
@@ -3600,6 +3600,12 @@ def get_loc(self, key, method=None, tolerance=None):
36003600
return self._engine.get_loc(casted_key)
36013601
except KeyError as err:
36023602
raise KeyError(key) from err
3603+
except TypeError:
3604+
# If we have a listlike key, _check_indexing_error will raise
3605+
# InvalidIndexError. Otherwise we fall through and re-raise
3606+
# the TypeError.
3607+
self._check_indexing_error(key)
3608+
raise
36033609

36043610
# GH#42269
36053611
warnings.warn(

pandas/core/indexes/multi.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2815,7 +2815,7 @@ def get_loc(self, key, method=None):
28152815
"currently supported for MultiIndex"
28162816
)
28172817

2818-
hash(key)
2818+
self._check_indexing_error(key)
28192819

28202820
def _maybe_to_slice(loc):
28212821
"""convert integer indexer to boolean mask or slice if possible"""

pandas/core/series.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,9 @@ def __getitem__(self, key):
966966

967967
return result
968968

969-
except (KeyError, TypeError):
969+
except (KeyError, TypeError, InvalidIndexError):
970+
# InvalidIndexError for e.g. generator
971+
# see test_series_getitem_corner_generator
970972
if isinstance(key, tuple) and isinstance(self.index, MultiIndex):
971973
# We still have the corner case where a tuple is a key
972974
# in the first level of our MultiIndex

pandas/tests/frame/indexing/test_indexing.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import pytest
99

1010
from pandas._libs import iNaT
11+
from pandas.errors import InvalidIndexError
1112
import pandas.util._test_decorators as td
1213

1314
from pandas.core.dtypes.common import is_integer
@@ -1171,7 +1172,7 @@ def test_type_error_multiindex(self):
11711172
dg = DataFrame(
11721173
[[1, 1, 2, 2], [3, 3, 4, 4]], columns=mi, index=Index([0, 1], name="i")
11731174
)
1174-
with pytest.raises(TypeError, match="unhashable type"):
1175+
with pytest.raises(InvalidIndexError, match="slice"):
11751176
dg[:, 0]
11761177

11771178
index = Index(range(2), name="i")

pandas/tests/indexes/multi/test_indexing.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ def test_get_loc_missing_nan(self):
652652
idx.get_loc(3)
653653
with pytest.raises(KeyError, match=r"^nan$"):
654654
idx.get_loc(np.nan)
655-
with pytest.raises(TypeError, match="unhashable type: 'list'"):
655+
with pytest.raises(InvalidIndexError, match=r"\[nan\]"):
656656
# listlike/non-hashable raises TypeError
657657
idx.get_loc([np.nan])
658658

@@ -699,8 +699,8 @@ def test_get_loc_past_lexsort_depth(self):
699699
def test_multiindex_get_loc_list_raises(self):
700700
# GH#35878
701701
idx = MultiIndex.from_tuples([("a", 1), ("b", 2)])
702-
msg = "unhashable type"
703-
with pytest.raises(TypeError, match=msg):
702+
msg = r"\[\]"
703+
with pytest.raises(InvalidIndexError, match=msg):
704704
idx.get_loc([])
705705

706706
def test_get_loc_nested_tuple_raises_keyerror(self):

pandas/tests/indexes/numeric/test_indexing.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import numpy as np
22
import pytest
33

4+
from pandas.errors import InvalidIndexError
5+
46
from pandas import (
57
Index,
68
RangeIndex,
@@ -41,10 +43,12 @@ def test_get_loc_raises_bad_label(self, method):
4143
index = Index([0, 1, 2])
4244
if method:
4345
msg = "not supported between"
46+
err = TypeError
4447
else:
45-
msg = "invalid key"
48+
msg = r"\[1, 2\]"
49+
err = InvalidIndexError
4650

47-
with pytest.raises(TypeError, match=msg):
51+
with pytest.raises(err, match=msg):
4852
index.get_loc([1, 2], method=method)
4953

5054
@pytest.mark.parametrize(
@@ -141,7 +145,7 @@ def test_get_loc_missing_nan(self):
141145
idx.get_loc(3)
142146
with pytest.raises(KeyError, match="^nan$"):
143147
idx.get_loc(np.nan)
144-
with pytest.raises(TypeError, match=r"'\[nan\]' is an invalid key"):
148+
with pytest.raises(InvalidIndexError, match=r"\[nan\]"):
145149
# listlike/non-hashable raises TypeError
146150
idx.get_loc([np.nan])
147151

pandas/tests/indexes/test_any_index.py

+13
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
"""
44
import re
55

6+
import numpy as np
67
import pytest
78

9+
from pandas.errors import InvalidIndexError
10+
811
import pandas._testing as tm
912

1013

@@ -125,6 +128,16 @@ def test_pickle_preserves_name(self, index):
125128

126129

127130
class TestIndexing:
131+
def test_get_loc_listlike_raises_invalid_index_error(self, index):
132+
# and never TypeError
133+
key = np.array([0, 1], dtype=np.intp)
134+
135+
with pytest.raises(InvalidIndexError, match=r"\[0 1\]"):
136+
index.get_loc(key)
137+
138+
with pytest.raises(InvalidIndexError, match=r"\[False True\]"):
139+
index.get_loc(key.astype(bool))
140+
128141
def test_getitem_ellipsis(self, index):
129142
# GH#21282
130143
result = index[...]

pandas/tests/indexes/test_base.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import pytest
99

1010
from pandas.compat import IS64
11+
from pandas.errors import InvalidIndexError
1112
from pandas.util._test_decorators import async_mark
1213

1314
import pandas as pd
@@ -398,11 +399,15 @@ def test_asof_numeric_vs_bool_raises(self):
398399
left = Index([1, 2, 3])
399400
right = Index([True, False])
400401

401-
msg = "'<' not supported between instances"
402+
msg = "Cannot compare dtypes int64 and object"
402403
with pytest.raises(TypeError, match=msg):
404+
left.asof(right[0])
405+
# TODO: should right.asof(left[0]) also raise?
406+
407+
with pytest.raises(InvalidIndexError, match=re.escape(str(right))):
403408
left.asof(right)
404409

405-
with pytest.raises(TypeError, match=msg):
410+
with pytest.raises(InvalidIndexError, match=re.escape(str(left))):
406411
right.asof(left)
407412

408413
@pytest.mark.parametrize("index", ["string"], indirect=True)

pandas/tests/indexes/test_indexing.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,14 @@ def test_get_loc_generator(self, index):
206206
exc = KeyError
207207
if isinstance(
208208
index,
209-
(DatetimeIndex, TimedeltaIndex, PeriodIndex, RangeIndex, IntervalIndex),
209+
(
210+
DatetimeIndex,
211+
TimedeltaIndex,
212+
PeriodIndex,
213+
RangeIndex,
214+
IntervalIndex,
215+
MultiIndex,
216+
),
210217
):
211218
# TODO: make these more consistent?
212219
exc = InvalidIndexError

0 commit comments

Comments
 (0)