From 83cdd42461c3d6690dbad0f3b612a0b9eb4f7234 Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Thu, 9 Jan 2020 16:25:48 -0800 Subject: [PATCH 1/3] Fix _get_string_slice taking non-strings --- pandas/core/indexes/base.py | 2 +- pandas/core/indexes/period.py | 2 +- pandas/core/indexes/timedeltas.py | 52 +++++++------------------------ 3 files changed, 14 insertions(+), 42 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 1489e100b5682..97042b187197e 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -4625,7 +4625,7 @@ def isin(self, values, level=None): self._validate_index_level(level) return algos.isin(self, values) - def _get_string_slice(self, key, use_lhs=True, use_rhs=True): + def _get_string_slice(self, key: str, use_lhs=True, use_rhs=True): # this is for partial string indexing, # overridden in DatetimeIndex, TimedeltaIndex and PeriodIndex raise NotImplementedError diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 6ab2e66e05d6e..7e56161e8828e 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -695,7 +695,7 @@ def _parsed_string_to_bounds(self, reso, parsed): raise KeyError(reso) return (t1.asfreq(self.freq, how="start"), t1.asfreq(self.freq, how="end")) - def _get_string_slice(self, key): + def _get_string_slice(self, key: str): if not self.is_monotonic: raise ValueError("Partial indexing only valid for ordered time series") diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index 1f3182bc83e1d..defbe83fc0e13 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -237,25 +237,18 @@ def get_value(self, series, key): know what you're doing """ - if _is_convertible_to_td(key): + if isinstance(key, str): + try: + key = Timedelta(key) + except ValueError: + raise KeyError(key) + + if isinstance(key, self._data._recognized_scalars) or key is NaT: key = Timedelta(key) return self.get_value_maybe_box(series, key) - try: - value = Index.get_value(self, series, key) - except KeyError: - try: - loc = self._get_string_slice(key) - return series[loc] - except (TypeError, ValueError, KeyError): - pass - - try: - return self.get_value_maybe_box(series, key) - except (TypeError, ValueError, KeyError): - raise KeyError(key) - else: - return com.maybe_box(self, value, series, key) + value = Index.get_value(self, series, key) + return com.maybe_box(self, value, series, key) def get_value_maybe_box(self, series, key: Timedelta): values = self._engine.get_value(com.values_from_object(series), key) @@ -288,19 +281,7 @@ def get_loc(self, key, method=None, tolerance=None): key = Timedelta(key) return Index.get_loc(self, key, method, tolerance) - try: - return Index.get_loc(self, key, method, tolerance) - except (KeyError, ValueError, TypeError): - try: - return self._get_string_slice(key) - except (TypeError, KeyError, ValueError): - pass - - try: - stamp = Timedelta(key) - return Index.get_loc(self, stamp, method, tolerance) - except (KeyError, ValueError): - raise KeyError(key) + return Index.get_loc(self, key, method, tolerance) def _maybe_cast_slice_bound(self, label, side, kind): """ @@ -330,18 +311,9 @@ def _maybe_cast_slice_bound(self, label, side, kind): return label - def _get_string_slice(self, key): - if is_integer(key) or is_float(key) or key is NaT: - self._invalid_indexer("slice", key) - loc = self._partial_td_slice(key) - return loc - - def _partial_td_slice(self, key): - + def _get_string_slice(self, key: str): + assert isinstance(key, str), type(key) # given a key, try to figure out a location for a partial slice - if not isinstance(key, str): - return key - raise NotImplementedError @Substitution(klass="TimedeltaIndex") From 0b4889fee90dddffedbb41ad6531b83a80adb40e Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Thu, 9 Jan 2020 17:45:58 -0800 Subject: [PATCH 2/3] make signatures match --- pandas/core/indexes/base.py | 2 +- pandas/core/indexes/period.py | 3 ++- pandas/core/indexes/timedeltas.py | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 06714b75111c9..9b237cae09450 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -4630,7 +4630,7 @@ def isin(self, values, level=None): self._validate_index_level(level) return algos.isin(self, values) - def _get_string_slice(self, key: str, use_lhs=True, use_rhs=True): + def _get_string_slice(self, key: str, use_lhs: bool = True, use_rhs: bool = True): # this is for partial string indexing, # overridden in DatetimeIndex, TimedeltaIndex and PeriodIndex raise NotImplementedError diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 7e56161e8828e..1de7fb0e55869 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -695,7 +695,8 @@ def _parsed_string_to_bounds(self, reso, parsed): raise KeyError(reso) return (t1.asfreq(self.freq, how="start"), t1.asfreq(self.freq, how="end")) - def _get_string_slice(self, key: str): + def _get_string_slice(self, key: str, use_lhs: bool = True, use_rhs: bool = True): + # TODO: Check for non-True use_lhs/use_rhs if not self.is_monotonic: raise ValueError("Partial indexing only valid for ordered time series") diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index defbe83fc0e13..903fe9aa24458 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -311,7 +311,8 @@ def _maybe_cast_slice_bound(self, label, side, kind): return label - def _get_string_slice(self, key: str): + def _get_string_slice(self, key: str, use_lhs: bool = True, use_rhs: bool = True): + # TODO: Check for non-True use_lhs/use_rhs assert isinstance(key, str), type(key) # given a key, try to figure out a location for a partial slice raise NotImplementedError From c39a72b2c61c66d66403ed1986d3cbcb775c0ebf Mon Sep 17 00:00:00 2001 From: Brock Mendel Date: Thu, 9 Jan 2020 18:37:50 -0800 Subject: [PATCH 3/3] mypy fixup --- pandas/core/indexes/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index 9b237cae09450..e6747c90168cb 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -96,6 +96,7 @@ duplicated="np.ndarray", ) _index_shared_docs = dict() +str_t = str def _make_comparison_op(op, cls): @@ -4630,7 +4631,7 @@ def isin(self, values, level=None): self._validate_index_level(level) return algos.isin(self, values) - def _get_string_slice(self, key: str, use_lhs: bool = True, use_rhs: bool = True): + def _get_string_slice(self, key: str_t, use_lhs: bool = True, use_rhs: bool = True): # this is for partial string indexing, # overridden in DatetimeIndex, TimedeltaIndex and PeriodIndex raise NotImplementedError