From 8a99cf4f4af9b04f90d52a494a918fbb9c85f211 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 13 Jul 2025 08:23:15 +0200 Subject: [PATCH 1/2] refactor: only drop TimestampSeries https://github.com/pandas-dev/pandas-stubs/pull/1273#pullrequestreview-3013726071 --- docs/philosophy.md | 16 +- pandas-stubs/_libs/interval.pyi | 11 +- pandas-stubs/_libs/tslibs/timedeltas.pyi | 7 +- pandas-stubs/_libs/tslibs/timestamps.pyi | 19 +- pandas-stubs/core/indexes/accessors.pyi | 66 +++++- pandas-stubs/core/indexes/datetimes.pyi | 8 +- pandas-stubs/core/indexes/interval.pyi | 3 +- pandas-stubs/core/reshape/tile.pyi | 13 +- pandas-stubs/core/series.pyi | 252 ++++++++++++++++------- pandas-stubs/core/tools/datetimes.pyi | 7 +- pyproject.toml | 2 +- tests/test_frame.py | 14 +- tests/test_pandas.py | 20 +- tests/test_scalars.py | 24 ++- tests/test_series.py | 134 ++++++------ tests/test_timefuncs.py | 183 ++++++++++------ 16 files changed, 494 insertions(+), 285 deletions(-) diff --git a/docs/philosophy.md b/docs/philosophy.md index 853c516e1..c19f1e1b9 100644 --- a/docs/philosophy.md +++ b/docs/philosophy.md @@ -36,6 +36,8 @@ This also allows type checking for operations on series that contain date/time d the following example that creates two series of datetimes with corresponding arithmetic. ```python +import pandas as pd + s1 = pd.Series(pd.to_datetime(["2022-05-01", "2022-06-01"])) reveal_type(s1) s2 = pd.Series(pd.to_datetime(["2022-05-15", "2022-06-15"])) @@ -46,19 +48,21 @@ ssum = s1 + s2 reveal_type(ssum) ``` -The above code (without the `reveal_type()` statements) will raise an `Exception` on the computation of `ssum` because it is +The above code (without the `reveal_type()` statements) will get a `Never` +on the computation of `ssum` because it is inappropriate to add two series containing `Timestamp` values. The types will be revealed as follows: ```text -ttest.py:4: note: Revealed type is "pandas.core.series.TimestampSeries" -ttest.py:6: note: Revealed type is "pandas.core.series.TimestampSeries" +ttest.py:4: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp]" +ttest.py:6: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp]" ttest.py:8: note: Revealed type is "pandas.core.series.TimedeltaSeries" -ttest.py:10: note: Revealed type is "builtins.Exception" +ttest.py:9: error: Need type annotation for "ssum" [var-annotated] +ttest.py:10: note: Revealed type is "Never" ``` -The type `TimestampSeries` is the result of creating a series from `pd.to_datetime()`, while -the type `TimedeltaSeries` is the result of subtracting two `TimestampSeries` as well as +The type `Series[Timestamp]` is the result of creating a series from `pd.to_datetime()`, while +the type `TimedeltaSeries` is the result of subtracting two `Series[Timestamp]` as well as the result of `pd.to_timedelta()`. ### Interval is Generic diff --git a/pandas-stubs/_libs/interval.pyi b/pandas-stubs/_libs/interval.pyi index fdb0a398c..613eb06ba 100644 --- a/pandas-stubs/_libs/interval.pyi +++ b/pandas-stubs/_libs/interval.pyi @@ -13,10 +13,7 @@ from pandas import ( Timedelta, Timestamp, ) -from pandas.core.series import ( - TimedeltaSeries, - TimestampSeries, -) +from pandas.core.series import TimedeltaSeries from pandas._typing import ( IntervalClosedType, @@ -174,7 +171,7 @@ class Interval(IntervalMixin, Generic[_OrderableT]): @overload def __gt__( self, - other: Series[int] | Series[float] | TimestampSeries | TimedeltaSeries, + other: Series[int] | Series[float] | Series[Timestamp] | TimedeltaSeries, ) -> Series[bool]: ... @overload def __lt__(self, other: Interval[_OrderableT]) -> bool: ... @@ -183,7 +180,7 @@ class Interval(IntervalMixin, Generic[_OrderableT]): @overload def __lt__( self, - other: Series[int] | Series[float] | TimestampSeries | TimedeltaSeries, + other: Series[int] | Series[float] | Series[Timestamp] | TimedeltaSeries, ) -> Series[bool]: ... @overload def __ge__(self, other: Interval[_OrderableT]) -> bool: ... @@ -192,7 +189,7 @@ class Interval(IntervalMixin, Generic[_OrderableT]): @overload def __ge__( self, - other: Series[int] | Series[float] | TimestampSeries | TimedeltaSeries, + other: Series[int] | Series[float] | Series[Timestamp] | TimedeltaSeries, ) -> Series[bool]: ... @overload def __le__(self, other: Interval[_OrderableT]) -> bool: ... diff --git a/pandas-stubs/_libs/tslibs/timedeltas.pyi b/pandas-stubs/_libs/tslibs/timedeltas.pyi index 01a17e1df..798b87a9d 100644 --- a/pandas-stubs/_libs/tslibs/timedeltas.pyi +++ b/pandas-stubs/_libs/tslibs/timedeltas.pyi @@ -17,10 +17,7 @@ from pandas import ( Series, TimedeltaIndex, ) -from pandas.core.series import ( - TimedeltaSeries, - TimestampSeries, -) +from pandas.core.series import TimedeltaSeries from typing_extensions import ( Self, TypeAlias, @@ -167,7 +164,7 @@ class Timedelta(timedelta): other: TimedeltaSeries, ) -> TimedeltaSeries: ... @overload - def __add__(self, other: TimestampSeries) -> TimestampSeries: ... + def __add__(self, other: Series[Timestamp]) -> Series[Timestamp]: ... @overload def __radd__(self, other: np.datetime64) -> Timestamp: ... @overload diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index b986c186a..3b991d7ef 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -25,7 +25,6 @@ from pandas import ( from pandas.core.series import ( Series, TimedeltaSeries, - TimestampSeries, ) from typing_extensions import ( Never, @@ -172,7 +171,7 @@ class Timestamp(datetime, SupportsIndex): self, other: DatetimeIndex | npt.NDArray[np.datetime64] ) -> np_ndarray_bool: ... @overload - def __le__(self, other: TimestampSeries) -> Series[bool]: ... + def __le__(self, other: Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] def __lt__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload @@ -180,7 +179,7 @@ class Timestamp(datetime, SupportsIndex): self, other: DatetimeIndex | npt.NDArray[np.datetime64] ) -> np_ndarray_bool: ... @overload - def __lt__(self, other: TimestampSeries) -> Series[bool]: ... + def __lt__(self, other: Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] def __ge__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload @@ -188,7 +187,7 @@ class Timestamp(datetime, SupportsIndex): self, other: DatetimeIndex | npt.NDArray[np.datetime64] ) -> np_ndarray_bool: ... @overload - def __ge__(self, other: TimestampSeries) -> Series[bool]: ... + def __ge__(self, other: Series[Timestamp]) -> Series[bool]: ... @overload # type: ignore[override] def __gt__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[misc] @overload @@ -196,7 +195,7 @@ class Timestamp(datetime, SupportsIndex): self, other: DatetimeIndex | npt.NDArray[np.datetime64] ) -> np_ndarray_bool: ... @overload - def __gt__(self, other: TimestampSeries) -> Series[bool]: ... + def __gt__(self, other: Series[Timestamp]) -> Series[bool]: ... # error: Signature of "__add__" incompatible with supertype "date"/"datetime" @overload # type: ignore[override] def __add__( @@ -205,7 +204,7 @@ class Timestamp(datetime, SupportsIndex): @overload def __add__(self, other: timedelta | np.timedelta64 | Tick) -> Self: ... @overload - def __add__(self, other: TimedeltaSeries) -> TimestampSeries: ... + def __add__(self, other: TimedeltaSeries) -> Series[Timestamp]: ... @overload def __add__(self, other: TimedeltaIndex) -> DatetimeIndex: ... @overload @@ -224,9 +223,9 @@ class Timestamp(datetime, SupportsIndex): @overload def __sub__(self, other: TimedeltaIndex) -> DatetimeIndex: ... @overload - def __sub__(self, other: TimedeltaSeries) -> TimestampSeries: ... + def __sub__(self, other: TimedeltaSeries) -> Series[Timestamp]: ... @overload - def __sub__(self, other: TimestampSeries) -> TimedeltaSeries: ... + def __sub__(self, other: Series[Timestamp]) -> TimedeltaSeries: ... @overload def __sub__( self, other: npt.NDArray[np.timedelta64] @@ -234,7 +233,7 @@ class Timestamp(datetime, SupportsIndex): @overload def __eq__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload - def __eq__(self, other: TimestampSeries) -> Series[bool]: ... # type: ignore[overload-overlap] + def __eq__(self, other: Series[Timestamp]) -> Series[bool]: ... # type: ignore[overload-overlap] @overload def __eq__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... # type: ignore[overload-overlap] @overload @@ -242,7 +241,7 @@ class Timestamp(datetime, SupportsIndex): @overload def __ne__(self, other: Timestamp | datetime | np.datetime64) -> bool: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload - def __ne__(self, other: TimestampSeries) -> Series[bool]: ... # type: ignore[overload-overlap] + def __ne__(self, other: Series[Timestamp]) -> Series[bool]: ... # type: ignore[overload-overlap] @overload def __ne__(self, other: npt.NDArray[np.datetime64] | Index) -> np_ndarray_bool: ... # type: ignore[overload-overlap] @overload diff --git a/pandas-stubs/core/indexes/accessors.pyi b/pandas-stubs/core/indexes/accessors.pyi index b5db84dba..70ce8e090 100644 --- a/pandas-stubs/core/indexes/accessors.pyi +++ b/pandas-stubs/core/indexes/accessors.pyi @@ -4,9 +4,11 @@ from datetime import ( tzinfo as _tzinfo, ) from typing import ( + Any, Generic, Literal, TypeVar, + overload, ) import numpy as np @@ -17,6 +19,7 @@ from pandas import ( PeriodIndex, Timedelta, TimedeltaIndex, + Timestamp, ) from pandas.core.accessor import PandasDelegate from pandas.core.arrays import ( @@ -29,12 +32,13 @@ from pandas.core.series import ( PeriodSeries, Series, TimedeltaSeries, - TimestampSeries, ) +from typing_extensions import Never from pandas._libs.tslibs import BaseOffset from pandas._libs.tslibs.offsets import DateOffset from pandas._typing import ( + S1, TimeAmbiguous, TimeNonexistent, TimestampConvention, @@ -155,14 +159,13 @@ class _DatetimeLikeOps( ], ): ... -# Ideally, the rounding methods would return TimestampSeries when `Series.dt.method` +# Ideally, the rounding methods would return Series[Timestamp] when `Series.dt.method` # is invoked, but because of how Series.dt is hooked in and that we may not know the # type of the series, we don't know which kind of series was ...ed # in to the dt accessor _DTTimestampTimedeltaReturnType = TypeVar( - "_DTTimestampTimedeltaReturnType", - bound=Series | TimestampSeries | TimedeltaSeries | DatetimeIndex | TimedeltaIndex, + "_DTTimestampTimedeltaReturnType", bound=Series | DatetimeIndex | TimedeltaIndex ) class _DatetimeRoundingMethods(Generic[_DTTimestampTimedeltaReturnType]): @@ -198,7 +201,7 @@ class _DatetimeRoundingMethods(Generic[_DTTimestampTimedeltaReturnType]): ) -> _DTTimestampTimedeltaReturnType: ... _DTNormalizeReturnType = TypeVar( - "_DTNormalizeReturnType", TimestampSeries, DatetimeIndex + "_DTNormalizeReturnType", Series[Timestamp], DatetimeIndex ) _DTStrKindReturnType = TypeVar("_DTStrKindReturnType", bound=Series[str] | Index) _DTToPeriodReturnType = TypeVar( @@ -320,7 +323,7 @@ class TimedeltaProperties( def as_unit(self, unit: TimeUnit) -> TimedeltaSeries: ... _PeriodDTReturnTypes = TypeVar( - "_PeriodDTReturnTypes", bound=TimestampSeries | DatetimeIndex + "_PeriodDTReturnTypes", bound=Series[Timestamp] | DatetimeIndex ) _PeriodIntReturnTypes = TypeVar("_PeriodIntReturnTypes", bound=Series[int] | Index[int]) _PeriodStrReturnTypes = TypeVar("_PeriodStrReturnTypes", bound=Series[str] | Index) @@ -363,7 +366,7 @@ class PeriodIndexFieldOps( class PeriodProperties( Properties, _PeriodProperties[ - TimestampSeries, Series[int], Series[str], DatetimeArray, PeriodArray + Series[Timestamp], Series[int], Series[str], DatetimeArray, PeriodArray ], _DatetimeFieldOps[Series[int]], _IsLeapYearProperty, @@ -377,7 +380,7 @@ class CombinedDatetimelikeProperties( Series[dt.date], Series[dt.time], str, - TimestampSeries, + Series[Timestamp], Series[str], PeriodSeries, ], @@ -388,11 +391,11 @@ class TimestampProperties( DatetimeProperties[ Series[int], Series[bool], - TimestampSeries, + Series[Timestamp], Series[dt.date], Series[dt.time], str, - TimestampSeries, + Series[Timestamp], Series[str], PeriodSeries, ] @@ -427,3 +430,46 @@ class TimedeltaIndexProperties( _TimedeltaPropertiesNoRounding[Index, Index], _DatetimeRoundingMethods[TimedeltaIndex], ): ... + +class _dtDescriptor(CombinedDatetimelikeProperties, Generic[S1]): + @overload + def __get__(self, instance: Series[Never], owner: Any) -> Never: ... + @overload + def __get__( + self, instance: Series[Timestamp], owner: Any + ) -> TimestampProperties: ... + @overload + def __get__( + self, instance: Series[S1], owner: Any + ) -> CombinedDatetimelikeProperties: ... + def round( + self, + freq: str | BaseOffset | None, + ambiguous: Literal["raise", "infer", "NaT"] | bool | np_ndarray_bool = ..., + nonexistent: ( + Literal["shift_forward", "shift_backward", "NaT", "raise"] + | timedelta + | Timedelta + ) = ..., + ) -> Series[S1]: ... + def floor( + self, + freq: str | BaseOffset | None, + ambiguous: Literal["raise", "infer", "NaT"] | bool | np_ndarray_bool = ..., + nonexistent: ( + Literal["shift_forward", "shift_backward", "NaT", "raise"] + | timedelta + | Timedelta + ) = ..., + ) -> Series[S1]: ... + def ceil( + self, + freq: str | BaseOffset | None, + ambiguous: Literal["raise", "infer", "NaT"] | bool | np_ndarray_bool = ..., + nonexistent: ( + Literal["shift_forward", "shift_backward", "NaT", "raise"] + | timedelta + | Timedelta + ) = ..., + ) -> Series[S1]: ... + def as_unit(self, unit: TimeUnit) -> Series[S1]: ... diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 40a7102cd..589390856 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -23,8 +23,8 @@ from pandas import ( from pandas.core.indexes.accessors import DatetimeIndexProperties from pandas.core.indexes.datetimelike import DatetimeTimedeltaMixin from pandas.core.series import ( + Series, TimedeltaSeries, - TimestampSeries, ) from typing_extensions import Self @@ -60,13 +60,13 @@ class DatetimeIndex(DatetimeTimedeltaMixin[Timestamp], DatetimeIndexProperties): # various ignores needed for mypy, as we do want to restrict what can be used in # arithmetic for these types @overload - def __add__(self, other: TimedeltaSeries) -> TimestampSeries: ... + def __add__(self, other: TimedeltaSeries) -> Series[Timestamp]: ... @overload def __add__( self, other: timedelta | Timedelta | TimedeltaIndex | BaseOffset ) -> DatetimeIndex: ... @overload - def __sub__(self, other: TimedeltaSeries) -> TimestampSeries: ... + def __sub__(self, other: TimedeltaSeries) -> Series[Timestamp]: ... @overload def __sub__( self, other: timedelta | Timedelta | TimedeltaIndex | BaseOffset @@ -76,7 +76,7 @@ class DatetimeIndex(DatetimeTimedeltaMixin[Timestamp], DatetimeIndexProperties): self, other: datetime | Timestamp | DatetimeIndex ) -> TimedeltaIndex: ... @final - def to_series(self, index=..., name: Hashable = ...) -> TimestampSeries: ... + def to_series(self, index=..., name: Hashable = ...) -> Series[Timestamp]: ... def snap(self, freq: str = ...): ... def slice_indexer(self, start=..., end=..., step=...): ... def searchsorted(self, value, side: str = ..., sorter=...): ... diff --git a/pandas-stubs/core/indexes/interval.pyi b/pandas-stubs/core/indexes/interval.pyi index 026c4f2af..cc53b668c 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -15,7 +15,6 @@ from pandas import Index from pandas.core.indexes.extension import ExtensionIndex from pandas.core.series import ( TimedeltaSeries, - TimestampSeries, ) from typing_extensions import TypeAlias @@ -53,7 +52,7 @@ _EdgesFloat: TypeAlias = ( _EdgesTimestamp: TypeAlias = ( Sequence[DatetimeLike] | npt.NDArray[np.datetime64] - | TimestampSeries + | pd.Series[pd.Timestamp] | pd.DatetimeIndex ) _EdgesTimedelta: TypeAlias = ( diff --git a/pandas-stubs/core/reshape/tile.pyi b/pandas-stubs/core/reshape/tile.pyi index 336426cc9..da7d83f16 100644 --- a/pandas-stubs/core/reshape/tile.pyi +++ b/pandas-stubs/core/reshape/tile.pyi @@ -12,10 +12,9 @@ from pandas import ( Index, Interval, IntervalIndex, - Series, Timestamp, ) -from pandas.core.series import TimestampSeries +from pandas.core.series import Series from pandas._typing import ( IntervalT, @@ -51,10 +50,10 @@ def cut( ) -> tuple[npt.NDArray[np.intp], IntervalIndex[IntervalT]]: ... @overload def cut( # pyright: ignore[reportOverlappingOverload] - x: TimestampSeries, + x: Series[Timestamp], bins: ( int - | TimestampSeries + | Series[Timestamp] | DatetimeIndex | Sequence[Timestamp] | Sequence[np.datetime64] @@ -70,7 +69,7 @@ def cut( # pyright: ignore[reportOverlappingOverload] ) -> tuple[Series, DatetimeIndex]: ... @overload def cut( - x: TimestampSeries, + x: Series[Timestamp], bins: IntervalIndex[Interval[Timestamp]], right: bool = ..., labels: Sequence[Label] | None = ..., @@ -156,10 +155,10 @@ def cut( ) -> npt.NDArray[np.intp]: ... @overload def cut( - x: TimestampSeries, + x: Series[Timestamp], bins: ( int - | TimestampSeries + | Series[Timestamp] | DatetimeIndex | Sequence[Timestamp] | Sequence[np.datetime64] diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 3a3ba8c41..834a96938 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -25,6 +25,7 @@ from typing import ( Generic, Literal, NoReturn, + TypeVar, final, overload, ) @@ -59,10 +60,9 @@ from pandas.core.groupby.generic import SeriesGroupBy from pandas.core.groupby.groupby import BaseGroupBy from pandas.core.indexers import BaseIndexer from pandas.core.indexes.accessors import ( - CombinedDatetimelikeProperties, PeriodProperties, TimedeltaProperties, - TimestampProperties, + _dtDescriptor, ) from pandas.core.indexes.category import CategoricalIndex from pandas.core.indexes.datetimes import DatetimeIndex @@ -184,6 +184,30 @@ from pandas.core.dtypes.dtypes import CategoricalDtype from pandas.plotting import PlotAccessor +_T_FLOAT = TypeVar("_T_FLOAT", bound=float) +_T_COMPLEX = TypeVar("_T_COMPLEX", bound=complex) + +_scalar_timestamp: TypeAlias = datetime | np.datetime64 | Timestamp +_vector_timestamp: TypeAlias = ( + Sequence[datetime] + | Sequence[np.datetime64] + | Sequence[Timestamp] + | np.typing.NDArray[np.datetime64] + | DatetimeIndex +) +_nonseries_timestamp: TypeAlias = _scalar_timestamp | _vector_timestamp + +_scalar_timedelta: TypeAlias = timedelta | np.timedelta64 | BaseOffset | Timedelta +_vector_timedelta: TypeAlias = ( + Sequence[timedelta] + | Sequence[np.timedelta64] + | Sequence[Timedelta] + | np.typing.NDArray[np.timedelta64] + | TimedeltaIndex +) +_nonseries_timedelta: TypeAlias = _scalar_timedelta | _vector_timedelta +_T_TIMESTAMP = TypeVar("_T_TIMESTAMP", bound=Timestamp) + class _iLocIndexerSeries(_iLocIndexer, Generic[S1]): # get item @overload @@ -301,7 +325,7 @@ class Series(IndexOpsMixin[S1], NDFrame): dtype: TimestampDtypeArg = ..., name: Hashable = ..., copy: bool = ..., - ) -> TimestampSeries: ... + ) -> Series[Timestamp]: ... @overload def __new__( cls, @@ -311,7 +335,7 @@ class Series(IndexOpsMixin[S1], NDFrame): dtype: TimestampDtypeArg, name: Hashable = ..., copy: bool = ..., - ) -> TimestampSeries: ... + ) -> Series[Timestamp]: ... @overload def __new__( cls, @@ -754,6 +778,13 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def count(self, level: Hashable) -> Series[S1]: ... def mode(self, dropna=...) -> Series[S1]: ... + @overload + def unique(self: Series[Never]) -> np.ndarray: ... # type: ignore[overload-overlap] + @overload + def unique(self: Series[Timestamp]) -> DatetimeArray: ... # type: ignore[overload-overlap] + @overload + def unique(self: Series[Timedelta]) -> TimedeltaArray: ... # type: ignore[overload-overlap] + @overload def unique(self) -> np.ndarray: ... @overload def drop_duplicates( @@ -811,6 +842,8 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def diff(self: Series[_str], periods: int = ...) -> Never: ... @overload + def diff(self: Series[Timestamp], periods: int = ...) -> TimedeltaSeries: ... # type: ignore[overload-overlap] + @overload def diff(self, periods: int = ...) -> Series[float]: ... def autocorr(self, lag: int = ...) -> float: ... @overload @@ -1194,7 +1227,7 @@ class Series(IndexOpsMixin[S1], NDFrame): Series[type[object]], ]: ... @property - def dt(self) -> CombinedDatetimelikeProperties: ... + def dt(self) -> _dtDescriptor[S1]: ... @property def plot(self) -> PlotAccessor: ... sparse = ... @@ -1315,7 +1348,7 @@ class Series(IndexOpsMixin[S1], NDFrame): dtype: TimestampDtypeArg, copy: _bool = ..., errors: IgnoreRaise = ..., - ) -> TimestampSeries: ... + ) -> Series[Timestamp]: ... @overload def astype( self, @@ -1617,6 +1650,26 @@ class Series(IndexOpsMixin[S1], NDFrame): # just failed to generate these so I couldn't match # them up. @overload + def __add__( + self: Series[Never], + other: num | _str | timedelta | Timedelta | _ListLike | Series | np.timedelta64, + ) -> Series: ... + @overload + def __add__( + self: Series[Timestamp], other: _nonseries_timestamp | Series[Timestamp] + ) -> Never: ... + @overload + def __add__( + self: Series[Timestamp], + other: _nonseries_timedelta | Series[Timedelta] | TimedeltaSeries, + ) -> Series[Timestamp]: ... + @overload + def __add__(self: Series[Timedelta], other: Period) -> PeriodSeries: ... + @overload + def __add__( + self: Series[Timedelta], other: _nonseries_timestamp | Series[Timestamp] + ) -> Series[Timestamp]: ... + @overload def __add__(self, other: S1 | Self) -> Self: ... @overload def __add__( @@ -1633,6 +1686,16 @@ class Series(IndexOpsMixin[S1], NDFrame): # def __array__(self, dtype: Optional[_bool] = ...) -> _np_ndarray def __div__(self, other: num | _ListLike | Series[S1]) -> Series[S1]: ... def __eq__(self, other: object) -> Series[_bool]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @overload + def __floordiv__( + self: Series[Timedelta], other: float | Sequence[float] + ) -> TimedeltaSeries: ... + @overload + def __floordiv__( + self: Series[Timedelta], + other: _nonseries_timedelta | Series[Timedelta], + ) -> Series[int]: ... + @overload def __floordiv__(self, other: num | _ListLike | Series[S1]) -> Series[int]: ... def __ge__( # type: ignore[override] self, other: S1 | _ListLike | Series[S1] | datetime | timedelta | date @@ -1647,8 +1710,27 @@ class Series(IndexOpsMixin[S1], NDFrame): self, other: S1 | _ListLike | Series[S1] | datetime | timedelta | date ) -> Series[_bool]: ... @overload + def __mul__(self: Series[Never], other: num | _ListLike | Series) -> Series: ... + @overload + def __mul__(self, other: Series[Never]) -> Series: ... # type: ignore[overload-overlap] + @overload def __mul__( - self, other: timedelta | Timedelta | TimedeltaSeries | np.timedelta64 + self: Series[int], other: _T_COMPLEX | Series[_T_COMPLEX] + ) -> Series[_T_COMPLEX]: ... + @overload + def __mul__( + self: Series[Timestamp], + other: ( + num | Sequence[num] | Series[int] | Series[float] | float | Sequence[float] + ), + ) -> Series[Timestamp]: ... + @overload + def __mul__( + self: Series[Timestamp], other: _nonseries_timedelta | TimedeltaSeries + ) -> Never: ... + @overload + def __mul__( + self: Series[_T_FLOAT], other: _nonseries_timedelta | TimedeltaSeries ) -> TimedeltaSeries: ... @overload def __mul__(self, other: num | _ListLike | Series) -> Series: ... @@ -1663,6 +1745,18 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __or__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... @overload + def __radd__( + self: Series[Never], other: num | _str | _ListLike | Series + ) -> Series: ... + @overload + def __radd__( + self: Series[Timestamp], other: _nonseries_timedelta | Series[Timedelta] + ) -> Series[Timestamp]: ... + @overload + def __radd__( + self: Series[Timedelta], other: datetime | Timestamp | Series[Timestamp] + ) -> Series[Timestamp]: ... + @overload def __radd__(self, other: S1 | Series[S1]) -> Self: ... @overload def __radd__(self, other: num | _str | _ListLike | Series) -> Series: ... @@ -1675,6 +1769,11 @@ class Series(IndexOpsMixin[S1], NDFrame): def __rand__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... def __rdiv__(self, other: num | _ListLike | Series[S1]) -> Series[S1]: ... def __rdivmod__(self, other: num | _ListLike | Series[S1]) -> Series[S1]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @overload + def __rfloordiv__( + self: Series[Timedelta], other: _nonseries_timedelta | Series[Timedelta] + ) -> Series[int]: ... + @overload def __rfloordiv__(self, other: num | _ListLike | Series[S1]) -> Series[S1]: ... def __rmod__(self, other: num | _ListLike | Series[S1]) -> Series[S1]: ... @overload @@ -1693,6 +1792,11 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __ror__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... def __rsub__(self, other: num | _ListLike | Series[S1]) -> Series: ... + @overload + def __rtruediv__( + self: Series[Timedelta], other: _nonseries_timedelta | Series[Timedelta] + ) -> Series[float]: ... + @overload def __rtruediv__(self, other: num | _ListLike | Series[S1] | Path) -> Series: ... # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] @@ -1702,21 +1806,33 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __rxor__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... @overload - def __sub__( - self: Series[Timestamp], - other: Timedelta | TimedeltaSeries | TimedeltaIndex | np.timedelta64, - ) -> TimestampSeries: ... + def __sub__(self: Series[Never], other: num | _ListLike | Series) -> Series: ... @overload def __sub__( - self: Series[Timedelta], - other: Timedelta | TimedeltaSeries | TimedeltaIndex | np.timedelta64, - ) -> TimedeltaSeries: ... + self: Series[Timestamp], other: _nonseries_timedelta | TimedeltaSeries + ) -> Series[Timestamp]: ... @overload def __sub__( - self, other: Timestamp | datetime | TimestampSeries + self: Series[Timestamp], other: _nonseries_timestamp | Series[_T_TIMESTAMP] ) -> TimedeltaSeries: ... @overload + def __sub__(self, other: S1 | Self) -> Self: ... + @overload def __sub__(self, other: num | _ListLike | Series) -> Series: ... + @overload + def __truediv__( + self: Series[Never], other: num | _ListLike | Series[S1] | Path + ) -> Series: ... + @overload + def __truediv__( + self: Series[Timestamp], + other: float | Series[int] | Series[float] | Sequence[float], + ) -> Series[Timestamp]: ... + @overload + def __truediv__( + self: Series[Timedelta], other: _nonseries_timedelta | Series[Timedelta] + ) -> Series[float]: ... + @overload def __truediv__(self, other: num | _ListLike | Series[S1] | Path) -> Series: ... # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] @@ -1786,6 +1902,14 @@ class Series(IndexOpsMixin[S1], NDFrame): **kwargs: Any, ) -> Never: ... @overload + def cumprod( + self: Series[Timestamp], + axis: AxisIndex = ..., + skipna: _bool = ..., + *args: Any, + **kwargs: Any, + ) -> Never: ... + @overload def cumprod( self, axis: AxisIndex = ..., @@ -1899,6 +2023,25 @@ class Series(IndexOpsMixin[S1], NDFrame): numeric_only: _bool = ..., **kwargs: Any, ) -> S1: ... + @overload + def mean( + self: Series[Never], + axis: AxisIndex | None = ..., + skipna: _bool = ..., + level: None = ..., + numeric_only: _bool = ..., + **kwargs: Any, + ) -> float: ... + @overload + def mean( + self: Series[Timestamp], + axis: AxisIndex | None = ..., + skipna: _bool = ..., + level: None = ..., + numeric_only: _bool = ..., + **kwargs: Any, + ) -> Timestamp: ... + @overload def mean( self, axis: AxisIndex | None = ..., @@ -1914,7 +2057,7 @@ class Series(IndexOpsMixin[S1], NDFrame): level: None = ..., numeric_only: _bool = ..., **kwargs: Any, - ) -> float: ... + ) -> S1: ... def min( self, axis: AxisIndex | None = ..., @@ -2091,6 +2234,17 @@ class Series(IndexOpsMixin[S1], NDFrame): numeric_only: _bool = ..., **kwargs: Any, ) -> Scalar: ... + @overload + def std( + self: Series[Timestamp], + axis: AxisIndex | None = ..., + skipna: _bool | None = ..., + level: None = ..., + ddof: int = ..., + numeric_only: _bool = ..., + **kwargs: Any, + ) -> Timedelta: ... + @overload def std( self, axis: AxisIndex | None = ..., @@ -2217,71 +2371,19 @@ class Series(IndexOpsMixin[S1], NDFrame): @final def __bool__(self) -> NoReturn: ... -class TimestampSeries(Series[Timestamp]): - @property - def dt(self) -> TimestampProperties: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - def __add__(self, other: TimedeltaSeries | np.timedelta64 | timedelta | BaseOffset) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - def __radd__(self, other: TimedeltaSeries | np.timedelta64 | timedelta) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - @overload # type: ignore[override] - def __sub__( - self, other: Timestamp | datetime | TimestampSeries - ) -> TimedeltaSeries: ... - @overload - def __sub__( # pyright: ignore[reportIncompatibleMethodOverride] - self, - other: ( - timedelta | TimedeltaSeries | TimedeltaIndex | np.timedelta64 | BaseOffset - ), - ) -> TimestampSeries: ... - def __mul__(self, other: float | Series[int] | Series[float] | Sequence[float]) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - def __truediv__(self, other: float | Series[int] | Series[float] | Sequence[float]) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - def unique(self) -> DatetimeArray: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - def mean( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - self, - axis: AxisIndex | None = ..., - skipna: _bool = ..., - level: None = ..., - numeric_only: _bool = ..., - **kwargs: Any, - ) -> Timestamp: ... - def median( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - self, - axis: AxisIndex | None = ..., - skipna: _bool = ..., - level: None = ..., - numeric_only: _bool = ..., - **kwargs: Any, - ) -> Timestamp: ... - def std( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - self, - axis: AxisIndex | None = ..., - skipna: _bool | None = ..., - ddof: int = ..., - numeric_only: _bool = ..., - **kwargs: Any, - ) -> Timedelta: ... - def diff(self, periods: int = ...) -> TimedeltaSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - def cumprod( - self, - axis: AxisIndex = ..., - skipna: _bool = ..., - *args: Any, - **kwargs: Any, - ) -> Never: ... - class TimedeltaSeries(Series[Timedelta]): # ignores needed because of mypy @overload # type: ignore[override] def __add__(self, other: Period) -> PeriodSeries: ... @overload def __add__( - self, other: datetime | Timestamp | TimestampSeries | DatetimeIndex - ) -> TimestampSeries: ... + self, other: datetime | Timestamp | Series[Timestamp] | DatetimeIndex + ) -> Series[Timestamp]: ... @overload def __add__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: timedelta | Timedelta | np.timedelta64 ) -> TimedeltaSeries: ... - def __radd__(self, other: datetime | Timestamp | TimestampSeries) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def __radd__(self, other: datetime | Timestamp | Series[Timestamp]) -> Series[Timestamp]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] def __mul__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] self, other: num | Sequence[num] | Series[int] | Series[float] ) -> TimedeltaSeries: ... @@ -2348,7 +2450,7 @@ class TimedeltaSeries(Series[Timedelta]): numeric_only: _bool = ..., **kwargs: Any, ) -> Timedelta: ... - def median( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def median( self, axis: AxisIndex | None = ..., skipna: _bool = ..., @@ -2373,7 +2475,7 @@ class TimedeltaSeries(Series[Timedelta]): *args: Any, **kwargs: Any, ) -> TimedeltaSeries: ... - def cumprod( + def cumprod( # pyrefly: ignore self, axis: AxisIndex = ..., skipna: _bool = ..., @@ -2401,7 +2503,7 @@ class OffsetSeries(Series[BaseOffset]): def __radd__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: BaseOffset ) -> OffsetSeries: ... - def cumprod( + def cumprod( # pyrefly: ignore self, axis: AxisIndex = ..., skipna: _bool = ..., @@ -2412,4 +2514,4 @@ class OffsetSeries(Series[BaseOffset]): class IntervalSeries(Series[Interval[_OrderableT]], Generic[_OrderableT]): @property def array(self) -> IntervalArray: ... - def diff(self, periods: int = ...) -> Never: ... + def diff(self, periods: int = ...) -> Never: ... # pyrefly: ignore diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index 6d45eef4d..f040023bf 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -16,10 +16,7 @@ from pandas import ( ) from pandas.core.arrays import ExtensionArray from pandas.core.indexes.datetimes import DatetimeIndex -from pandas.core.series import ( - Series, - TimestampSeries, -) +from pandas.core.series import Series from typing_extensions import TypeAlias from pandas._libs.tslibs import NaTType @@ -94,7 +91,7 @@ def to_datetime( unit: str | None = ..., origin: Literal["julian", "unix"] | TimestampConvertibleTypes = ..., cache: bool = ..., -) -> TimestampSeries: ... +) -> Series[Timestamp]: ... @overload def to_datetime( arg: ( diff --git a/pyproject.toml b/pyproject.toml index a60a4f6ba..0de7fe6ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ mypy = "1.17.0" pandas = "2.3.1" pyarrow = ">=10.0.1" pytest = ">=7.1.2" -pyright = ">=1.1.400" +pyright = ">=1.1.403" ty = "^0.0.1a8" pyrefly = "^0.21.0" poethepoet = ">=0.16.5" diff --git a/tests/test_frame.py b/tests/test_frame.py index 2973d25cb..5a3ffb67c 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -31,7 +31,6 @@ import numpy as np import numpy.typing as npt import pandas as pd -from pandas import Timestamp from pandas.api.typing import NAType from pandas.core.resample import ( DatetimeIndexResampler, @@ -63,10 +62,8 @@ if TYPE_CHECKING: from pandas.core.frame import _PandasNamedTuple - from pandas.core.series import TimestampSeries else: _PandasNamedTuple: TypeAlias = tuple - TimestampSeries: TypeAlias = pd.Series DF = pd.DataFrame(data={"col1": [1, 2], "col2": [3, 4]}) @@ -2535,9 +2532,9 @@ def test_types_regressions() -> None: sseries + pd.Timedelta(1, "d") check( - assert_type(sseries + pd.Timedelta(1, "D"), TimestampSeries), + assert_type(sseries + pd.Timedelta(1, "D"), "pd.Series[pd.Timestamp]"), pd.Series, - Timestamp, + pd.Timestamp, ) # https://github.com/microsoft/pylance-release/issues/2133 @@ -2819,9 +2816,9 @@ def test_sum_get_add() -> None: summer = df.sum(axis=1) check(assert_type(summer, pd.Series), pd.Series) - check(assert_type(s + summer, pd.Series), pd.Series) - check(assert_type(s + df["y"], pd.Series), pd.Series) - check(assert_type(summer + summer, pd.Series), pd.Series) + check(assert_type(s + summer, pd.Series), pd.Series) # type: ignore[assert-type] + check(assert_type(s + df["y"], pd.Series), pd.Series) # type: ignore[assert-type] + check(assert_type(summer + summer, pd.Series), pd.Series) # type: ignore[assert-type] def test_getset_untyped() -> None: @@ -3479,6 +3476,7 @@ def test_groupby_apply() -> None: df = pd.DataFrame({"col1": [1, 2, 3], "col2": [4, 5, 6]}) def sum_mean(x: pd.DataFrame) -> float: + x.sum() return x.sum().mean() with pytest_warns_bounded( diff --git a/tests/test_pandas.py b/tests/test_pandas.py index 068254c3a..1807a3c50 100644 --- a/tests/test_pandas.py +++ b/tests/test_pandas.py @@ -23,7 +23,6 @@ import pytest from typing_extensions import ( Never, - TypeAlias, assert_type, ) @@ -36,18 +35,19 @@ pytest_warns_bounded, ) -if TYPE_CHECKING: - from pandas.core.series import TimestampSeries -else: - TimestampSeries: TypeAlias = pd.Series - def test_types_to_datetime() -> None: df = pd.DataFrame({"year": [2015, 2016], "month": [2, 3], "day": [4, 5]}) - check(assert_type(pd.to_datetime(df), TimestampSeries), pd.Series, pd.Timestamp) + check( + assert_type(pd.to_datetime(df), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) check( - assert_type(pd.to_datetime(df, unit="s", origin="unix"), TimestampSeries), + assert_type( + pd.to_datetime(df, unit="s", origin="unix"), "pd.Series[pd.Timestamp]" + ), pd.Series, pd.Timestamp, ) @@ -56,7 +56,7 @@ def test_types_to_datetime() -> None: pd.to_datetime( df, unit="ns", dayfirst=True, utc=False, format="%M:%D", exact=False ), - TimestampSeries, + "pd.Series[pd.Timestamp]", ), pd.Series, pd.Timestamp, @@ -92,7 +92,7 @@ def test_types_to_datetime() -> None: check( assert_type( pd.to_datetime({"year": [2015, 2016], "month": [2, 3], "day": [4, 5]}), - TimestampSeries, + "pd.Series[pd.Timestamp]", ), pd.Series, pd.Timestamp, diff --git a/tests/test_scalars.py b/tests/test_scalars.py index bfc78ae65..0a782ddbd 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -39,12 +39,10 @@ OffsetSeries, PeriodSeries, TimedeltaSeries, - TimestampSeries, ) else: TimedeltaSeries: TypeAlias = pd.Series - TimestampSeries: TypeAlias = pd.Series PeriodSeries: TypeAlias = pd.Series OffsetSeries: TypeAlias = pd.Series @@ -1215,10 +1213,14 @@ def test_timestamp_add_sub() -> None: check(assert_type(as_timedelta_index + ts, pd.DatetimeIndex), pd.DatetimeIndex) check( - assert_type(ts + as_timedelta_series, TimestampSeries), pd.Series, pd.Timestamp + assert_type(ts + as_timedelta_series, "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, ) check( - assert_type(as_timedelta_series + ts, TimestampSeries), pd.Series, pd.Timestamp + assert_type(as_timedelta_series + ts, "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, ) check( @@ -1241,7 +1243,9 @@ def test_timestamp_add_sub() -> None: check(assert_type(ts - as_offset, pd.Timestamp), pd.Timestamp) check(assert_type(ts - as_timedelta_index, pd.DatetimeIndex), pd.DatetimeIndex) check( - assert_type(ts - as_timedelta_series, TimestampSeries), pd.Series, pd.Timestamp + assert_type(ts - as_timedelta_series, "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, ) check( assert_type(ts - as_np_ndarray_td64, npt.NDArray[np.datetime64]), @@ -1264,9 +1268,13 @@ def test_timestamp_cmp() -> None: # DatetimeIndex, but the type checker detects it to be UnknownIndex. c_unknown_index = pd.DataFrame({"a": [1]}, index=c_datetimeindex).index c_np_ndarray_dt64 = np_dt64_arr - c_series_dt64: TimestampSeries = pd.Series([1, 2, 3], dtype="datetime64[ns]") + c_series_dt64 = pd.Series([1, 2, 3], dtype="datetime64[ns]") c_series_timestamp = pd.Series(pd.DatetimeIndex(["2000-1-1"])) - check(assert_type(c_series_timestamp, TimestampSeries), pd.Series, pd.Timestamp) + check( + assert_type(c_series_timestamp, "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) # Use xor to ensure one is True and the other is False # Correctness ensures since tested to be bools gt = check(assert_type(ts > c_timestamp, bool), bool) @@ -1725,7 +1733,7 @@ def test_types_timestamp_series_comparisons() -> None: data = pd.date_range("2022-01-01", "2022-01-31", freq="D") s = pd.Series(data) ts2 = pd.Timestamp("2022-01-15") - check(assert_type(s, TimestampSeries), pd.Series, pd.Timestamp) + check(assert_type(s, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) check(assert_type(ts2 <= s, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(ts2 >= s, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(ts2 < s, "pd.Series[bool]"), pd.Series, np.bool_) diff --git a/tests/test_series.py b/tests/test_series.py index f58d651f4..bda68d692 100644 --- a/tests/test_series.py +++ b/tests/test_series.py @@ -68,7 +68,6 @@ from pandas.core.series import ( OffsetSeries, TimedeltaSeries, - TimestampSeries, ) from tests import ( @@ -89,7 +88,6 @@ else: TimedeltaSeries: TypeAlias = pd.Series - TimestampSeries: TypeAlias = pd.Series OffsetSeries: TypeAlias = pd.Series @@ -811,13 +809,11 @@ def test_types_element_wise_arithmetic() -> None: check(assert_type(s + s2, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(s.add(s2, fill_value=0), "pd.Series[int]"), pd.Series, np.integer) - # TODO this one below should type pd.Series[int] - check(assert_type(s - s2, pd.Series), pd.Series, np.integer) + check(assert_type(s - s2, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(s.sub(s2, fill_value=0), "pd.Series[int]"), pd.Series, np.integer) - # TODO these two below should type pd.Series[int] - # check(assert_type(s * s2, "pd.Series[int]"), pd.Series, np.integer ) - check(assert_type(s * s2, pd.Series), pd.Series, np.integer) + check(assert_type(s * s2, "pd.Series[int]"), pd.Series, np.integer) + # TODO this below should type pd.Series[int] # check(assert_type(s.mul(s2, fill_value=0), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(s.mul(s2, fill_value=0), pd.Series), pd.Series, np.integer) @@ -1604,8 +1600,8 @@ def test_series_min_max_sub_axis() -> None: ss = s1 - s2 sm = s1 * s2 sd = s1 / s2 - check(assert_type(sa, pd.Series), pd.Series) - check(assert_type(ss, pd.Series), pd.Series) + check(assert_type(sa, pd.Series), pd.Series) # type: ignore[assert-type] + check(assert_type(ss, pd.Series), pd.Series) # type: ignore[assert-type] check(assert_type(sm, pd.Series), pd.Series) check(assert_type(sd, pd.Series), pd.Series) @@ -1641,11 +1637,11 @@ def test_series_multiindex_getitem() -> None: def test_series_mul() -> None: s = pd.Series([1, 2, 3]) sm = s * 4 - check(assert_type(sm, pd.Series), pd.Series) + check(assert_type(sm, "pd.Series[int]"), pd.Series, np.integer) ss = s - 4 - check(assert_type(ss, pd.Series), pd.Series) + check(assert_type(ss, "pd.Series[int]"), pd.Series, np.integer) sm2 = s * s - check(assert_type(sm2, pd.Series), pd.Series) + check(assert_type(sm2, "pd.Series[int]"), pd.Series, np.integer) sp = s + 4 check(assert_type(sp, "pd.Series[int]"), pd.Series, np.integer) @@ -2791,64 +2787,64 @@ def test_astype_timestamp(cast_arg: TimestampDtypeArg, target_type: type) -> Non if cast_arg in ("date32[pyarrow]", "date64[pyarrow]"): x = pd.Series(pd.date_range("2000-01-01", "2000-02-01")) - check(x.astype(cast_arg), TimestampSeries, target_type) + check(x.astype(cast_arg), pd.Series, target_type) else: - check(s.astype(cast_arg), TimestampSeries, target_type) + check(s.astype(cast_arg), pd.Series, target_type) if TYPE_CHECKING: # numpy datetime64 - assert_type(s.astype("datetime64[Y]"), TimestampSeries) - assert_type(s.astype("datetime64[M]"), TimestampSeries) - assert_type(s.astype("datetime64[W]"), TimestampSeries) - assert_type(s.astype("datetime64[D]"), TimestampSeries) - assert_type(s.astype("datetime64[h]"), TimestampSeries) - assert_type(s.astype("datetime64[m]"), TimestampSeries) - assert_type(s.astype("datetime64[s]"), TimestampSeries) - assert_type(s.astype("datetime64[ms]"), TimestampSeries) - assert_type(s.astype("datetime64[us]"), TimestampSeries) - assert_type(s.astype("datetime64[μs]"), TimestampSeries) - assert_type(s.astype("datetime64[ns]"), TimestampSeries) - assert_type(s.astype("datetime64[ps]"), TimestampSeries) - assert_type(s.astype("datetime64[fs]"), TimestampSeries) - assert_type(s.astype("datetime64[as]"), TimestampSeries) + assert_type(s.astype("datetime64[Y]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[M]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[W]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[D]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[h]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[m]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[s]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[ms]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[us]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[μs]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[ns]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[ps]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[fs]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("datetime64[as]"), "pd.Series[pd.Timestamp]") # numpy datetime64 type codes - assert_type(s.astype("M8[Y]"), TimestampSeries) - assert_type(s.astype("M8[M]"), TimestampSeries) - assert_type(s.astype("M8[W]"), TimestampSeries) - assert_type(s.astype("M8[D]"), TimestampSeries) - assert_type(s.astype("M8[h]"), TimestampSeries) - assert_type(s.astype("M8[m]"), TimestampSeries) - assert_type(s.astype("M8[s]"), TimestampSeries) - assert_type(s.astype("M8[ms]"), TimestampSeries) - assert_type(s.astype("M8[us]"), TimestampSeries) - assert_type(s.astype("M8[μs]"), TimestampSeries) - assert_type(s.astype("M8[ns]"), TimestampSeries) - assert_type(s.astype("M8[ps]"), TimestampSeries) - assert_type(s.astype("M8[fs]"), TimestampSeries) - assert_type(s.astype("M8[as]"), TimestampSeries) + assert_type(s.astype("M8[Y]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[M]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[W]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[D]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[h]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[m]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[s]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[ms]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[us]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[μs]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[ns]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[ps]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[fs]"), "pd.Series[pd.Timestamp]") + assert_type(s.astype("M8[as]"), "pd.Series[pd.Timestamp]") # numpy datetime64 type codes - assert_type(s.astype(" None: def test_timedeltaseries_operators() -> None: series = pd.Series([pd.Timedelta(days=1)]) check( - assert_type(series + datetime.datetime.now(), TimestampSeries), + assert_type(series + datetime.datetime.now(), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) @@ -3363,7 +3359,7 @@ def test_timedeltaseries_operators() -> None: pd.Timedelta, ) check( - assert_type(datetime.datetime.now() + series, TimestampSeries), + assert_type(datetime.datetime.now() + series, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) @@ -3377,13 +3373,13 @@ def test_timedeltaseries_operators() -> None: def test_timestamp_series() -> None: series = pd.Series([pd.Timestamp(2024, 4, 4)]) check( - assert_type(series + YearEnd(0), TimestampSeries), - TimestampSeries, + assert_type(series + YearEnd(0), "pd.Series[pd.Timestamp]"), + pd.Series, pd.Timestamp, ) check( - assert_type(series - YearEnd(0), TimestampSeries), - TimestampSeries, + assert_type(series - YearEnd(0), "pd.Series[pd.Timestamp]"), + pd.Series, pd.Timestamp, ) @@ -3915,7 +3911,7 @@ def test_cumsum_timedelta() -> None: s = pd.Series(pd.to_timedelta([1, 2, 3], "h")) check(assert_type(s.cumsum(), "TimedeltaSeries"), pd.Series, pd.Timedelta) check( - assert_type(pd.Timestamp(0) + s.cumsum(), "TimestampSeries"), + assert_type(pd.Timestamp(0) + s.cumsum(), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 4843c5139..67de2b7ae 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -51,7 +51,6 @@ if TYPE_CHECKING: from pandas.core.series import PeriodSeries # noqa: F401 from pandas.core.series import TimedeltaSeries # noqa: F401 - from pandas.core.series import TimestampSeries # noqa: F401 from tests import np_ndarray_bool @@ -125,7 +124,7 @@ def test_types_timestamp_series_comparisons() -> None: data = pd.date_range("2022-01-01", "2022-01-31", freq="D") s = pd.Series(data) ts2 = pd.Timestamp("2022-01-15") - check(assert_type(s, "TimestampSeries"), pd.Series, pd.Timestamp) + check(assert_type(s, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) check(assert_type(ts2 <= s, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(ts2 >= s, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(ts2 < s, "pd.Series[bool]"), pd.Series, np.bool_) @@ -216,7 +215,7 @@ def test_datetimeindex_plus_timedelta() -> None: check( assert_type( pd.Series([pd.Timestamp("2022-03-05"), pd.Timestamp("2022-03-06")]), - "TimestampSeries", + "pd.Series[pd.Timestamp]", ), pd.Series, pd.Timestamp, @@ -225,13 +224,13 @@ def test_datetimeindex_plus_timedelta() -> None: td_s = pd.to_timedelta(pd.Series([10, 20]), "minutes") dti_td_s = dti + td_s check( - assert_type(dti_td_s, "TimestampSeries"), + assert_type(dti_td_s, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) td_dti_s = td_s + dti check( - assert_type(td_dti_s, "TimestampSeries"), + assert_type(td_dti_s, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) @@ -251,7 +250,7 @@ def test_datetimeindex_minus_timedelta() -> None: check( assert_type( pd.Series([pd.Timestamp("2022-03-05"), pd.Timestamp("2022-03-06")]), - "TimestampSeries", + "pd.Series[pd.Timestamp]", ), pd.Series, pd.Timestamp, @@ -260,7 +259,7 @@ def test_datetimeindex_minus_timedelta() -> None: td_s = pd.to_timedelta(pd.Series([10, 20]), "minutes") dti_td_s = dti - td_s check( - assert_type(dti_td_s, "TimestampSeries"), + assert_type(dti_td_s, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) @@ -277,7 +276,7 @@ def test_timestamp_plus_timedelta_series() -> None: check( assert_type( pd.Series([pd.Timestamp("2022-03-05"), pd.Timestamp("2022-03-06")]), - "TimestampSeries", + "pd.Series[pd.Timestamp]", ), pd.Series, pd.Timestamp, @@ -285,9 +284,9 @@ def test_timestamp_plus_timedelta_series() -> None: ts = pd.Timestamp("2022-03-05") td = pd.to_timedelta(pd.Series([10, 20]), "minutes") r3 = td + ts - check(assert_type(r3, "TimestampSeries"), pd.Series, pd.Timestamp) + check(assert_type(r3, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) r4 = ts + td - check(assert_type(r4, "TimestampSeries"), pd.Series, pd.Timestamp) + check(assert_type(r4, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) def test_timedelta_series_mult() -> None: @@ -321,9 +320,9 @@ def test_fail_on_adding_two_timestamps() -> None: s1 = pd.Series(pd.to_datetime(["2022-05-01", "2022-06-01"])) s2 = pd.Series(pd.to_datetime(["2022-05-15", "2022-06-15"])) if TYPE_CHECKING_INVALID_USAGE: - ssum: pd.Series = s1 + s2 # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + ssum = s1 + s2 # type: ignore[var-annotated] ts = pd.Timestamp("2022-06-30") - tsum: pd.Series = s1 + ts # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + tsum = s1 + ts # type: ignore[var-annotated] def test_dtindex_tzinfo() -> None: @@ -378,7 +377,9 @@ def test_series_dt_accessors() -> None: i0 = pd.date_range(start="2022-06-01", periods=10) check(assert_type(i0, pd.DatetimeIndex), pd.DatetimeIndex, pd.Timestamp) - check(assert_type(i0.to_series(), "TimestampSeries"), pd.Series, pd.Timestamp) + check( + assert_type(i0.to_series(), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp + ) s0 = pd.Series(i0) @@ -425,94 +426,125 @@ def test_series_dt_accessors() -> None: ) s0_local = s0.dt.tz_localize("UTC") check( - assert_type(s0_local, "TimestampSeries"), + assert_type(s0_local, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) check( - assert_type(s0.dt.tz_localize(None), "TimestampSeries"), pd.Series, pd.Timestamp + assert_type(s0.dt.tz_localize(None), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, ) check( assert_type( s0.dt.tz_localize(pytz.UTC, nonexistent=dt.timedelta(0)), - "TimestampSeries", + "pd.Series[pd.Timestamp]", ), pd.Series, pd.Timestamp, ) check( - assert_type(s0.dt.tz_localize(pytz.timezone("US/Eastern")), "TimestampSeries"), + assert_type( + s0.dt.tz_localize(pytz.timezone("US/Eastern")), "pd.Series[pd.Timestamp]" + ), pd.Series, pd.Timestamp, ) check( - assert_type(s0_local.dt.tz_convert("EST"), "TimestampSeries"), + assert_type(s0_local.dt.tz_convert("EST"), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) check( - assert_type(s0_local.dt.tz_convert(None), "TimestampSeries"), + assert_type(s0_local.dt.tz_convert(None), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) check( - assert_type(s0_local.dt.tz_convert(pytz.UTC), "TimestampSeries"), + assert_type(s0_local.dt.tz_convert(pytz.UTC), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) check( - assert_type(s0_local.dt.tz_convert(1), "TimestampSeries"), + assert_type(s0_local.dt.tz_convert(1), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) check( assert_type( - s0_local.dt.tz_convert(pytz.timezone("US/Eastern")), "TimestampSeries" + s0_local.dt.tz_convert(pytz.timezone("US/Eastern")), + "pd.Series[pd.Timestamp]", ), pd.Series, pd.Timestamp, ) check(assert_type(s0.dt.tz, Optional[dt.tzinfo]), type(None)) check(assert_type(s0_local.dt.tz, Optional[dt.tzinfo]), dt.tzinfo) - check(assert_type(s0.dt.normalize(), "TimestampSeries"), pd.Series, pd.Timestamp) + check( + assert_type(s0.dt.normalize(), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) check(assert_type(s0.dt.strftime("%Y"), "pd.Series[str]"), pd.Series, str) check( - assert_type(s0.dt.round("D", nonexistent=dt.timedelta(1)), "TimestampSeries"), + assert_type( + s0.dt.round("D", nonexistent=dt.timedelta(1)), "pd.Series[pd.Timestamp]" + ), pd.Series, pd.Timestamp, ) check( - assert_type(s0.dt.round("D", ambiguous=False), "TimestampSeries"), + assert_type(s0.dt.round("D", ambiguous=False), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) check( - assert_type(s0.dt.floor("D", nonexistent=dt.timedelta(1)), "TimestampSeries"), + assert_type( + s0.dt.floor("D", nonexistent=dt.timedelta(1)), "pd.Series[pd.Timestamp]" + ), pd.Series, pd.Timestamp, ) check( - assert_type(s0.dt.floor("D", ambiguous=False), "TimestampSeries"), + assert_type(s0.dt.floor("D", ambiguous=False), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) check( - assert_type(s0.dt.ceil("D", nonexistent=dt.timedelta(1)), "TimestampSeries"), + assert_type( + s0.dt.ceil("D", nonexistent=dt.timedelta(1)), "pd.Series[pd.Timestamp]" + ), pd.Series, pd.Timestamp, ) check( - assert_type(s0.dt.ceil("D", ambiguous=False), "TimestampSeries"), + assert_type(s0.dt.ceil("D", ambiguous=False), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp, ) check(assert_type(s0.dt.month_name(), "pd.Series[str]"), pd.Series, str) check(assert_type(s0.dt.day_name(), "pd.Series[str]"), pd.Series, str) check(assert_type(s0.dt.unit, TimeUnit), str) - check(assert_type(s0.dt.as_unit("s"), "TimestampSeries"), pd.Series, pd.Timestamp) - check(assert_type(s0.dt.as_unit("ms"), "TimestampSeries"), pd.Series, pd.Timestamp) - check(assert_type(s0.dt.as_unit("us"), "TimestampSeries"), pd.Series, pd.Timestamp) - check(assert_type(s0.dt.as_unit("ns"), "TimestampSeries"), pd.Series, pd.Timestamp) + check( + assert_type(s0.dt.as_unit("s"), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) + check( + assert_type(s0.dt.as_unit("ms"), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) + check( + assert_type(s0.dt.as_unit("us"), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) + check( + assert_type(s0.dt.as_unit("ns"), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) i1 = pd.period_range(start="2022-06-01", periods=10) @@ -523,8 +555,14 @@ def test_series_dt_accessors() -> None: s1 = pd.Series(i1) check(assert_type(s1.dt.qyear, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(s1.dt.start_time, "TimestampSeries"), pd.Series, pd.Timestamp) - check(assert_type(s1.dt.end_time, "TimestampSeries"), pd.Series, pd.Timestamp) + check( + assert_type(s1.dt.start_time, "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) + check( + assert_type(s1.dt.end_time, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp + ) i2 = pd.timedelta_range(start="1 day", periods=10) check(assert_type(i2, pd.TimedeltaIndex), pd.TimedeltaIndex) @@ -551,18 +589,31 @@ def test_series_dt_accessors() -> None: check(assert_type(s2.dt.as_unit("us"), "TimedeltaSeries"), pd.Series, pd.Timedelta) check(assert_type(s2.dt.as_unit("ns"), "TimedeltaSeries"), pd.Series, pd.Timedelta) - # Checks for general Series other than TimestampSeries and TimedeltaSeries + # Checks for general Series other than Series[Timestamp] and TimedeltaSeries - s4 = cast( - "pd.Series[pd.Timestamp]", - pd.Series([pd.Timestamp("2024-01-01"), pd.Timestamp("2024-01-02")]), - ) + s4 = pd.Series([pd.Timestamp("2024-01-01"), pd.Timestamp("2024-01-02")]) check(assert_type(s4.dt.unit, TimeUnit), str) - check(assert_type(s4.dt.as_unit("s"), pd.Series), pd.Series, pd.Timestamp) - check(assert_type(s4.dt.as_unit("ms"), pd.Series), pd.Series, pd.Timestamp) - check(assert_type(s4.dt.as_unit("us"), pd.Series), pd.Series, pd.Timestamp) - check(assert_type(s4.dt.as_unit("ns"), pd.Series), pd.Series, pd.Timestamp) + check( + assert_type(s4.dt.as_unit("s"), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) + check( + assert_type(s4.dt.as_unit("ms"), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) + check( + assert_type(s4.dt.as_unit("us"), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) + check( + assert_type(s4.dt.as_unit("ns"), "pd.Series[pd.Timestamp]"), + pd.Series, + pd.Timestamp, + ) s5 = cast( "pd.Series[pd.Timedelta]", @@ -570,10 +621,26 @@ def test_series_dt_accessors() -> None: ) check(assert_type(s5.dt.unit, TimeUnit), str) - check(assert_type(s5.dt.as_unit("s"), pd.Series), pd.Series, pd.Timedelta) - check(assert_type(s5.dt.as_unit("ms"), pd.Series), pd.Series, pd.Timedelta) - check(assert_type(s5.dt.as_unit("us"), pd.Series), pd.Series, pd.Timedelta) - check(assert_type(s5.dt.as_unit("ns"), pd.Series), pd.Series, pd.Timedelta) + check( + assert_type(s5.dt.as_unit("s"), "pd.Series[pd.Timedelta]"), # type: ignore[assert-type] + pd.Series, + pd.Timedelta, + ) + check( + assert_type(s5.dt.as_unit("ms"), "pd.Series[pd.Timedelta]"), # type: ignore[assert-type] + pd.Series, + pd.Timedelta, + ) + check( + assert_type(s5.dt.as_unit("us"), "pd.Series[pd.Timedelta]"), # type: ignore[assert-type] + pd.Series, + pd.Timedelta, + ) + check( + assert_type(s5.dt.as_unit("ns"), "pd.Series[pd.Timedelta]"), # type: ignore[assert-type] + pd.Series, + pd.Timedelta, + ) def test_datetimeindex_accessors() -> None: @@ -1068,7 +1135,7 @@ def test_to_datetime_scalar_extended() -> None: def test_to_datetime_series() -> None: s = pd.Series(["2000-01-01", "2000-01-02"]) - check(assert_type(pd.to_datetime(s), "TimestampSeries"), pd.Series) + check(assert_type(pd.to_datetime(s), "pd.Series[pd.Timestamp]"), pd.Series) d: FulldatetimeDict = { "year": [2000, 2000, 2000], "month": [1, 1, 1], @@ -1089,9 +1156,9 @@ def test_to_datetime_series() -> None: "us": [1, 1, 1], "ns": [1, 1, 1], } - check(assert_type(pd.to_datetime(df), "TimestampSeries"), pd.Series) - check(assert_type(pd.to_datetime(d), "TimestampSeries"), pd.Series) - check(assert_type(pd.to_datetime(d_ex), "TimestampSeries"), pd.Series) + check(assert_type(pd.to_datetime(df), "pd.Series[pd.Timestamp]"), pd.Series) + check(assert_type(pd.to_datetime(d), "pd.Series[pd.Timestamp]"), pd.Series) + check(assert_type(pd.to_datetime(d_ex), "pd.Series[pd.Timestamp]"), pd.Series) def test_to_datetime_array() -> None: @@ -1334,19 +1401,19 @@ def test_timedelta64_and_arithmatic_operator() -> None: s3 = s2 - s1 check(assert_type(s3, "TimedeltaSeries"), pd.Series, pd.Timedelta) td1 = pd.Timedelta(1, "D") - check(assert_type(s2 - td1, "TimestampSeries"), pd.Series, pd.Timestamp) + check(assert_type(s2 - td1, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) # GH 758 s4 = s1.astype(object) - check(assert_type(s4 - td1, "TimestampSeries"), pd.Series, pd.Timestamp) + check(assert_type(s4 - td1, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) td = np.timedelta64(1, "D") - check(assert_type((s1 - td), "TimestampSeries"), pd.Series, pd.Timestamp) - check(assert_type((s1 + td), "TimestampSeries"), pd.Series, pd.Timestamp) + check(assert_type((s1 - td), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) + check(assert_type((s1 + td), "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) check(assert_type((s3 - td), "TimedeltaSeries"), pd.Series, pd.Timedelta) check(assert_type((s3 + td), "TimedeltaSeries"), pd.Series, pd.Timedelta) check(assert_type((s3 / td), "pd.Series[float]"), pd.Series, float) if TYPE_CHECKING_INVALID_USAGE: - r1 = s1 * td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + r1 = s1 * td # type: ignore[var-annotated] r2 = s1 / td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] r3 = s3 * td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -1355,7 +1422,7 @@ def test_timedeltaseries_add_timestampseries() -> None: tds = pd.Series(pd.timedelta_range(start="1 day", periods=10)) tss = pd.Series(pd.date_range(start="2012-01-01", periods=10, freq="W-MON")) plus = tds + tss - check(assert_type(plus, "TimestampSeries"), pd.Series, pd.Timestamp) + check(assert_type(plus, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) def test_mean_median_std() -> None: From ed69ec596d09989815da1c8251d5476e9e862aad Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 28 Jul 2025 17:05:33 +0200 Subject: [PATCH 2/2] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1274/files#r2229555145 --- docs/philosophy.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/philosophy.md b/docs/philosophy.md index c19f1e1b9..0c54e6833 100644 --- a/docs/philosophy.md +++ b/docs/philosophy.md @@ -37,6 +37,7 @@ the following example that creates two series of datetimes with corresponding ar ```python import pandas as pd +from typing import reveal_type s1 = pd.Series(pd.to_datetime(["2022-05-01", "2022-06-01"])) reveal_type(s1) @@ -51,14 +52,14 @@ reveal_type(ssum) The above code (without the `reveal_type()` statements) will get a `Never` on the computation of `ssum` because it is inappropriate to add two series containing `Timestamp` values. The types will be -revealed as follows: +revealed by `mypy` as follows: ```text -ttest.py:4: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp]" -ttest.py:6: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp]" -ttest.py:8: note: Revealed type is "pandas.core.series.TimedeltaSeries" -ttest.py:9: error: Need type annotation for "ssum" [var-annotated] -ttest.py:10: note: Revealed type is "Never" +ttest.py:5: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp]" +ttest.py:7: note: Revealed type is "pandas.core.series.Series[pandas._libs.tslibs.timestamps.Timestamp]" +ttest.py:9: note: Revealed type is "pandas.core.series.TimedeltaSeries" +ttest.py:10: error: Need type annotation for "ssum" [var-annotated] +ttest.py:11: note: Revealed type is "Never" ``` The type `Series[Timestamp]` is the result of creating a series from `pd.to_datetime()`, while