|
51 | 51 | length_of_indexer,
|
52 | 52 | )
|
53 | 53 | from pandas.core.indexes.api import (
|
| 54 | + CategoricalIndex, |
54 | 55 | Index,
|
| 56 | + IntervalIndex, |
55 | 57 | MultiIndex,
|
| 58 | + ensure_index, |
56 | 59 | )
|
57 | 60 |
|
58 | 61 | if TYPE_CHECKING:
|
@@ -1297,6 +1300,11 @@ def _get_listlike_indexer(self, key, axis: int):
|
1297 | 1300 | keyarr, indexer, new_indexer = ax._reindex_non_unique(keyarr)
|
1298 | 1301 |
|
1299 | 1302 | self._validate_read_indexer(keyarr, indexer, axis)
|
| 1303 | + |
| 1304 | + if isinstance(ax, (IntervalIndex, CategoricalIndex)): |
| 1305 | + # take instead of reindex to preserve dtype. For IntervalIndex |
| 1306 | + # this is to map integers to the Intervals they match to. |
| 1307 | + keyarr = ax.take(indexer) |
1300 | 1308 | return keyarr, indexer
|
1301 | 1309 |
|
1302 | 1310 | def _validate_read_indexer(self, key, indexer, axis: int):
|
@@ -1329,13 +1337,22 @@ def _validate_read_indexer(self, key, indexer, axis: int):
|
1329 | 1337 | missing = (missing_mask).sum()
|
1330 | 1338 |
|
1331 | 1339 | if missing:
|
| 1340 | + ax = self.obj._get_axis(axis) |
| 1341 | + |
| 1342 | + # TODO: remove special-case; this is just to keep exception |
| 1343 | + # message tests from raising while debugging |
| 1344 | + use_interval_msg = isinstance(ax, IntervalIndex) or ( |
| 1345 | + isinstance(ax, CategoricalIndex) |
| 1346 | + and isinstance(ax.categories, IntervalIndex) |
| 1347 | + ) |
| 1348 | + |
1332 | 1349 | if missing == len(indexer):
|
1333 | 1350 | axis_name = self.obj._get_axis_name(axis)
|
| 1351 | + if use_interval_msg: |
| 1352 | + key = list(key) |
1334 | 1353 | raise KeyError(f"None of [{key}] are in the [{axis_name}]")
|
1335 | 1354 |
|
1336 |
| - ax = self.obj._get_axis(axis) |
1337 |
| - |
1338 |
| - not_found = list(set(key) - set(ax)) |
| 1355 | + not_found = list(ensure_index(key)[missing_mask.nonzero()[0]].unique()) |
1339 | 1356 | raise KeyError(f"{not_found} not in index")
|
1340 | 1357 |
|
1341 | 1358 |
|
|
0 commit comments