Exemplo n.º 1
0
 def _get_string_slice(self, key: str):
     parsed, reso = parse_time_string(key, self.freq)
     reso = Resolution.from_attrname(reso)
     try:
         return self._partial_date_slice(reso, parsed)
     except KeyError as err:
         raise KeyError(key) from err
Exemplo n.º 2
0
 def _get_string_slice(self, key: str, use_lhs: bool = True, use_rhs: bool = True):
     # TODO: Check for non-True use_lhs/use_rhs
     parsed, reso = parse_time_string(key, self.freq)
     reso = Resolution.from_attrname(reso)
     try:
         return self._partial_date_slice(reso, parsed, use_lhs, use_rhs)
     except KeyError as err:
         raise KeyError(key) from err
Exemplo n.º 3
0
 def _get_string_slice(self,
                       key: str,
                       use_lhs: bool = True,
                       use_rhs: bool = True):
     freq = getattr(self, "freqstr", getattr(self, "inferred_freq", None))
     parsed, reso = parsing.parse_time_string(key, freq)
     reso = Resolution.from_attrname(reso)
     loc = self._partial_date_slice(reso,
                                    parsed,
                                    use_lhs=use_lhs,
                                    use_rhs=use_rhs)
     return loc
Exemplo n.º 4
0
    def _validate_partial_date_slice(self, reso: str):
        if (self.is_monotonic and reso in ["day", "hour", "minute", "second"]
                and self._resolution_obj >= Resolution.from_attrname(reso)):
            # These resolution/monotonicity validations came from GH3931,
            # GH3452 and GH2369.

            # See also GH14826
            raise KeyError

        if reso == "microsecond":
            # _partial_date_slice doesn't allow microsecond resolution, but
            # _parsed_string_to_bounds allows it.
            raise KeyError
Exemplo n.º 5
0
    def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
        """
        If label is a string, cast it to datetime according to resolution.

        Parameters
        ----------
        label : object
        side : {'left', 'right'}
        kind : {'loc', 'getitem'} or None

        Returns
        -------
        label : object

        Notes
        -----
        Value of `side` parameter should be validated in caller.
        """
        assert kind in ["loc", "getitem", None, 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)
            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)
            # because label may be passed to searchsorted
            # the bounds need swapped if index is reverse sorted and has a
            # length > 1 (is_monotonic_decreasing gives True for empty
            # and length 1 index)
            if self._is_strictly_monotonic_decreasing and len(self) > 1:
                return upper if side == "left" else lower
            return lower if side == "left" else upper
        elif isinstance(label, (self._data._recognized_scalars, date)):
            self._deprecate_mismatched_indexing(label)
        else:
            raise self._invalid_indexer("slice", label)

        return self._maybe_cast_for_get_loc(label)
Exemplo n.º 6
0
    def _maybe_cast_slice_bound(self, label, side: str, kind):
        """
        If label is a string, cast it to datetime according to resolution.

        Parameters
        ----------
        label : object
        side : {'left', 'right'}
        kind : {'loc', 'getitem'} or None

        Returns
        -------
        label : object

        Notes
        -----
        Value of `side` parameter should be validated in caller.
        """
        assert kind in ["loc", "getitem", None]

        if is_float(label) or isinstance(label, time) or is_integer(label):
            self._invalid_indexer("slice", label)

        if isinstance(label, str):
            freq = getattr(self, "freqstr", getattr(self, "inferred_freq",
                                                    None))
            parsed, reso = parsing.parse_time_string(label, freq)
            reso = Resolution.from_attrname(reso)
            lower, upper = self._parsed_string_to_bounds(reso, parsed)
            # lower, upper form the half-open interval:
            #   [parsed, parsed + 1 freq)
            # because label may be passed to searchsorted
            # the bounds need swapped if index is reverse sorted and has a
            # length > 1 (is_monotonic_decreasing gives True for empty
            # and length 1 index)
            if self._is_strictly_monotonic_decreasing and len(self) > 1:
                return upper if side == "left" else lower
            return lower if side == "left" else upper
        else:
            return label
Exemplo n.º 7
0
    def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default):
        """
        If label is a string or a datetime, cast it to Period.ordinal according
        to resolution.

        Parameters
        ----------
        label : object
        side : {'left', 'right'}
        kind : {'loc', 'getitem'}, or None

        Returns
        -------
        bound : Period or object

        Notes
        -----
        Value of `side` parameter should be validated in caller.

        """
        assert kind in ["loc", "getitem", None, lib.no_default]
        self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound")

        if isinstance(label, datetime):
            return Period(label, freq=self.freq)
        elif isinstance(label, str):
            try:
                parsed, reso_str = parse_time_string(label, self.freq)
            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):
            raise self._invalid_indexer("slice", label)

        return label
Exemplo n.º 8
0
    def _maybe_cast_slice_bound(self, label, side: str, kind: str):
        """
        If label is a string or a datetime, cast it to Period.ordinal according
        to resolution.

        Parameters
        ----------
        label : object
        side : {'left', 'right'}
        kind : {'loc', 'getitem'}

        Returns
        -------
        bound : Period or object

        Notes
        -----
        Value of `side` parameter should be validated in caller.

        """
        assert kind in ["loc", "getitem"]

        if isinstance(label, datetime):
            return Period(label, freq=self.freq)
        elif isinstance(label, str):
            try:
                parsed, reso = parse_time_string(label, self.freq)
                reso = Resolution.from_attrname(reso)
                bounds = self._parsed_string_to_bounds(reso, parsed)
                return bounds[0 if side == "left" else 1]
            except ValueError as err:
                # string cannot be parsed as datetime-like
                # TODO: we need tests for this case
                raise KeyError(label) from err
        elif is_integer(label) or is_float(label):
            self._invalid_indexer("slice", label)

        return label
