diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index 70acb42712201..415bdf74db80a 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -23,7 +23,7 @@ cdef class PeriodDtypeBase: return self._dtype_code == other._dtype_code @property - def freq_group(self) -> int: + def freq_group_code(self) -> int: # See also: libperiod.get_freq_group return (self._dtype_code // 1000) * 1000 @@ -37,7 +37,6 @@ cdef class PeriodDtypeBase: from .offsets import to_offset freqstr = _reverse_period_code_map.get(self._dtype_code) - # equiv: freqstr = libfrequencies.get_freq_str(self._dtype_code) return to_offset(freqstr) @@ -134,7 +133,7 @@ cdef dict attrname_to_abbrevs = _attrname_to_abbrevs cdef dict _abbrev_to_attrnames = {v: k for k, v in attrname_to_abbrevs.items()} -class FreqGroup: +class FreqGroup(Enum): # Mirrors c_FreqGroup in the .pxd file FR_ANN = 1000 FR_QTR = 2000 @@ -151,9 +150,10 @@ class FreqGroup: FR_UND = -10000 # undefined @staticmethod - def get_freq_group(code: int) -> int: - # See also: PeriodDtypeBase.freq_group - return (code // 1000) * 1000 + def get_freq_group(code: int) -> "FreqGroup": + # See also: PeriodDtypeBase.freq_group_code + code = (code // 1000) * 1000 + return FreqGroup(code) class Resolution(Enum): @@ -178,8 +178,7 @@ class Resolution(Enum): return self.value >= other.value @property - def freq_group(self): - # TODO: annotate as returning FreqGroup once that is an enum + def freq_group(self) -> FreqGroup: if self == Resolution.RESO_NS: return FreqGroup.FR_NS elif self == Resolution.RESO_US: diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index edcc1f29a5ec2..96a075dd21bf9 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -1068,11 +1068,11 @@ def _range_from_fields( if quarter is not None: if freq is None: freq = to_offset("Q") - base = FreqGroup.FR_QTR + base = FreqGroup.FR_QTR.value else: freq = to_offset(freq) base = libperiod.freq_to_dtype_code(freq) - if base != FreqGroup.FR_QTR: + if base != FreqGroup.FR_QTR.value: raise AssertionError("base must equal FR_QTR") freqstr = freq.freqstr diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index 932868451058f..8609c61065327 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -571,7 +571,7 @@ def _parsed_string_to_bounds(self, reso: Resolution, parsed: datetime): raise KeyError grp = reso.freq_group - per = Period(parsed, freq=grp) + per = Period(parsed, freq=grp.value) start, end = per.start_time, per.end_time # GH 24076 diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 7762198246603..8fe92ed757401 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -506,8 +506,8 @@ def get_loc(self, key, method=None, tolerance=None): raise KeyError(f"Cannot interpret '{key}' as period") from err reso = Resolution.from_attrname(reso) - grp = reso.freq_group - freqn = self.dtype.freq_group + grp = reso.freq_group.value + freqn = self.dtype.freq_group_code # _get_string_slice will handle cases where grp < freqn assert grp >= freqn @@ -580,15 +580,15 @@ def _maybe_cast_slice_bound(self, label, side: str, kind: str): def _parsed_string_to_bounds(self, reso: Resolution, parsed: datetime): grp = reso.freq_group - iv = Period(parsed, freq=grp) + iv = Period(parsed, freq=grp.value) return (iv.asfreq(self.freq, how="start"), iv.asfreq(self.freq, how="end")) def _validate_partial_date_slice(self, reso: Resolution): assert isinstance(reso, Resolution), (type(reso), reso) grp = reso.freq_group - freqn = self.dtype.freq_group + freqn = self.dtype.freq_group_code - if not grp < freqn: + if not grp.value < freqn: # TODO: we used to also check for # reso in ["day", "hour", "minute", "second"] # why is that check not needed? diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index 978010efd7ee5..3d2d69162c70a 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -510,28 +510,28 @@ def _daily_finder(vmin, vmax, freq: BaseOffset): periodsperday = -1 - if dtype_code >= FreqGroup.FR_HR: - if dtype_code == FreqGroup.FR_NS: + if dtype_code >= FreqGroup.FR_HR.value: + if dtype_code == FreqGroup.FR_NS.value: periodsperday = 24 * 60 * 60 * 1000000000 - elif dtype_code == FreqGroup.FR_US: + elif dtype_code == FreqGroup.FR_US.value: periodsperday = 24 * 60 * 60 * 1000000 - elif dtype_code == FreqGroup.FR_MS: + elif dtype_code == FreqGroup.FR_MS.value: periodsperday = 24 * 60 * 60 * 1000 - elif dtype_code == FreqGroup.FR_SEC: + elif dtype_code == FreqGroup.FR_SEC.value: periodsperday = 24 * 60 * 60 - elif dtype_code == FreqGroup.FR_MIN: + elif dtype_code == FreqGroup.FR_MIN.value: periodsperday = 24 * 60 - elif dtype_code == FreqGroup.FR_HR: + elif dtype_code == FreqGroup.FR_HR.value: periodsperday = 24 else: # pragma: no cover raise ValueError(f"unexpected frequency: {dtype_code}") periodsperyear = 365 * periodsperday periodspermonth = 28 * periodsperday - elif dtype_code == FreqGroup.FR_BUS: + elif dtype_code == FreqGroup.FR_BUS.value: periodsperyear = 261 periodspermonth = 19 - elif dtype_code == FreqGroup.FR_DAY: + elif dtype_code == FreqGroup.FR_DAY.value: periodsperyear = 365 periodspermonth = 28 elif FreqGroup.get_freq_group(dtype_code) == FreqGroup.FR_WK: @@ -661,7 +661,7 @@ def _second_finder(label_interval): elif span <= periodsperyear // 4: month_start = period_break(dates_, "month") info_maj[month_start] = True - if dtype_code < FreqGroup.FR_HR: + if dtype_code < FreqGroup.FR_HR.value: info["min"] = True else: day_start = period_break(dates_, "day") @@ -872,14 +872,15 @@ def _annual_finder(vmin, vmax, freq): def get_finder(freq: BaseOffset): dtype_code = freq._period_dtype_code fgroup = (dtype_code // 1000) * 1000 + fgroup = FreqGroup(fgroup) if fgroup == FreqGroup.FR_ANN: return _annual_finder elif fgroup == FreqGroup.FR_QTR: return _quarterly_finder - elif dtype_code == FreqGroup.FR_MTH: + elif dtype_code == FreqGroup.FR_MTH.value: return _monthly_finder - elif (dtype_code >= FreqGroup.FR_BUS) or fgroup == FreqGroup.FR_WK: + elif (dtype_code >= FreqGroup.FR_BUS.value) or fgroup == FreqGroup.FR_WK: return _daily_finder else: # pragma: no cover raise NotImplementedError(f"Unsupported frequency: {dtype_code}") diff --git a/pandas/plotting/_matplotlib/timeseries.py b/pandas/plotting/_matplotlib/timeseries.py index ae4fff7b495d0..e04b03e5b0420 100644 --- a/pandas/plotting/_matplotlib/timeseries.py +++ b/pandas/plotting/_matplotlib/timeseries.py @@ -215,7 +215,7 @@ def use_dynamic_x(ax: "Axes", data: FrameOrSeriesUnion) -> bool: if isinstance(data.index, ABCDatetimeIndex): base = to_offset(freq)._period_dtype_code x = data.index - if base <= FreqGroup.FR_DAY: + if base <= FreqGroup.FR_DAY.value: return x[:1].is_normalized return Period(x[0], freq).to_timestamp().tz_localize(x.tz) == x[0] return True