diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 3108c1a1afd0c..a756900ff9ae5 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -1,7 +1,7 @@ """ define the IntervalIndex """ from operator import le, lt import textwrap -from typing import Any, Optional, Tuple, Union +from typing import TYPE_CHECKING, Any, Optional, Tuple, Union import numpy as np @@ -34,7 +34,6 @@ is_object_dtype, is_scalar, ) -from pandas.core.dtypes.generic import ABCSeries from pandas.core.dtypes.missing import isna from pandas.core import accessor @@ -59,6 +58,10 @@ from pandas.tseries.frequencies import to_offset from pandas.tseries.offsets import DateOffset +if TYPE_CHECKING: + from pandas import Series + + _VALID_CLOSED = {"left", "right", "both", "neither"} _index_doc_kwargs = dict(ibase._index_doc_kwargs) @@ -681,7 +684,7 @@ def _searchsorted_monotonic(self, label, side, exclude_label=False): return sub_idx._searchsorted_monotonic(label, side) def get_loc( - self, key: Any, method: Optional[str] = None, tolerance=None + self, key, method: Optional[str] = None, tolerance=None ) -> Union[int, slice, np.ndarray]: """ Get integer location, slice or boolean mask for requested label. @@ -723,10 +726,8 @@ def get_loc( """ self._check_method(method) - # list-like are invalid labels for II but in some cases may work, e.g - # single element array of comparable type, so guard against them early - if is_list_like(key): - raise KeyError(key) + if not is_scalar(key): + raise InvalidIndexError(key) if isinstance(key, Interval): if self.closed != key.closed: @@ -819,6 +820,9 @@ def get_indexer( loc = self.get_loc(key) except KeyError: loc = -1 + except InvalidIndexError: + # i.e. non-scalar key + raise TypeError(key) indexer.append(loc) return ensure_platform_int(indexer) @@ -882,25 +886,15 @@ def get_indexer_for(self, target: AnyArrayLike, **kwargs) -> np.ndarray: return self.get_indexer(target, **kwargs) @Appender(_index_shared_docs["get_value"] % _index_doc_kwargs) - def get_value(self, series: ABCSeries, key: Any) -> Any: - - if com.is_bool_indexer(key): - loc = key - elif is_list_like(key): - if self.is_overlapping: - loc, missing = self.get_indexer_non_unique(key) - if len(missing): - raise KeyError - else: - loc = self.get_indexer(key) - elif isinstance(key, slice): - if not (key.step is None or key.step == 1): - raise ValueError("cannot support not-default step in a slice") - loc = self._convert_slice_indexer(key, kind="getitem") - else: - loc = self.get_loc(key) + def get_value(self, series: "Series", key): + loc = self.get_loc(key) return series.iloc[loc] + def _convert_slice_indexer(self, key: slice, kind=None): + if not (key.step is None or key.step == 1): + raise ValueError("cannot support not-default step in a slice") + return super()._convert_slice_indexer(key, kind) + @Appender(_index_shared_docs["where"]) def where(self, cond, other=None): if other is None: diff --git a/pandas/core/series.py b/pandas/core/series.py index ffe0642f799fa..2f861f1e0ec64 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -75,6 +75,7 @@ from pandas.core.indexes.api import ( Float64Index, Index, + IntervalIndex, InvalidIndexError, MultiIndex, ensure_index, @@ -872,6 +873,9 @@ def _get_with(self, key): if key_type == "integer": if self.index.is_integer() or self.index.is_floating(): return self.loc[key] + elif isinstance(self.index, IntervalIndex): + indexer = self.index.get_indexer_for(key) + return self.iloc[indexer] else: return self._get_values(key) elif key_type == "boolean":