Skip to content

REF: share _get_string_slice #42149

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
merged 3 commits into from
Jun 25, 2021
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
3 changes: 1 addition & 2 deletions pandas/_libs/tslibs/parsing.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -470,8 +470,7 @@ cdef inline object _parse_dateabbr_string(object date_string, datetime default,
except ValueError:
pass

if date_len == 6 and (freq == 'M' or
getattr(freq, 'rule_code', None) == 'M'):
if date_len == 6 and freq == 'M':
year = int(date_string[:4])
month = int(date_string[4:6])
try:
Expand Down
16 changes: 15 additions & 1 deletion pandas/core/indexes/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
NaTType,
Resolution,
Tick,
parsing,
)
from pandas._typing import (
Callable,
Expand Down Expand Up @@ -401,9 +402,22 @@ def _summary(self, name=None) -> str:
def _validate_partial_date_slice(self, reso: Resolution):
raise NotImplementedError

def _parsed_string_to_bounds(self, reso: Resolution, parsed: datetime):
def _parsed_string_to_bounds(self, reso: Resolution, parsed):
raise NotImplementedError

def _parse_with_reso(self, label: str):
# overridden by TimedeltaIndex
parsed, reso_str = parsing.parse_time_string(label, self.freq)
reso = Resolution.from_attrname(reso_str)
return parsed, reso

def _get_string_slice(self, key: str):
parsed, reso = self._parse_with_reso(key)
try:
return self._partial_date_slice(reso, parsed)
except KeyError as err:
raise KeyError(key) from err

@final
def _partial_date_slice(
self,
Expand Down
10 changes: 1 addition & 9 deletions pandas/core/indexes/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -732,13 +732,11 @@ def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound")

if isinstance(label, str):
freq = getattr(self, "freqstr", getattr(self, "inferred_freq", None))
try:
parsed, reso_str = parsing.parse_time_string(label, freq)
parsed, reso = self._parse_with_reso(label)
except parsing.DateParseError as err:
raise self._invalid_indexer("slice", label) from err

reso = Resolution.from_attrname(reso_str)
lower, upper = self._parsed_string_to_bounds(reso, parsed)
# lower, upper form the half-open interval:
# [parsed, parsed + 1 freq)
Expand All @@ -756,12 +754,6 @@ def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):

return self._maybe_cast_for_get_loc(label)

def _get_string_slice(self, key: str):
freq = getattr(self, "freqstr", getattr(self, "inferred_freq", None))
parsed, reso_str = parsing.parse_time_string(key, freq)
reso = Resolution.from_attrname(reso_str)
return self._partial_date_slice(reso, parsed)

def slice_indexer(self, start=None, end=None, step=None, kind=None):
"""
Return indexer for specified label slice.
Expand Down
11 changes: 1 addition & 10 deletions pandas/core/indexes/period.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,12 +487,11 @@ def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
return Period(label, freq=self.freq)
elif isinstance(label, str):
try:
parsed, reso_str = parse_time_string(label, self.freq)
parsed, reso = self._parse_with_reso(label)
except ValueError as err:
# string cannot be parsed as datetime-like
raise self._invalid_indexer("slice", label) from err

reso = Resolution.from_attrname(reso_str)
lower, upper = self._parsed_string_to_bounds(reso, parsed)
return lower if side == "left" else upper
elif not isinstance(label, self._data._recognized_scalars):
Expand All @@ -516,14 +515,6 @@ def _validate_partial_date_slice(self, reso: Resolution):
# why is that check not needed?
raise ValueError

def _get_string_slice(self, key: str):
parsed, reso_str = parse_time_string(key, self.freq)
reso = Resolution.from_attrname(reso_str)
try:
return self._partial_date_slice(reso, parsed)
except KeyError as err:
raise KeyError(key) from err


def period_range(
start=None, end=None, periods: int | None = None, freq=None, name=None
Expand Down
20 changes: 16 additions & 4 deletions pandas/core/indexes/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ class TimedeltaIndex(DatetimeTimedeltaMixin):

_data: TimedeltaArray

# Use base class method instead of DatetimeTimedeltaMixin._get_string_slice
_get_string_slice = Index._get_string_slice

# -------------------------------------------------------------------
# Constructors

Expand Down Expand Up @@ -197,20 +200,29 @@ def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):

if isinstance(label, str):
try:
parsed = Timedelta(label)
parsed, reso = self._parse_with_reso(label)
except ValueError as err:
# e.g. 'unit abbreviation w/o a number'
raise self._invalid_indexer("slice", label) from err

# The next two lines are analogous to DTI/PI._parsed_str_to_bounds
lower = parsed.round(parsed.resolution_string)
upper = lower + to_offset(parsed.resolution_string) - Timedelta(1, "ns")
lower, upper = self._parsed_string_to_bounds(reso, parsed)
return lower if side == "left" else upper
elif not isinstance(label, self._data._recognized_scalars):
raise self._invalid_indexer("slice", label)

return label

def _parse_with_reso(self, label: str):
# the "with_reso" is a no-op for TimedeltaIndex
parsed = Timedelta(label)
return parsed, None

def _parsed_string_to_bounds(self, reso, parsed: Timedelta):
# reso is unused, included to match signature of DTI/PI
lbound = parsed.round(parsed.resolution_string)
rbound = lbound + to_offset(parsed.resolution_string) - Timedelta(1, "ns")
return lbound, rbound

# -------------------------------------------------------------------

@property
Expand Down