Exemplo n.º 9
0
 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
Exemplo n.º 10
0
    def get_loc(self, key, method=None, tolerance=None):
        """
        Get integer location for requested label.

        Parameters
        ----------
        key : Period, NaT, str, or datetime
            String or datetime key must be parsable as Period.

        Returns
        -------
        loc : int or ndarray[int64]

        Raises
        ------
        KeyError
            Key is not present in the index.
        TypeError
            If key is listlike or otherwise not hashable.
        """
        orig_key = key

        if not is_scalar(key):
            raise InvalidIndexError(key)

        if isinstance(key, str):

            try:
                loc = self._get_string_slice(key)
                return loc
            except (TypeError, ValueError):
                pass

            try:
                asdt, reso = parse_time_string(key, self.freq)
            except (ValueError, DateParseError) as err:
                # A string with invalid format
                raise KeyError(f"Cannot interpret '{key}' as period") from err

            reso = Resolution.from_attrname(reso)
            grp = reso.freq_group
            freqn = self.dtype.freq_group

            # _get_string_slice will handle cases where grp < freqn
            assert grp >= freqn

            # BusinessDay is a bit strange. It has a *lower* code, but we never parse
            # a string as "BusinessDay" resolution, just Day.
            if grp == freqn or (
                reso == Resolution.RESO_DAY and self.dtype.freq.name == "B"
            ):
                key = Period(asdt, freq=self.freq)
                loc = self.get_loc(key, method=method, tolerance=tolerance)
                return loc
            elif method is None:
                raise KeyError(key)
            else:
                key = asdt

        elif is_integer(key):
            # Period constructor will cast to string, which we dont want
            raise KeyError(key)

        try:
            key = Period(key, freq=self.freq)
        except ValueError as err:
            # we cannot construct the Period
            raise KeyError(orig_key) from err

        try:
            return Index.get_loc(self, key, method, tolerance)
        except KeyError as err:
            raise KeyError(orig_key) from err
Exemplo n.º 11
0
def test_get_freq_roundtrip2(freq):
    obj = Resolution.get_reso_from_freq(freq)
    result = _attrname_to_abbrevs[obj.attrname]
    assert freq == result
Exemplo n.º 12
0
def test_get_attrname_from_abbrev(freqstr, expected):
    assert Resolution.get_reso_from_freq(freqstr).attrname == expected
Exemplo n.º 13
0
 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)
Exemplo n.º 14
0
def test_get_freq_unsupported_(freq):
    # Lowest-frequency resolution is for Day
    with pytest.raises(KeyError, match=freq.lower()):
        Resolution.get_reso_from_freq(freq)
Exemplo n.º 15
0
    def get_loc(self, key, method=None, tolerance=None):
        """
        Get integer location for requested label.

        Parameters
        ----------
        key : Period, NaT, str, or datetime
            String or datetime key must be parsable as Period.

        Returns
        -------
        loc : int or ndarray[int64]

        Raises
        ------
        KeyError
            Key is not present in the index.
        TypeError
            If key is listlike or otherwise not hashable.
        """
        orig_key = key

        if not is_scalar(key):
            raise InvalidIndexError(key)

        if is_valid_na_for_dtype(key, self.dtype):
            key = NaT

        elif isinstance(key, str):

            try:
                loc = self._get_string_slice(key)
                return loc
            except (TypeError, ValueError):
                pass

            try:
                asdt, reso_str = parse_time_string(key, self.freq)
            except (ValueError, DateParseError) as err:
                # A string with invalid format
                raise KeyError(f"Cannot interpret '{key}' as period") from err

            reso = Resolution.from_attrname(reso_str)
            grp = reso.freq_group.value
            freqn = self.dtype.freq_group_code

            # _get_string_slice will handle cases where grp < freqn
            assert grp >= freqn

            # BusinessDay is a bit strange. It has a *lower* code, but we never parse
            # a string as "BusinessDay" resolution, just Day.
            if grp == freqn or (reso == Resolution.RESO_DAY
                                and self.dtype.freq.name == "B"):
                key = Period(asdt, freq=self.freq)
                loc = self.get_loc(key, method=method, tolerance=tolerance)
                return loc
            elif method is None:
                raise KeyError(key)
            else:
                key = asdt

        elif isinstance(key, Period):
            sfreq = self.freq
            kfreq = key.freq
            if not (sfreq.n == kfreq.n
                    and sfreq._period_dtype_code == kfreq._period_dtype_code):
                # GH#42247 For the subset of DateOffsets that can be Period freqs,
                #  checking these two attributes is sufficient to check equality,
                #  and much more performant than `self.freq == key.freq`
                raise KeyError(key)
        elif isinstance(key, datetime):
            try:
                key = Period(key, freq=self.freq)
            except ValueError as err:
                # we cannot construct the Period
                raise KeyError(orig_key) from err
        else:
            # in particular integer, which Period constructor would cast to string
            raise KeyError(key)

        try:
            key = Period(key, freq=self.freq)
        except ValueError as err:
            # we cannot construct the Period
            raise KeyError(orig_key) from err

        try:
            return Index.get_loc(self, key, method, tolerance)
        except KeyError as err:
            raise KeyError(orig_key) from err