diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index ea0c93e75f496..cad1fb431dd84 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -3,6 +3,10 @@ """ from __future__ import annotations +from abc import ( + ABC, + abstractmethod, +) from datetime import datetime from typing import ( TYPE_CHECKING, @@ -61,10 +65,7 @@ Index, _index_shared_docs, ) -from pandas.core.indexes.extension import ( - NDArrayBackedExtensionIndex, - inherit_names, -) +from pandas.core.indexes.extension import NDArrayBackedExtensionIndex from pandas.core.indexes.range import RangeIndex from pandas.core.tools.timedeltas import to_timedelta @@ -77,21 +78,17 @@ _TDT = TypeVar("_TDT", bound="DatetimeTimedeltaMixin") -@inherit_names( - ["inferred_freq", "_resolution_obj", "resolution"], - DatetimeLikeArrayMixin, - cache=True, -) -@inherit_names(["mean", "freqstr"], DatetimeLikeArrayMixin) -class DatetimeIndexOpsMixin(NDArrayBackedExtensionIndex): +class DatetimeIndexOpsMixin(NDArrayBackedExtensionIndex, ABC): """ Common ops mixin to support a unified interface datetimelike Index. """ _can_hold_strings = False _data: DatetimeArray | TimedeltaArray | PeriodArray - freqstr: str | None - _resolution_obj: Resolution + + @doc(DatetimeLikeArrayMixin.mean) + def mean(self, *, skipna: bool = True, axis: int | None = 0): + return self._data.mean(skipna=skipna, axis=axis) @property def freq(self) -> BaseOffset | None: @@ -106,6 +103,21 @@ def freq(self, value) -> None: def asi8(self) -> npt.NDArray[np.int64]: return self._data.asi8 + @property + @doc(DatetimeLikeArrayMixin.freqstr) + def freqstr(self) -> str | None: + return self._data.freqstr + + @cache_readonly + @abstractmethod + def _resolution_obj(self) -> Resolution: + ... + + @cache_readonly + @doc(DatetimeLikeArrayMixin.resolution) + def resolution(self) -> str: + return self._data.resolution + # ------------------------------------------------------------------------ @cache_readonly @@ -390,7 +402,7 @@ def _maybe_cast_listlike_indexer(self, keyarr): return Index(res, dtype=res.dtype) -class DatetimeTimedeltaMixin(DatetimeIndexOpsMixin): +class DatetimeTimedeltaMixin(DatetimeIndexOpsMixin, ABC): """ Mixin class for methods shared by DatetimeIndex and TimedeltaIndex, but not PeriodIndex @@ -461,6 +473,11 @@ def shift(self: _TDT, periods: int = 1, freq=None) -> _TDT: ) return type(self)._simple_new(result, name=self.name) + @cache_readonly + @doc(DatetimeLikeArrayMixin.inferred_freq) + def inferred_freq(self) -> str | None: + return self._data.inferred_freq + # -------------------------------------------------------------------- # Set Operation Methods diff --git a/pandas/core/indexes/datetimes.py b/pandas/core/indexes/datetimes.py index b2305d0fe1cbf..bba4bae511ec9 100644 --- a/pandas/core/indexes/datetimes.py +++ b/pandas/core/indexes/datetimes.py @@ -110,7 +110,7 @@ def _new_DatetimeIndex(cls, d): DatetimeArray, wrap=True, ) -@inherit_names(["is_normalized", "_resolution_obj"], DatetimeArray, cache=True) +@inherit_names(["is_normalized"], DatetimeArray, cache=True) @inherit_names( [ "tz", @@ -249,7 +249,6 @@ def _engine_type(self) -> type[libindex.DatetimeEngine]: return libindex.DatetimeEngine _data: DatetimeArray - inferred_freq: str | None tz: dt.tzinfo | None # -------------------------------------------------------------------- @@ -294,6 +293,10 @@ def isocalendar(self) -> DataFrame: df = self._data.isocalendar() return df.set_index(self) + @cache_readonly + def _resolution_obj(self) -> Resolution: + return self._data._resolution_obj + # -------------------------------------------------------------------- # Constructors diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index bcd073051cb27..5c849b47745eb 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -156,8 +156,7 @@ def _engine_type(self) -> type[libindex.PeriodEngine]: return libindex.PeriodEngine @cache_readonly - # Signature of "_resolution_obj" incompatible with supertype "DatetimeIndexOpsMixin" - def _resolution_obj(self) -> Resolution: # type: ignore[override] + def _resolution_obj(self) -> Resolution: # for compat with DatetimeIndex return self.dtype._resolution_obj diff --git a/pandas/core/indexes/timedeltas.py b/pandas/core/indexes/timedeltas.py index 54a9152670cab..e7ea54df62411 100644 --- a/pandas/core/indexes/timedeltas.py +++ b/pandas/core/indexes/timedeltas.py @@ -6,6 +6,7 @@ lib, ) from pandas._libs.tslibs import ( + Resolution, Timedelta, to_offset, ) @@ -112,6 +113,12 @@ def _engine_type(self) -> type[libindex.TimedeltaEngine]: # Use base class method instead of DatetimeTimedeltaMixin._get_string_slice _get_string_slice = Index._get_string_slice + # error: Signature of "_resolution_obj" incompatible with supertype + # "DatetimeIndexOpsMixin" + @property + def _resolution_obj(self) -> Resolution | None: # type: ignore[override] + return self._data._resolution_obj + # ------------------------------------------------------------------- # Constructors