diff --git a/pandas-stubs/_libs/tslibs/timedeltas.pyi b/pandas-stubs/_libs/tslibs/timedeltas.pyi index aa09000ad..dad83b6fe 100644 --- a/pandas-stubs/_libs/tslibs/timedeltas.pyi +++ b/pandas-stubs/_libs/tslibs/timedeltas.pyi @@ -1,24 +1,56 @@ +import datetime as dt from datetime import timedelta from typing import ( ClassVar, Literal, + NamedTuple, TypeVar, Union, overload, ) import numpy as np +import pandas as pd +from pandas import ( + DatetimeIndex, + Float64Index, + Int64Index, + PeriodIndex, + Series, + TimedeltaIndex, +) +from pandas.core.series import ( + TimedeltaSeries, + TimestampSeries, +) from typing_extensions import TypeAlias from pandas._libs.tslibs import ( + BaseOffset, NaTType, - Tick, ) +from pandas._libs.tslibs.period import Period +from pandas._libs.tslibs.timestamps import Timestamp from pandas._typing import npt +class Components(NamedTuple): + days: int + hours: int + minutes: int + seconds: int + milliseconds: int + microseconds: int + nanoseconds: int + # This should be kept consistent with the keys in the dict timedelta_abbrevs # in pandas/_libs/tslibs/timedeltas.pyx TimeDeltaUnitChoices: TypeAlias = Literal[ + "H", + "T", + "S", + "L", + "U", + "N", "W", "w", "D", @@ -70,28 +102,23 @@ UnitChoices: TypeAlias = Union[ _S = TypeVar("_S", bound=timedelta) -def ints_to_pytimedelta( - arr: npt.NDArray[np.int64], # const int64_t[:] - box: bool = ..., -) -> npt.NDArray[np.object_]: ... -def array_to_timedelta64( - values: npt.NDArray[np.object_], - unit: str | None = ..., - errors: str = ..., -) -> np.ndarray: ... # np.ndarray[m8ns] -def parse_timedelta_unit(unit: str | None) -> UnitChoices: ... -def delta_to_nanoseconds(delta: np.timedelta64 | timedelta | Tick) -> int: ... - class Timedelta(timedelta): min: ClassVar[Timedelta] max: ClassVar[Timedelta] resolution: ClassVar[Timedelta] - value: int # np.int64 + value: int def __new__( cls: type[_S], - value=..., - unit: str = ..., - **kwargs: float | np.integer | np.floating, + value: str | int | Timedelta | timedelta | np.timedelta64 = ..., + unit: TimeDeltaUnitChoices = ..., + *, + days: float | np.integer | np.floating = ..., + seconds: float | np.integer | np.floating = ..., + microseconds: float | np.integer | np.floating = ..., + milliseconds: float | np.integer | np.floating = ..., + minutes: float | np.integer | np.floating = ..., + hours: float | np.integer | np.floating = ..., + weeks: float | np.integer | np.floating = ..., ) -> _S: ... # GH 46171 # While Timedelta can return pd.NaT, having the constructor return @@ -99,6 +126,8 @@ class Timedelta(timedelta): @property def days(self) -> int: ... @property + def nanoseconds(self) -> int: ... + @property def seconds(self) -> int: ... @property def microseconds(self) -> int: ... @@ -108,49 +137,259 @@ class Timedelta(timedelta): @property def asm8(self) -> np.timedelta64: ... # TODO: round/floor/ceil could return NaT? - def round(self: _S, freq: str) -> _S: ... - def floor(self: _S, freq: str) -> _S: ... - def ceil(self: _S, freq: str) -> _S: ... + def round(self: _S, freq: str | BaseOffset) -> _S: ... + def floor(self: _S, freq: str | BaseOffset) -> _S: ... + def ceil(self: _S, freq: str | BaseOffset) -> _S: ... @property def resolution_string(self) -> str: ... - def __add__(self, other: timedelta) -> Timedelta: ... - def __radd__(self, other: timedelta) -> Timedelta: ... - def __sub__(self, other: timedelta) -> Timedelta: ... - def __rsub__(self, other: timedelta) -> Timedelta: ... + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] + def __add__(self, other: timedelta | Timedelta | np.timedelta64) -> Timedelta: ... + @overload + def __add__(self, other: dt.datetime | np.datetime64 | Timestamp) -> Timestamp: ... + @overload + def __add__(self, other: NaTType) -> NaTType: ... + @overload + def __add__(self, other: Period) -> Period: ... + @overload + def __add__(self, other: dt.date) -> dt.date: ... + @overload + def __add__(self, other: PeriodIndex) -> PeriodIndex: ... + @overload + def __add__(self, other: DatetimeIndex) -> DatetimeIndex: ... + @overload + def __add__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.timedelta64]: ... + @overload + def __add__( + self, other: npt.NDArray[np.datetime64] + ) -> npt.NDArray[np.datetime64]: ... + @overload + def __add__(self, other: pd.TimedeltaIndex) -> pd.TimedeltaIndex: ... + @overload + def __add__( + self, other: TimedeltaSeries | Series[pd.Timedelta] + ) -> TimedeltaSeries: ... + @overload + def __add__( + self, other: Series[Timestamp] | TimestampSeries + ) -> TimestampSeries: ... + @overload + def __radd__(self, other: np.datetime64) -> Timestamp: ... + @overload + def __radd__(self, other: timedelta | Timedelta | np.timedelta64) -> Timedelta: ... + @overload + def __radd__(self, other: NaTType) -> NaTType: ... + @overload + def __radd__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.timedelta64]: ... + @overload + def __radd__( + self, other: npt.NDArray[np.datetime64] + ) -> npt.NDArray[np.datetime64]: ... + @overload + def __radd__(self, other: pd.TimedeltaIndex) -> pd.TimedeltaIndex: ... + @overload + def __radd__(self, other: pd.PeriodIndex) -> pd.PeriodIndex: ... + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] + def __sub__(self, other: timedelta | Timedelta | np.timedelta64) -> Timedelta: ... + @overload + def __sub__(self, other: NaTType) -> NaTType: ... + @overload + def __sub__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.timedelta64]: ... + @overload + def __sub__(self, other: pd.TimedeltaIndex) -> TimedeltaIndex: ... + @overload + def __sub__( + self, other: TimedeltaSeries | Series[pd.Timedelta] + ) -> TimedeltaSeries: ... + @overload + def __rsub__(self, other: timedelta | Timedelta | np.timedelta64) -> Timedelta: ... + @overload + def __rsub__(self, other: Timestamp | np.datetime64) -> Timestamp: ... + @overload + def __rsub__(self, other: NaTType) -> NaTType: ... + @overload + def __rsub__(self, other: Period) -> Period: ... + @overload + def __rsub__(self, other: PeriodIndex) -> PeriodIndex: ... + @overload + def __rsub__(self, other: DatetimeIndex) -> DatetimeIndex: ... + @overload + def __rsub__( + self, other: npt.NDArray[np.datetime64] + ) -> npt.NDArray[np.datetime64]: ... + @overload + def __rsub__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.timedelta64]: ... + @overload + def __rsub__(self, other: pd.TimedeltaIndex) -> pd.TimedeltaIndex: ... def __neg__(self) -> Timedelta: ... def __pos__(self) -> Timedelta: ... def __abs__(self) -> Timedelta: ... + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] def __mul__(self, other: float) -> Timedelta: ... + @overload + def __mul__( + self, other: npt.NDArray[np.integer] | npt.NDArray[np.floating] + ) -> npt.NDArray[np.timedelta64]: ... + @overload + def __mul__(self, other: Series[int]) -> TimedeltaSeries: ... + @overload + def __mul__(self, other: Series[float]) -> TimedeltaSeries: ... + @overload + def __mul__(self, other: Int64Index | Float64Index) -> TimedeltaIndex: ... + @overload def __rmul__(self, other: float) -> Timedelta: ... + @overload + def __rmul__(self, other: np.ndarray) -> np.ndarray: ... + @overload + def __rmul__(self, other: Series[int]) -> TimedeltaSeries: ... + @overload + def __rmul__(self, other: Series[float]) -> TimedeltaSeries: ... + @overload + def __rmul__(self, other: Int64Index | Float64Index) -> TimedeltaIndex: ... + # Override due to more types supported than dt.timedelta # error: Signature of "__floordiv__" incompatible with supertype "timedelta" @overload # type: ignore[override] - def __floordiv__(self, other: timedelta) -> int: ... + def __floordiv__(self, other: timedelta | Timedelta | np.timedelta64) -> int: ... @overload def __floordiv__(self, other: float) -> Timedelta: ... @overload + def __floordiv__( + self, other: npt.NDArray[np.integer] | npt.NDArray[np.floating] + ) -> npt.NDArray[np.timedelta64]: ... + @overload def __floordiv__( self, other: npt.NDArray[np.timedelta64] - ) -> npt.NDArray[np.intp]: ... + ) -> npt.NDArray[np.int_]: ... + @overload + def __floordiv__(self, other: Int64Index | Float64Index) -> TimedeltaIndex: ... + @overload + def __floordiv__(self, other: Series[int]) -> TimedeltaSeries: ... + @overload + def __floordiv__(self, other: Series[float]) -> TimedeltaSeries: ... @overload def __floordiv__( - self, other: npt.NDArray[np.number] - ) -> npt.NDArray[np.timedelta64] | Timedelta: ... + self, other: Series[Timedelta] | TimedeltaSeries + ) -> Series[int]: ... @overload - def __rfloordiv__(self, other: timedelta | str) -> int: ... + def __floordiv__(self, other: NaTType | None) -> float: ... @overload - def __rfloordiv__(self, other: NaTType | None) -> NaTType: ... + def __rfloordiv__(self, other: timedelta | Timedelta | str) -> int: ... @overload - def __rfloordiv__(self, other: np.ndarray) -> npt.NDArray[np.timedelta64]: ... + def __rfloordiv__(self, other: NaTType | None) -> float: ... @overload - def __truediv__(self, other: timedelta) -> float: ... + def __rfloordiv__( + self, other: npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.int_]: ... + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] + def __truediv__(self, other: timedelta | Timedelta | NaTType) -> float: ... @overload def __truediv__(self, other: float) -> Timedelta: ... + @overload + def __truediv__( + self, other: npt.NDArray[np.integer] | npt.NDArray[np.floating] + ) -> npt.NDArray[np.timedelta64]: ... + @overload + def __truediv__( + self, other: Series[Timedelta] | TimedeltaSeries + ) -> Series[float]: ... + @overload + def __truediv__(self, other: Series[int]) -> TimedeltaSeries: ... + @overload + def __truediv__(self, other: Series[float]) -> TimedeltaSeries: ... + @overload + def __truediv__(self, other: Int64Index | Float64Index) -> TimedeltaIndex: ... + def __rtruediv__(self, other: timedelta | Timedelta | NaTType) -> float: ... + # Override due to more types supported than dt.timedelta + @overload + def __eq__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] + @overload + def __eq__(self, other: TimedeltaSeries | Series[pd.Timedelta]) -> Series[bool]: ... # type: ignore[misc] + @overload + def __eq__( # type: ignore[misc] + self, other: TimedeltaIndex | npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.bool_]: ... + @overload + def __eq__(self, other: object) -> Literal[False]: ... + # Override due to more types supported than dt.timedelta + @overload + def __ne__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] + @overload + def __ne__(self, other: TimedeltaSeries | Series[pd.Timedelta]) -> Series[bool]: ... # type: ignore[misc] + @overload + def __ne__( # type: ignore[misc] + self, other: TimedeltaIndex | npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.bool_]: ... + @overload + def __ne__(self, other: object) -> Literal[True]: ... + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] def __mod__(self, other: timedelta) -> Timedelta: ... + @overload + def __mod__(self, other: float) -> Timedelta: ... + @overload + def __mod__(self, other: Series[int] | Series[float]) -> TimedeltaSeries: ... + @overload + def __mod__(self, other: Int64Index | Float64Index) -> TimedeltaIndex: ... + @overload + def __mod__( + self, other: npt.NDArray[np.integer] | npt.NDArray[np.floating] + ) -> npt.NDArray[np.timedelta64]: ... + @overload + def __mod__( + self, other: Series[int] | Series[float] | Series[Timedelta] | TimedeltaSeries + ) -> TimedeltaSeries: ... def __divmod__(self, other: timedelta) -> tuple[int, Timedelta]: ... - def __le__(self, other: timedelta) -> bool: ... - def __lt__(self, other: timedelta) -> bool: ... - def __ge__(self, other: timedelta) -> bool: ... - def __gt__(self, other: timedelta) -> bool: ... - def __hash__(self) -> int: ... + # Mypy complains Forward operator "" is not callable, so ignore misc + # for le, lt ge and gt + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] + def __le__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] + @overload + def __le__( + self, other: TimedeltaIndex | npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.bool_]: ... + @overload + def __le__(self, other: TimedeltaSeries | Series[pd.Timedelta]) -> Series[bool]: ... + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] + def __lt__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] + @overload + def __lt__( + self, other: TimedeltaIndex | npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.bool_]: ... + @overload + def __lt__(self, other: TimedeltaSeries | Series[pd.Timedelta]) -> Series[bool]: ... + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] + def __ge__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] + @overload + def __ge__( + self, other: TimedeltaIndex | npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.bool_]: ... + @overload + def __ge__(self, other: TimedeltaSeries | Series[pd.Timedelta]) -> Series[bool]: ... + # Override due to more types supported than dt.timedelta + @overload # type: ignore[override] + def __gt__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] + @overload + def __gt__( + self, other: TimedeltaIndex | npt.NDArray[np.timedelta64] + ) -> npt.NDArray[np.bool_]: ... + @overload + def __gt__(self, other: TimedeltaSeries | Series[pd.Timedelta]) -> Series[bool]: ... def isoformat(self) -> str: ... def to_numpy(self) -> np.timedelta64: ... + @property + def components(self) -> Components: ... + def view(self, dtype: npt.DTypeLike = ...) -> object: ... diff --git a/pandas-stubs/core/indexes/timedeltas.pyi b/pandas-stubs/core/indexes/timedeltas.pyi index f85145fc4..376d7fd86 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -1,9 +1,12 @@ +import datetime as dt from typing import ( Hashable, Literal, + Sequence, overload, ) +import numpy as np from pandas import ( DateOffset, Period, @@ -18,21 +21,25 @@ from pandas._libs import ( Timedelta, Timestamp, ) +from pandas._libs.tslibs import BaseOffset from pandas._typing import ( + AnyArrayLike, TimedeltaConvertibleTypes, num, ) class TimedeltaIndex(DatetimeTimedeltaMixin, TimedeltaIndexProperties): - def __new__( - cls, - data=..., - unit=..., - freq=..., - closed=..., - dtype=..., + def __init__( + self, + data: AnyArrayLike + | list[str] + | Sequence[dt.timedelta | Timedelta | np.timedelta64 | float] = ..., + unit: Literal["D", "h", "m", "s", "ms", "us", "ns"] = ..., + freq: str | BaseOffset = ..., + closed: object = ..., + dtype: Literal[" Series[int]: ... def __rsub__(self, other: num | _ListLike | Series[S1]) -> Series: ... @overload - def __rtruediv__(self, other: Timedelta | TimedeltaSeries) -> Series[float]: ... + def __rtruediv__(self, other: TimedeltaSeries) -> Series[float]: ... @overload def __rtruediv__(self, other: num | _ListLike | Series[S1]) -> Series: ... # ignore needed for mypy as we want different results based on the arguments @@ -1303,9 +1303,13 @@ class Series(IndexOpsMixin, NDFrame, Generic[S1]): ) -> TimedeltaSeries: ... @overload def __sub__( - self, other: Timedelta | TimedeltaSeries | TimedeltaIndex + self: Series[Timestamp], other: Timedelta | TimedeltaSeries | TimedeltaIndex ) -> TimestampSeries: ... @overload + def __sub__( + self: Series[Timedelta], other: Timedelta | TimedeltaSeries | TimedeltaIndex + ) -> TimedeltaSeries: ... + @overload def __sub__(self, other: num | _ListLike | Series) -> Series: ... @overload def __truediv__( @@ -1741,6 +1745,8 @@ class TimedeltaSeries(Series[Timedelta]): def __add__(self, other: Period) -> PeriodSeries: ... @overload def __add__(self, other: Timestamp | DatetimeIndex) -> TimestampSeries: ... + @overload + def __add__(self, other: Timedelta) -> TimedeltaSeries: ... def __radd__(self, pther: Timestamp | TimestampSeries) -> TimestampSeries: ... # type: ignore[override] def __mul__(self, other: num) -> TimedeltaSeries: ... # type: ignore[override] def __sub__( # type: ignore[override] diff --git a/tests/test_scalars.py b/tests/test_scalars.py index 799277d0c..5c788909d 100644 --- a/tests/test_scalars.py +++ b/tests/test_scalars.py @@ -4,13 +4,16 @@ from typing import ( TYPE_CHECKING, Any, + Literal, Optional, + cast, ) import dateutil.tz import numpy as np from numpy import typing as npt import pandas as pd +import pytest import pytz from typing_extensions import ( TypeAlias, @@ -21,8 +24,12 @@ BaseOffset, NaTType, ) +from pandas._libs.tslibs.timedeltas import Components -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) from pandas.tseries.offsets import Day @@ -38,12 +45,695 @@ else: np_ndarray_bool = npt.NDArray[np.bool_] - TimedeltaSeries = pd.Series - TimestampSeries = pd.Series + TimedeltaSeries: TypeAlias = pd.Series + TimestampSeries: TypeAlias = pd.Series PeriodSeries: TypeAlias = pd.Series OffsetSeries: TypeAlias = pd.Series +def test_timedelta_construction() -> None: + + check(assert_type(pd.Timedelta(1, "H"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "T"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "S"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "L"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "U"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "N"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "W"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "w"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "D"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "d"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "days"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "day"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "hours"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "hour"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "hr"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "h"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "m"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "minute"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "min"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "minutes"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "t"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "s"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "seconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "sec"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "second"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "ms"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "milliseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "millisecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "milli"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "millis"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "l"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "us"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "microseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "microsecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "µs"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "micro"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "micros"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "u"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "ns"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "nanoseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "nano"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "nanos"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "nanosecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(1, "n"), pd.Timedelta), pd.Timedelta) + + check(assert_type(pd.Timedelta("1 W"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 w"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 D"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 d"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 days"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 day"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 hours"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 hour"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 hr"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 h"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 m"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 minute"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 min"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 minutes"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 t"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 s"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 seconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 sec"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 second"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 ms"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 milliseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 millisecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 milli"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 millis"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 l"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 us"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 microseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 microsecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 µs"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 micro"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 micros"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 u"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 ns"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 nanoseconds"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 nano"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 nanos"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 nanosecond"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta("1 n"), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(days=1), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(seconds=1), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(microseconds=1), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(minutes=1), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(hours=1), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(weeks=1), pd.Timedelta), pd.Timedelta) + check(assert_type(pd.Timedelta(milliseconds=1), pd.Timedelta), pd.Timedelta) + check( + assert_type( + pd.Timedelta( + days=1, + seconds=1, + microseconds=1, + minutes=1, + hours=1, + weeks=1, + milliseconds=1, + ), + pd.Timedelta, + ), + pd.Timedelta, + ) + + +def test_timedelta_properties_methods() -> None: + td = pd.Timedelta("1 day") + check(assert_type(td.value, int), int) + check(assert_type(td.asm8, np.timedelta64), np.timedelta64) + + check(assert_type(td.days, int), int) + check(assert_type(td.microseconds, int), int) + check(assert_type(td.nanoseconds, int), int) + check(assert_type(td.seconds, int), int) + check(assert_type(td.value, int), int) + check(assert_type(td.resolution_string, str), str) + check(assert_type(td.components, Components), Components) + + check(assert_type(td.ceil("D"), pd.Timedelta), pd.Timedelta) + check(assert_type(td.floor(Day()), pd.Timedelta), pd.Timedelta) + check(assert_type(td.isoformat(), str), str) + check(assert_type(td.round("s"), pd.Timedelta), pd.Timedelta) + check(assert_type(td.to_numpy(), np.timedelta64), np.timedelta64) + check(assert_type(td.to_pytimedelta(), dt.timedelta), dt.timedelta) + check(assert_type(td.to_timedelta64(), np.timedelta64), np.timedelta64) + check(assert_type(td.total_seconds(), float), float) + check(assert_type(td.view(np.int64), object), np.int64) + check(assert_type(td.view("i8"), object), np.int64) + + +def test_timedelta_add_sub() -> None: + td = pd.Timedelta("1 day") + + ndarray_td64: npt.NDArray[np.timedelta64] = np.array( + [1, 2, 3], dtype="timedelta64[D]" + ) + ndarray_dt64: npt.NDArray[np.datetime64] = np.array( + [1, 2, 3], dtype="datetime64[D]" + ) + as_period = pd.Period("2012-01-01", freq="D") + as_timestamp = pd.Timestamp("2012-01-01") + as_datetime = dt.datetime(2012, 1, 1) + as_date = dt.date(2012, 1, 1) + as_datetime64 = np.datetime64(1, "ns") + as_dt_timedelta = dt.timedelta(days=1) + as_timedelta64 = np.timedelta64(1, "D") + as_timedelta_index = pd.TimedeltaIndex([td]) + as_timedelta_series = pd.Series(as_timedelta_index) + as_period_index = pd.period_range("2012-01-01", periods=3, freq="D") + as_datetime_index = pd.date_range("2012-01-01", periods=3) + as_ndarray_td64 = ndarray_td64 + as_ndarray_dt64 = ndarray_dt64 + as_nat = pd.NaT + + check(assert_type(td + td, pd.Timedelta), pd.Timedelta) + check(assert_type(td + as_period, pd.Period), pd.Period) + check(assert_type(td + as_timestamp, pd.Timestamp), pd.Timestamp) + check(assert_type(td + as_datetime, pd.Timestamp), pd.Timestamp) + check(assert_type(td + as_date, dt.date), dt.date) + check(assert_type(td + as_datetime64, pd.Timestamp), pd.Timestamp) + check(assert_type(td + as_dt_timedelta, pd.Timedelta), pd.Timedelta) + check(assert_type(td + as_timedelta64, pd.Timedelta), pd.Timedelta) + check(assert_type(td + as_timedelta_index, pd.TimedeltaIndex), pd.TimedeltaIndex) + check( + assert_type(td + as_timedelta_series, TimedeltaSeries), pd.Series, pd.Timedelta + ) + check(assert_type(td + as_period_index, pd.PeriodIndex), pd.PeriodIndex) + check(assert_type(td + as_datetime_index, pd.DatetimeIndex), pd.DatetimeIndex) + check( + assert_type(td + as_ndarray_td64, npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check( + assert_type(td + as_ndarray_dt64, npt.NDArray[np.datetime64]), + np.ndarray, + np.datetime64, + ) + check(assert_type(td + as_nat, NaTType), NaTType) + + check(assert_type(as_period + td, pd.Period), pd.Period) + check(assert_type(as_timestamp + td, pd.Timestamp), pd.Timestamp) + check(assert_type(as_datetime + td, dt.datetime), dt.datetime) + check(assert_type(as_date + td, dt.date), dt.date) + check(assert_type(as_datetime64 + td, pd.Timestamp), pd.Timestamp) + # pyright can't know that as_td_timedelta + td calls + # td.__radd__(as_td_timedelta), not timedelta.__add__ + # https://github.com/microsoft/pyright/issues/4088 + check( + assert_type( + as_dt_timedelta + td, # pyright: ignore[reportGeneralTypeIssues] + pd.Timedelta, + ), + pd.Timedelta, + ) + check(assert_type(as_timedelta64 + td, pd.Timedelta), pd.Timedelta) + check(assert_type(as_timedelta_index + td, pd.TimedeltaIndex), pd.TimedeltaIndex) + check( + assert_type(as_timedelta_series + td, TimedeltaSeries), pd.Series, pd.Timedelta + ) + check(assert_type(as_period_index + td, pd.PeriodIndex), pd.PeriodIndex) + check(assert_type(as_datetime_index + td, pd.DatetimeIndex), pd.DatetimeIndex) + check( + assert_type( + as_ndarray_td64 + td, + npt.NDArray[np.timedelta64], + ), + np.ndarray, + np.timedelta64, + ) + check(assert_type(as_nat + td, NaTType), NaTType) + + # sub is not symmetric with dates. In general date_like - timedelta is + # sensible, while timedelta - date_like is not + # TypeError: as_period, as_timestamp, as_datetime, as_date, as_datetime64, + # as_period_index, as_datetime_index, as_ndarray_dt64 + if TYPE_CHECKING_INVALID_USAGE: + td - as_period # type: ignore[operator] + td - as_timestamp # type: ignore[operator] + td - as_datetime # type: ignore[operator] + td - as_date # type: ignore[operator] + td - as_datetime64 # type: ignore[operator] + td - as_period_index # type: ignore[operator] + td - as_datetime_index # type: ignore[operator] + td - as_ndarray_dt64 # type: ignore[operator] + + check(assert_type(td - td, pd.Timedelta), pd.Timedelta) + check(assert_type(td - as_dt_timedelta, pd.Timedelta), pd.Timedelta) + check(assert_type(td - as_timedelta64, pd.Timedelta), pd.Timedelta) + check(assert_type(td - as_timedelta_index, pd.TimedeltaIndex), pd.TimedeltaIndex) + check( + assert_type(td - as_timedelta_series, TimedeltaSeries), pd.Series, pd.Timedelta + ) + check( + assert_type(td - as_ndarray_td64, npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check(assert_type(td - as_nat, NaTType), NaTType) + check(assert_type(as_period - td, pd.Period), pd.Period) + check(assert_type(as_timestamp - td, pd.Timestamp), pd.Timestamp) + check(assert_type(as_datetime - td, dt.datetime), dt.datetime) + check(assert_type(as_date - td, dt.date), dt.date) + check(assert_type(as_datetime64 - td, pd.Timestamp), pd.Timestamp) + # pyright can't know that as_dt_timedelta - td calls td.__rsub__(as_dt_timedelta), + # not as_dt_timedelta.__sub__ + # https://github.com/microsoft/pyright/issues/4088 + check( + assert_type( + as_dt_timedelta - td, # pyright: ignore[reportGeneralTypeIssues] + pd.Timedelta, + ), + pd.Timedelta, + ) + check(assert_type(as_timedelta64 - td, pd.Timedelta), pd.Timedelta) + check(assert_type(as_timedelta_index - td, pd.TimedeltaIndex), pd.TimedeltaIndex) + check( + assert_type(as_timedelta_series - td, TimedeltaSeries), pd.Series, pd.Timedelta + ) + check(assert_type(as_period_index - td, pd.PeriodIndex), pd.PeriodIndex) + check(assert_type(as_datetime_index - td, pd.DatetimeIndex), pd.DatetimeIndex) + check( + assert_type( + as_ndarray_td64 - td, + npt.NDArray[np.timedelta64], + ), + np.ndarray, + np.timedelta64, + ) + check( + assert_type( + as_ndarray_dt64 - td, + npt.NDArray[np.datetime64], + ), + np.ndarray, + np.datetime64, + ) + check(assert_type(as_nat - td, NaTType), NaTType) + + +def test_timedelta_mul_div() -> None: + td = pd.Timedelta("1 day") + + with pytest.warns(FutureWarning): + i_idx = cast(pd.Int64Index, pd.Index([1, 2, 3], dtype=int)) + f_idx = cast(pd.Float64Index, pd.Index([1.2, 2.2, 3.4], dtype=float)) + + np_intp_arr: npt.NDArray[np.integer] = np.array([1, 2, 3]) + np_float_arr: npt.NDArray[np.floating] = np.array([1.2, 2.2, 3.4]) + + md_int = 3 + md_float = 3.5 + md_ndarray_intp = np_intp_arr + md_ndarray_float = np_float_arr + mp_series_int = pd.Series([1, 2, 3], dtype=int) + md_series_float = pd.Series([1.2, 2.2, 3.4], dtype=float) + md_int64_index = i_idx + md_float_index = f_idx + md_timedelta_series = pd.Series(pd.timedelta_range("1 day", periods=3)) + + check(assert_type(td * md_int, pd.Timedelta), pd.Timedelta) + check(assert_type(td * md_float, pd.Timedelta), pd.Timedelta) + check( + assert_type(td * md_ndarray_intp, npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check( + assert_type(td * md_ndarray_float, npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check(assert_type(td * mp_series_int, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(td * md_series_float, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(td * md_int64_index, pd.TimedeltaIndex), pd.TimedeltaIndex) + check(assert_type(td * md_float_index, pd.TimedeltaIndex), pd.TimedeltaIndex) + + check(assert_type(md_int * td, pd.Timedelta), pd.Timedelta) + check(assert_type(md_float * td, pd.Timedelta), pd.Timedelta) + check(assert_type(md_ndarray_intp * td, np.ndarray), np.ndarray, np.timedelta64) + check(assert_type(md_ndarray_float * td, np.ndarray), np.ndarray, np.timedelta64) + check(assert_type(mp_series_int * td, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(md_series_float * td, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(md_int64_index * td, pd.TimedeltaIndex), pd.TimedeltaIndex) + check(assert_type(md_float_index * td, pd.TimedeltaIndex), pd.TimedeltaIndex) + + check(assert_type(td // td, int), int) + check(assert_type(td // pd.NaT, float), float) + check(assert_type(td // md_int, pd.Timedelta), pd.Timedelta) + check(assert_type(td // md_float, pd.Timedelta), pd.Timedelta) + check( + assert_type(td // md_ndarray_intp, npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check( + assert_type(td // md_ndarray_float, npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check(assert_type(td // mp_series_int, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(td // md_series_float, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(td // md_int64_index, pd.TimedeltaIndex), pd.TimedeltaIndex) + check(assert_type(td // md_float_index, pd.TimedeltaIndex), pd.TimedeltaIndex) + check(assert_type(td // md_timedelta_series, "pd.Series[int]"), pd.Series, int) + + check(assert_type(pd.NaT // td, float), float) + # Note: None of the reverse floordiv work + # TypeError: md_int, md_float, md_ndarray_intp, md_ndarray_float, mp_series_int, + # mp_series_float, md_int64_index, md_float_index + if TYPE_CHECKING_INVALID_USAGE: + md_int // td # type: ignore[operator] + md_float // td # type: ignore[operator] + md_ndarray_intp // td # type: ignore[operator] + md_ndarray_float // td # type: ignore[operator] + mp_series_int // td # type: ignore[operator] + md_series_float // td # type: ignore[operator] + md_int64_index // td # type: ignore[operator] + md_float_index // td # type: ignore[operator] + + check(assert_type(td / td, float), float) + check(assert_type(td / pd.NaT, float), float) + check(assert_type(td / md_int, pd.Timedelta), pd.Timedelta) + check(assert_type(td / md_float, pd.Timedelta), pd.Timedelta) + check( + assert_type(td / md_ndarray_intp, npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check( + assert_type(td / md_ndarray_float, npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check(assert_type(td / mp_series_int, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(td / md_series_float, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(td / md_int64_index, pd.TimedeltaIndex), pd.TimedeltaIndex) + check(assert_type(td / md_float_index, pd.TimedeltaIndex), pd.TimedeltaIndex) + check(assert_type(td / md_timedelta_series, "pd.Series[float]"), pd.Series, float) + + check(assert_type(pd.NaT / td, float), float) + # Note: None of the reverse truediv work + # TypeError: md_int, md_float, md_ndarray_intp, md_ndarray_float, mp_series_int, + # mp_series_float, md_int64_index, md_float_index + if TYPE_CHECKING_INVALID_USAGE: + md_int / td # type: ignore[operator] + md_float / td # type: ignore[operator] + md_ndarray_intp / td # type: ignore[operator] + md_ndarray_float / td # type: ignore[operator] + # TODO: Series.__truediv__ says it supports Timedelta + # it does not, in general, except for TimedeltaSeries + # mp_series_int / td # type: ignore[operator] + # mp_series_float / td # type: ignore[operator] + md_int64_index / td # type: ignore[operator] + md_float_index / td # type: ignore[operator] + + +def test_timedelta_mod_abs_unary() -> None: + td = pd.Timedelta("1 day") + + with pytest.warns(FutureWarning): + i_idx = cast(pd.Int64Index, pd.Index([1, 2, 3], dtype=int)) + f_idx = cast(pd.Float64Index, pd.Index([1.2, 2.2, 3.4], dtype=float)) + + check(assert_type(td % 3, pd.Timedelta), pd.Timedelta) + check(assert_type(td % 3.5, pd.Timedelta), pd.Timedelta) + check(assert_type(td % td, pd.Timedelta), pd.Timedelta) + check( + assert_type(td % np.array([1, 2, 3]), npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + check( + assert_type(td % np.array([1.2, 2.2, 3.4]), npt.NDArray[np.timedelta64]), + np.ndarray, + np.timedelta64, + ) + int_series = pd.Series([1, 2, 3], dtype=int) + float_series = pd.Series([1.2, 2.2, 3.4], dtype=float) + check(assert_type(td % int_series, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(td % float_series, TimedeltaSeries), pd.Series, pd.Timedelta) + check(assert_type(td % i_idx, pd.TimedeltaIndex), pd.TimedeltaIndex) + + check( + assert_type(td % f_idx, pd.TimedeltaIndex), + pd.TimedeltaIndex, + ) + + # mypy reports dt.timedelta, even though __abs__ returns Timedelta + check(assert_type(abs(td), pd.Timedelta), pd.Timedelta) # type: ignore[assert-type] + check(assert_type(td.__abs__(), pd.Timedelta), pd.Timedelta) + check(assert_type(-td, pd.Timedelta), pd.Timedelta) + check(assert_type(+td, pd.Timedelta), pd.Timedelta) + + +def test_timedelta_cmp() -> None: + td = pd.Timedelta("1 day") + ndarray_td64: npt.NDArray[np.timedelta64] = np.array( + [1, 2, 3], dtype="timedelta64[D]" + ) + c_timedelta = td + c_dt_timedelta = dt.timedelta(days=1) + c_timedelta64 = np.timedelta64(1, "D") + c_ndarray_td64 = ndarray_td64 + c_timedelta_index = pd.TimedeltaIndex([1, 2, 3], unit="D") + c_timedelta_series = pd.Series(pd.TimedeltaIndex([1, 2, 3])) + + check(assert_type(td < c_timedelta, bool), bool) + check(assert_type(td < c_dt_timedelta, bool), bool) + check(assert_type(td < c_timedelta64, bool), bool) + check(assert_type(td < c_ndarray_td64, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_timedelta_index < td, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_dt_timedelta < td, bool), bool) + check(assert_type(c_ndarray_td64 < td, np_ndarray_bool), np.ndarray, np.bool_) + check(assert_type(c_timedelta_index < td, np_ndarray_bool), np.ndarray, np.bool_) + + gt = check(assert_type(td > c_timedelta, bool), bool) + le = check(assert_type(td <= c_timedelta, bool), bool) + assert gt != le + + gt = check(assert_type(td > c_dt_timedelta, bool), bool) + le = check(assert_type(td <= c_dt_timedelta, bool), bool) + assert gt != le + + gt = check(assert_type(td > c_timedelta64, bool), bool) + le = check(assert_type(td <= c_timedelta64, bool), bool) + assert gt != le + + gt_a = check( + assert_type(td > c_ndarray_td64, np_ndarray_bool), np.ndarray, np.bool_ + ) + le_a = check( + assert_type(td <= c_ndarray_td64, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (gt_a != le_a).all() + + gt_a = check( + assert_type(td > c_timedelta_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + le_a = check( + assert_type(td <= c_timedelta_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (gt_a != le_a).all() + + gt_s = check( + assert_type(td > c_timedelta_series, "pd.Series[bool]"), pd.Series, bool + ) + le_s = check( + assert_type(td <= c_timedelta_series, "pd.Series[bool]"), pd.Series, bool + ) + assert (gt_s != le_s).all() + + gt = check(assert_type(c_dt_timedelta > td, bool), bool) + le = check(assert_type(c_dt_timedelta <= td, bool), bool) + assert gt != le + + gt_b = check(assert_type(c_timedelta64 > td, Any), np.bool_) + le_b = check(assert_type(c_timedelta64 <= td, Any), np.bool_) + assert gt_b != le_b + + gt_a = check( + assert_type(c_ndarray_td64 > td, np_ndarray_bool), np.ndarray, np.bool_ + ) + le_a = check( + assert_type(c_ndarray_td64 <= td, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (gt_a != le_a).all() + + gt_a = check( + assert_type(c_timedelta_index > td, np_ndarray_bool), np.ndarray, np.bool_ + ) + le_a = check( + assert_type(c_timedelta_index <= td, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (gt_a != le_a).all() + + eq_s = check( + assert_type(c_timedelta_series > td, "pd.Series[bool]"), pd.Series, bool + ) + ne_s = check( + assert_type(c_timedelta_series <= td, "pd.Series[bool]"), pd.Series, bool + ) + assert (eq_s != ne_s).all() + + lt = check(assert_type(td < c_timedelta, bool), bool) + ge = check(assert_type(td >= c_timedelta, bool), bool) + assert lt != ge + + lt = check(assert_type(td < c_dt_timedelta, bool), bool) + ge = check(assert_type(td >= c_dt_timedelta, bool), bool) + assert lt != ge + + lt = check(assert_type(td < c_timedelta64, bool), bool) + ge = check(assert_type(td >= c_timedelta64, bool), bool) + assert lt != ge + + lt_a = check( + assert_type(td < c_ndarray_td64, np_ndarray_bool), np.ndarray, np.bool_ + ) + ge_a = check( + assert_type(td >= c_ndarray_td64, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (lt_a != ge_a).all() + + lt_a = check( + assert_type(td < c_timedelta_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + ge_a = check( + assert_type(td >= c_timedelta_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (lt_a != ge_a).all() + + eq_s = check( + assert_type(td < c_timedelta_series, "pd.Series[bool]"), pd.Series, bool + ) + ne_s = check( + assert_type(td >= c_timedelta_series, "pd.Series[bool]"), pd.Series, bool + ) + assert (eq_s != ne_s).all() + + lt = check(assert_type(c_dt_timedelta < td, bool), bool) + ge = check(assert_type(c_dt_timedelta >= td, bool), bool) + assert lt != ge + + lt_b = check(assert_type(c_timedelta64 < td, Any), np.bool_) + ge_b = check(assert_type(c_timedelta64 >= td, Any), np.bool_) + assert lt_b != ge_b + + lt_a = check( + assert_type(c_ndarray_td64 < td, np_ndarray_bool), np.ndarray, np.bool_ + ) + ge_a = check( + assert_type(c_ndarray_td64 >= td, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (lt_a != ge_a).all() + + lt_a = check( + assert_type(c_timedelta_index < td, np_ndarray_bool), np.ndarray, np.bool_ + ) + ge_a = check( + assert_type(c_timedelta_index >= td, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (lt_a != ge_a).all() + + eq_s = check( + assert_type(c_timedelta_series < td, "pd.Series[bool]"), pd.Series, bool + ) + ne_s = check( + assert_type(c_timedelta_series >= td, "pd.Series[bool]"), pd.Series, bool + ) + assert (eq_s != ne_s).all() + + eq = check(assert_type(td == td, bool), bool) + ne = check(assert_type(td != td, bool), bool) + assert eq != ne + + eq = check(assert_type(td == c_dt_timedelta, bool), bool) + ne = check(assert_type(td != c_dt_timedelta, bool), bool) + assert eq != ne + + eq = check(assert_type(td == c_timedelta64, bool), bool) + ne = check(assert_type(td != c_timedelta64, bool), bool) + assert eq != ne + + eq_a = check( + assert_type(td == c_ndarray_td64, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_a = check( + assert_type(td != c_ndarray_td64, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_a != ne_a).all() + + eq_a = check( + assert_type(td == c_timedelta_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_a = check( + assert_type(td != c_timedelta_index, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_a != ne_a).all() + + eq_s = check( + assert_type(td == c_timedelta_series, "pd.Series[bool]"), pd.Series, bool + ) + ne_s = check( + assert_type(td != c_timedelta_series, "pd.Series[bool]"), pd.Series, bool + ) + assert (eq_s != ne_s).all() + + eq = check(assert_type(td == 1, Literal[False]), bool) + ne = check(assert_type(td != 1, Literal[True]), bool) + assert eq != ne + + eq = check(assert_type(td == (3 + 2j), Literal[False]), bool) + ne = check(assert_type(td != (3 + 2j), Literal[True]), bool) + assert eq != ne + + +def test_timedelta_cmp_rhs() -> None: + # Test that check eq and ne when Timedelta is the RHS argument + # that use the __eq__ and __ne__ methods of the LHS + td = pd.Timedelta("1 day") + ndarray_td64: npt.NDArray[np.timedelta64] = np.array( + [1, 2, 3], dtype="timedelta64[D]" + ) + c_dt_timedelta = dt.timedelta(days=1) + c_timedelta64 = np.timedelta64(1, "D") + c_ndarray_td64 = ndarray_td64 + c_timedelta_index = pd.TimedeltaIndex([1, 2, 3], unit="D") + c_timedelta_series = pd.Series(pd.TimedeltaIndex([1, 2, 3])) + + eq = check(assert_type(c_dt_timedelta == td, bool), bool) + ne = check(assert_type(c_dt_timedelta != td, bool), bool) + assert eq != ne + + eq = check(assert_type(c_timedelta64 == td, Any), np.bool_) + ne = check(assert_type(c_timedelta64 != td, Any), np.bool_) + assert eq != ne + + eq_a = check(assert_type(c_ndarray_td64 == td, Any), np.ndarray, np.bool_) + ne_a = check(assert_type(c_ndarray_td64 != td, Any), np.ndarray, np.bool_) + assert (eq_a != ne_a).all() + + eq_a = check( + assert_type(c_timedelta_index == td, np_ndarray_bool), np.ndarray, np.bool_ + ) + ne_a = check( + assert_type(c_timedelta_index != td, np_ndarray_bool), np.ndarray, np.bool_ + ) + assert (eq_a != ne_a).all() + + eq_s = check( + assert_type(c_timedelta_series == td, "pd.Series[bool]"), pd.Series, bool + ) + ne_s = check( + assert_type(c_timedelta_series != td, "pd.Series[bool]"), pd.Series, bool + ) + assert (eq_s != ne_s).all() + + def test_timestamp_construction() -> None: check(assert_type(pd.Timestamp("2000-1-1"), pd.Timestamp), pd.Timestamp) @@ -160,7 +850,7 @@ def test_timestamp_add_sub() -> None: as_offset = 3 * Day() as_timedelta_index = pd.TimedeltaIndex([1, 2, 3], "D") as_timedelta_series = pd.Series(as_timedelta_index) - check(assert_type(as_timedelta_series, TimedeltaSeries), pd.Series) + check(assert_type(as_timedelta_series, TimedeltaSeries), pd.Series, pd.Timedelta) as_np_ndarray_td64 = np_td64_arr check(assert_type(ts + as_pd_timedelta, pd.Timestamp), pd.Timestamp) @@ -714,9 +1404,9 @@ def test_period_add_subtract() -> None: as_period = pd.Period("2012-1-1", freq="D") scale = 24 * 60 * 60 * 10**9 as_td_series = pd.Series(pd.timedelta_range(scale, scale, freq="D")) - check(assert_type(as_td_series, TimedeltaSeries), pd.Series) + check(assert_type(as_td_series, TimedeltaSeries), pd.Series, pd.Timedelta) as_period_series = pd.Series(as_period_index) - check(assert_type(as_period_series, PeriodSeries), pd.Series) + check(assert_type(as_period_series, PeriodSeries), pd.Series, pd.Period) as_timedelta_idx = pd.timedelta_range(scale, scale, freq="D") as_nat = pd.NaT