diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index ca81fff38..0c72514b2 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -280,7 +280,7 @@ class ElementOpsMixin(Generic[S2]): ) -> ElementOpsMixin[complex]: ... @overload def _proto_truediv( - self: ElementOpsMixin[Timedelta], other: timedelta | Timedelta | np.timedelta64 + self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta ) -> ElementOpsMixin[float]: ... @overload def _proto_rtruediv( @@ -296,8 +296,32 @@ class ElementOpsMixin(Generic[S2]): ) -> ElementOpsMixin[complex]: ... @overload def _proto_rtruediv( - self: ElementOpsMixin[Timedelta], other: timedelta | Timedelta | np.timedelta64 + self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta ) -> ElementOpsMixin[float]: ... + @overload + def _proto_floordiv( + self: ElementOpsMixin[int], other: int | np.integer + ) -> ElementOpsMixin[int]: ... + @overload + def _proto_floordiv( + self: ElementOpsMixin[float], other: float | np.floating + ) -> ElementOpsMixin[float]: ... + @overload + def _proto_floordiv( + self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta + ) -> ElementOpsMixin[int]: ... + @overload + def _proto_rfloordiv( + self: ElementOpsMixin[int], other: int | np.integer + ) -> ElementOpsMixin[int]: ... + @overload + def _proto_rfloordiv( + self: ElementOpsMixin[float], other: float | np.floating + ) -> ElementOpsMixin[float]: ... + @overload + def _proto_rfloordiv( + self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta + ) -> ElementOpsMixin[int]: ... @type_check_only class Supports_ProtoAdd(Protocol[_T_contra, S2]): @@ -322,3 +346,11 @@ class Supports_ProtoTrueDiv(Protocol[_T_contra, S2]): @type_check_only class Supports_ProtoRTrueDiv(Protocol[_T_contra, S2]): def _proto_rtruediv(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... + +@type_check_only +class Supports_ProtoFloorDiv(Protocol[_T_contra, S2]): + def _proto_floordiv(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... + +@type_check_only +class Supports_ProtoRFloorDiv(Protocol[_T_contra, S2]): + def _proto_rfloordiv(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 40129638a..a0e8f9a06 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -28,36 +28,37 @@ from _typeshed import ( _T_contra, ) import numpy as np -from pandas import ( - DataFrame, - DatetimeIndex, - Interval, - IntervalIndex, - MultiIndex, - Period, - PeriodDtype, - PeriodIndex, - Series, - TimedeltaIndex, -) from pandas.core.base import ( ElementOpsMixin, IndexOpsMixin, Supports_ProtoAdd, + Supports_ProtoFloorDiv, Supports_ProtoMul, Supports_ProtoRAdd, + Supports_ProtoRFloorDiv, Supports_ProtoRMul, Supports_ProtoRTrueDiv, Supports_ProtoTrueDiv, ) +from pandas.core.frame import DataFrame from pandas.core.indexes.category import CategoricalIndex +from pandas.core.indexes.datetimes import DatetimeIndex +from pandas.core.indexes.interval import IntervalIndex +from pandas.core.indexes.multi import MultiIndex +from pandas.core.indexes.period import PeriodIndex +from pandas.core.indexes.timedeltas import TimedeltaIndex +from pandas.core.series import Series from pandas.core.strings.accessor import StringMethods from typing_extensions import ( Never, Self, ) -from pandas._libs.interval import _OrderableT +from pandas._libs.interval import ( + Interval, + _OrderableT, +) +from pandas._libs.tslibs.period import Period from pandas._libs.tslibs.timedeltas import Timedelta from pandas._typing import ( C2, @@ -92,6 +93,7 @@ from pandas._typing import ( TimedeltaDtypeArg, TimestampDtypeArg, np_1darray, + np_ndarray, np_ndarray_anyint, np_ndarray_bool, np_ndarray_complex, @@ -102,6 +104,8 @@ from pandas._typing import ( type_t, ) +from pandas.core.dtypes.dtypes import PeriodDtype + class InvalidIndexError(Exception): ... class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @@ -894,14 +898,17 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @overload def __truediv__(self: Index[bool], other: np_ndarray_bool) -> Never: ... @overload + def __truediv__(self, other: np_ndarray_dt) -> Never: ... + @overload + def __truediv__(self: Index[T_COMPLEX], other: np_ndarray_td) -> Never: ... + @overload def __truediv__( self: Supports_ProtoTrueDiv[_T_contra, S2], other: _T_contra | Sequence[_T_contra], ) -> Index[S2]: ... @overload def __truediv__( - self: Index[int], - other: np_ndarray_bool | Index[bool], + self: Index[int], other: np_ndarray_bool | Index[bool] ) -> Index[float]: ... @overload def __truediv__( @@ -945,10 +952,12 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): self: Index[Never], other: complex | ArrayLike | SequenceNotStr[S1] | Index ) -> Index: ... @overload - def __rtruediv__(self, other: Index[Never]) -> Index: ... + def __rtruediv__(self, other: Index[Never]) -> Index: ... # type: ignore[overload-overlap] @overload def __rtruediv__(self: Index[bool], other: np_ndarray_bool) -> Never: ... @overload + def __rtruediv__(self, other: np_ndarray_dt) -> Never: ... + @overload def __rtruediv__( self: Supports_ProtoRTrueDiv[_T_contra, S2], other: _T_contra | Sequence[_T_contra], @@ -993,13 +1002,121 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ), ) -> Index[complex]: ... @overload + def __rtruediv__( + self: Index[int] | Index[float], + other: timedelta | np.timedelta64 | np_ndarray_td | TimedeltaIndex, + ) -> TimedeltaIndex: ... + @overload def __rtruediv__(self, other: Path) -> Index: ... + @overload def __floordiv__( - self, other: float | Sequence[float] | Index[int] | Index[float] - ) -> Self: ... + self: Index[Never], + other: ( + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + ), + ) -> Index: ... + @overload + def __floordiv__( + self: Index[bool] | Index[int] | Index[float], other: Index[Never] + ) -> Index: ... + @overload + def __floordiv__( + self: Index[int] | Index[float], + other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + ) -> Never: ... + @overload + def __floordiv__( + self: Index[bool] | Index[complex], other: np_ndarray + ) -> Never: ... + @overload + def __floordiv__( + self: Supports_ProtoFloorDiv[_T_contra, S2], + other: _T_contra | Sequence[_T_contra], + ) -> Index[S2]: ... + @overload + def __floordiv__( + self: Index[int], other: np_ndarray_bool | Index[bool] + ) -> Index[int]: ... + @overload + def __floordiv__( + self: Index[float], other: np_ndarray_bool | Index[bool] + ) -> Index[float]: ... + @overload + def __floordiv__( + self: Index[bool] | Index[int], other: np_ndarray_anyint | Index[int] + ) -> Index[int]: ... + @overload + def __floordiv__( + self: Index[float], other: np_ndarray_anyint | Index[int] + ) -> Index[float]: ... + @overload + def __floordiv__( + self: Index[int] | Index[float], + other: float | Sequence[float] | np_ndarray_float | Index[float], + ) -> Index[float]: ... + @overload def __rfloordiv__( - self, other: float | Sequence[float] | Index[int] | Index[float] - ) -> Self: ... + self: Index[Never], + other: ( + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + ), + ) -> Index: ... + @overload + def __rfloordiv__(self: Index[bool] | Index[int] | Index[float], other: Index[Never]) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rfloordiv__( + self: Index[int] | Index[float], + other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + ) -> Never: ... + @overload + def __rfloordiv__( + self: Index[bool] | Index[complex], other: np_ndarray + ) -> Never: ... + @overload + def __rfloordiv__( + self: Supports_ProtoRFloorDiv[_T_contra, S2], + other: _T_contra | Sequence[_T_contra], + ) -> Index[S2]: ... + @overload + def __rfloordiv__( + self: Index[int], other: np_ndarray_bool | Index[bool] + ) -> Index[int]: ... + @overload + def __rfloordiv__( + self: Index[float], other: np_ndarray_bool | Index[bool] + ) -> Index[float]: ... + @overload + def __rfloordiv__( + self: Index[bool] | Index[int], other: np_ndarray_anyint | Index[int] + ) -> Index[int]: ... + @overload + def __rfloordiv__( + self: Index[float], other: np_ndarray_anyint | Index[int] + ) -> Index[float]: ... + @overload + def __rfloordiv__( + self: Index[int] | Index[float], + other: float | Sequence[float] | np_ndarray_float | Index[float], + ) -> Index[float]: ... + @overload + def __rfloordiv__( + self: Index[int] | Index[float], + other: timedelta | np_ndarray_td | TimedeltaIndex, + ) -> TimedeltaIndex: ... def infer_objects(self, copy: bool = True) -> Self: ... @type_check_only diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 4ff9bc44f..bd504096e 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -14,17 +14,18 @@ from typing import ( ) import numpy as np -from pandas import ( - DataFrame, - Index, - TimedeltaIndex, - Timestamp, -) +from pandas.core.frame import DataFrame from pandas.core.indexes.accessors import DatetimeIndexProperties +from pandas.core.indexes.base import Index from pandas.core.indexes.datetimelike import DatetimeTimedeltaMixin +from pandas.core.indexes.timedeltas import TimedeltaIndex from pandas.core.series import Series -from typing_extensions import Self +from typing_extensions import ( + Never, + Self, +) +from pandas._libs.tslibs.timestamps import Timestamp from pandas._typing import ( AxesData, DateAndDatetimeLike, @@ -34,6 +35,7 @@ from pandas._typing import ( TimeUnit, TimeZones, np_1darray, + np_ndarray, np_ndarray_dt, np_ndarray_td, ) @@ -63,18 +65,23 @@ class DatetimeIndex( def __add__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] self, other: timedelta | BaseOffset ) -> Self: ... - def __radd__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def __radd__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] self, other: timedelta | BaseOffset ) -> Self: ... @overload # type: ignore[override] - # pyrefly: ignore # bad-override - def __sub__( + def __sub__( # pyrefly: ignore[bad-override] self, other: datetime | np.datetime64 | np_ndarray_dt | Self ) -> TimedeltaIndex: ... @overload def __sub__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: timedelta | np.timedelta64 | np_ndarray_td | BaseOffset ) -> Self: ... + def __truediv__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override] + self, other: np_ndarray + ) -> Never: ... + def __rtruediv__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override] + self, other: np_ndarray + ) -> Never: ... @final def to_series( self, index: Index | None = None, name: Hashable | None = None diff --git a/pandas-stubs/core/indexes/timedeltas.pyi b/pandas-stubs/core/indexes/timedeltas.pyi index dd1a8b189..2f632cd8a 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -2,7 +2,10 @@ from collections.abc import ( Hashable, Sequence, ) -import datetime as dt +from datetime import ( + datetime, + timedelta, +) from typing import ( Literal, TypeAlias, @@ -36,7 +39,6 @@ from pandas._typing import ( np_ndarray_dt, np_ndarray_float, np_ndarray_td, - num, ) _NUM_FACTOR: TypeAlias = Just[int] | Just[float] | np.integer | np.floating @@ -48,7 +50,7 @@ _NUM_FACTOR_SEQ: TypeAlias = ( | Index[int] | Index[float] ) -_DT_FACTOR: TypeAlias = dt.timedelta | np.timedelta64 | Timedelta +_DT_FACTOR: TypeAlias = timedelta | np.timedelta64 | Timedelta _DT_FACTOR_SEQ: TypeAlias = _DT_FACTOR | Sequence[_DT_FACTOR] | np_ndarray_td class TimedeltaIndex( @@ -56,9 +58,7 @@ class TimedeltaIndex( ): def __new__( cls, - data: ( - Sequence[dt.timedelta | Timedelta | np.timedelta64 | float] | AxesData - ) = ..., + data: Sequence[timedelta | Timedelta | np.timedelta64 | float] | AxesData = ..., freq: Frequency = ..., closed: object = ..., dtype: Literal[" PeriodIndex: ... @overload - def __add__(self, other: dt.datetime | DatetimeIndex) -> DatetimeIndex: ... + def __add__(self, other: datetime | DatetimeIndex) -> DatetimeIndex: ... @overload def __add__( # pyright: ignore[reportIncompatibleMethodOverride] - self, other: dt.timedelta | Self + self, other: timedelta | Self ) -> Self: ... @overload # type: ignore[override] # pyrefly: ignore # bad-override def __radd__(self, other: Period) -> PeriodIndex: ... @overload - def __radd__(self, other: dt.datetime | DatetimeIndex) -> DatetimeIndex: ... + def __radd__(self, other: datetime | DatetimeIndex) -> DatetimeIndex: ... @overload def __radd__( # pyright: ignore[reportIncompatibleMethodOverride] - self, other: dt.timedelta | Self + self, other: timedelta | Self ) -> Self: ... def __sub__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - self, other: dt.timedelta | np.timedelta64 | np_ndarray_td | BaseOffset | Self + self, other: timedelta | np.timedelta64 | np_ndarray_td | BaseOffset | Self ) -> Self: ... @overload # type: ignore[override] # pyrefly: ignore # bad-override def __rsub__( - self, other: dt.timedelta | np.timedelta64 | np_ndarray_td | BaseOffset | Self + self, other: timedelta | np.timedelta64 | np_ndarray_td | BaseOffset | Self ) -> Self: ... @overload def __rsub__( # pyright: ignore[reportIncompatibleMethodOverride] - self, other: dt.datetime | np.datetime64 | np_ndarray_dt | DatetimeIndex + self, other: datetime | np.datetime64 | np_ndarray_dt | DatetimeIndex ) -> DatetimeIndex: ... @overload # type: ignore[override] def __mul__(self, other: np_ndarray_bool | np_ndarray_complex) -> Never: ... @@ -124,13 +124,30 @@ class TimedeltaIndex( self, other: _DT_FACTOR_SEQ | Self ) -> Index[float]: ... @overload # type: ignore[override] - # pyrefly: ignore # bad-override - def __floordiv__(self, other: num | Sequence[float]) -> Self: ... + def __floordiv__( # pyrefly: ignore [bad-override] + self, other: np_ndarray_bool | np_ndarray_complex | np_ndarray_dt + ) -> Never: ... + @overload + def __floordiv__(self, other: _NUM_FACTOR_SEQ) -> Self: ... @overload def __floordiv__( # pyright: ignore[reportIncompatibleMethodOverride] - self, other: dt.timedelta | Sequence[dt.timedelta] + self, other: _DT_FACTOR_SEQ | Self + ) -> Index[int]: ... + @overload + def __rfloordiv__( # pyrefly: ignore[bad-override] + self, + other: ( + np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | np_ndarray_complex + | np_ndarray_dt + ), + ) -> Never: ... + @overload + def __rfloordiv__( # pyright: ignore[reportIncompatibleMethodOverride] + self, other: _DT_FACTOR_SEQ | Self ) -> Index[int]: ... - def __rfloordiv__(self, other: dt.timedelta | Sequence[dt.timedelta]) -> Index[int]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] @property def inferred_type(self) -> str: ... @final @@ -138,7 +155,7 @@ class TimedeltaIndex( self, index: Index | None = None, name: Hashable | None = None ) -> Series[Timedelta]: ... def shift( - self, periods: int = 1, freq: Frequency | dt.timedelta | None = None + self, periods: int = 1, freq: Frequency | timedelta | None = None ) -> Self: ... @overload @@ -146,7 +163,7 @@ def timedelta_range( start: TimedeltaConvertibleTypes, end: TimedeltaConvertibleTypes, *, - freq: Frequency | Timedelta | dt.timedelta | None = None, + freq: Frequency | Timedelta | timedelta | None = None, name: Hashable | None = None, closed: Literal["left", "right"] | None = None, unit: None | str = ..., @@ -156,7 +173,7 @@ def timedelta_range( *, end: TimedeltaConvertibleTypes, periods: int, - freq: Frequency | Timedelta | dt.timedelta | None = None, + freq: Frequency | Timedelta | timedelta | None = None, name: Hashable | None = None, closed: Literal["left", "right"] | None = None, unit: None | str = ..., @@ -166,7 +183,7 @@ def timedelta_range( start: TimedeltaConvertibleTypes, *, periods: int, - freq: Frequency | Timedelta | dt.timedelta | None = None, + freq: Frequency | Timedelta | timedelta | None = None, name: Hashable | None = None, closed: Literal["left", "right"] | None = None, unit: None | str = ..., diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 30f9722b7..4361586f1 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -69,8 +69,10 @@ from pandas.core.base import ( IndexOpsMixin, NumListLike, Supports_ProtoAdd, + Supports_ProtoFloorDiv, Supports_ProtoMul, Supports_ProtoRAdd, + Supports_ProtoRFloorDiv, Supports_ProtoRMul, Supports_ProtoRTrueDiv, Supports_ProtoTrueDiv, @@ -2141,19 +2143,38 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[_str]: ... # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] - # pyrefly: ignore # bad-override - def __and__( # pyright: ignore[reportOverlappingOverload] + def __and__( # pyright: ignore[reportOverlappingOverload] # pyrefly: ignore[bad-override] self, other: bool | list[int] | MaskType ) -> Series[bool]: ... @overload def __and__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... def __eq__(self, other: object) -> Series[_bool]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] @overload - def __floordiv__(self, other: Index[Never] | Series[Never]) -> Series: ... + def __floordiv__( # type: ignore[overload-overlap] + self: Series[Never], + other: ( + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + | Series[bool] + | Series[int] + | Series[float] + ), + ) -> Series: ... + @overload + def __floordiv__( + self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], + other: Index[Never] | Series[Never], + ) -> Series: ... @overload def __floordiv__( self: Series[int] | Series[float], - other: np_ndarray_bool | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, ) -> Never: ... @overload def __floordiv__( @@ -2161,40 +2182,31 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Never: ... @overload def __floordiv__( - self: Series[int], - other: ( - Just[int] - | Sequence[Just[int]] - | np_ndarray_anyint - | Index[int] - | Series[int] - ), + self: Supports_ProtoFloorDiv[_T_contra, S2], + other: _T_contra | Sequence[_T_contra], + ) -> Series[S2]: ... + @overload + def __floordiv__( + self: Series[int], other: np_ndarray_bool | Index[bool] | Series[bool] ) -> Series[int]: ... @overload def __floordiv__( - self: Series[int], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + self: Series[float], other: np_ndarray_bool | Index[bool] | Series[bool] ) -> Series[float]: ... @overload def __floordiv__( - self: Series[float], + self: Series[bool] | Series[int], + other: np_ndarray_anyint | Index[int] | Series[int], + ) -> Series[int]: ... + @overload + def __floordiv__( + self: Series[float], other: np_ndarray_anyint | Index[int] | Series[int] + ) -> Series[float]: ... + @overload + def __floordiv__( + self: Series[int] | Series[float], other: ( - Just[int] - | Just[float] - | Sequence[Just[int]] - | Sequence[Just[float]] - | np_ndarray_anyint - | np_ndarray_float - | Index[int] - | Index[float] - | Series[int] - | Series[float] + float | Sequence[float] | np_ndarray_float | Index[float] | Series[float] ), ) -> Series[float]: ... @overload @@ -2208,8 +2220,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): other: ( Just[int] | Just[float] - | Sequence[Just[int]] - | Sequence[Just[float]] + | Sequence[Just[int] | Just[float]] | np_ndarray_anyint | np_ndarray_float | Index[int] @@ -2221,65 +2232,81 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def __floordiv__( self: Series[Timedelta], + other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + ) -> Series[int]: ... + @overload + def floordiv( + self: Series[Never], other: ( - timedelta - | Sequence[timedelta] - | np.timedelta64 - | np_ndarray_td - | TimedeltaIndex - | Series[Timedelta] + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + | Series[bool] + | Series[int] + | Series[float] ), - ) -> Series[int]: ... + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, + ) -> Series: ... @overload def floordiv( - self, + self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], other: Index[Never] | Series[Never], level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, ) -> Series: ... @overload + def floordiv( + self: Supports_ProtoFloorDiv[_T_contra, S2], + other: _T_contra | Sequence[_T_contra], + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, + ) -> Series[S2]: ... + @overload def floordiv( self: Series[int], - other: ( - Just[int] - | Sequence[Just[int]] - | np_ndarray_anyint - | Index[int] - | Series[int] - ), + other: np_ndarray_bool | Index[bool] | Series[bool], level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, ) -> Series[int]: ... @overload def floordiv( - self: Series[int], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + self: Series[float], + other: np_ndarray_bool | Index[bool] | Series[bool], level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, ) -> Series[float]: ... @overload + def floordiv( + self: Series[bool] | Series[int], + other: np_ndarray_anyint | Index[int] | Series[int], + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, + ) -> Series[int]: ... + @overload def floordiv( self: Series[float], + other: np_ndarray_anyint | Index[int] | Series[int], + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, + ) -> Series[float]: ... + @overload + def floordiv( + self: Series[int] | Series[float], other: ( - Just[int] - | Just[float] - | Sequence[Just[int]] - | Sequence[Just[float]] - | np_ndarray_anyint - | np_ndarray_float - | Index[int] - | Index[float] - | Series[int] - | Series[float] + float | Sequence[float] | np_ndarray_float | Index[float] | Series[float] ), level: Level | None = ..., fill_value: float | None = None, @@ -2291,8 +2318,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): other: ( Just[int] | Just[float] - | Sequence[Just[int]] - | Sequence[Just[float]] + | Sequence[Just[int] | Just[float]] | np_ndarray_anyint | np_ndarray_float | Index[int] @@ -2307,24 +2333,37 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def floordiv( self: Series[Timedelta], - other: ( - timedelta - | Sequence[timedelta] - | np.timedelta64 - | np_ndarray_td - | TimedeltaIndex - | Series[Timedelta] - ), + other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, ) -> Series[int]: ... @overload - def __rfloordiv__(self, other: Index[Never] | Series[Never]) -> Series: ... + def __rfloordiv__( # type: ignore[overload-overlap] + self: Series[Never], + other: ( + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + | Series[bool] + | Series[int] + | Series[float] + ), + ) -> Series: ... + @overload + def __rfloordiv__( + self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], + other: Index[Never] | Series[Never], + ) -> Series: ... @overload def __rfloordiv__( self: Series[int] | Series[float], - other: np_ndarray_bool | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, ) -> Never: ... @overload def __rfloordiv__( @@ -2332,40 +2371,31 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Never: ... @overload def __rfloordiv__( - self: Series[int], - other: ( - Just[int] - | Sequence[Just[int]] - | np_ndarray_anyint - | Index[int] - | Series[int] - ), + self: Supports_ProtoRFloorDiv[_T_contra, S2], + other: _T_contra | Sequence[_T_contra], + ) -> Series[S2]: ... + @overload + def __rfloordiv__( + self: Series[int], other: np_ndarray_bool | Index[bool] | Series[bool] ) -> Series[int]: ... @overload def __rfloordiv__( - self: Series[int], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + self: Series[float], other: np_ndarray_bool | Index[bool] | Series[bool] ) -> Series[float]: ... @overload def __rfloordiv__( - self: Series[float], + self: Series[bool] | Series[int], + other: np_ndarray_anyint | Index[int] | Series[int], + ) -> Series[int]: ... + @overload + def __rfloordiv__( + self: Series[float], other: np_ndarray_anyint | Index[int] | Series[int] + ) -> Series[float]: ... + @overload + def __rfloordiv__( + self: Series[int] | Series[float], other: ( - Just[int] - | Just[float] - | Sequence[Just[int]] - | Sequence[Just[float]] - | np_ndarray_anyint - | np_ndarray_float - | Index[int] - | Index[float] - | Series[int] - | Series[float] + float | Sequence[float] | np_ndarray_float | Index[float] | Series[float] ), ) -> Series[float]: ... @overload @@ -2380,67 +2410,88 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ), ) -> Never: ... @overload + def __rfloordiv__( + self: Series[int] | Series[float], + other: timedelta | np_ndarray_td | TimedeltaIndex | Series[Timedelta], + ) -> Series[Timedelta]: ... + @overload def __rfloordiv__( self: Series[Timedelta], + other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + ) -> Series[int]: ... + @overload + def rfloordiv( + self: Series[Never], other: ( - timedelta - | Sequence[timedelta] - | np.timedelta64 - | np_ndarray_td - | TimedeltaIndex - | Series[Timedelta] + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + | Series[bool] + | Series[int] + | Series[float] ), - ) -> Series[int]: ... + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, + ) -> Series: ... @overload def rfloordiv( - self, + self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], other: Index[Never] | Series[Never], level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, ) -> Series: ... @overload + def rfloordiv( + self: Supports_ProtoRFloorDiv[_T_contra, S2], + other: _T_contra | Sequence[_T_contra], + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex = ..., + ) -> Series[S2]: ... + @overload def rfloordiv( self: Series[int], - other: ( - Just[int] - | Sequence[Just[int]] - | np_ndarray_anyint - | Index[int] - | Series[int] - ), + other: np_ndarray_bool | Index[bool] | Series[bool], level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex = ..., ) -> Series[int]: ... @overload def rfloordiv( - self: Series[int], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + self: Series[float], + other: np_ndarray_bool | Index[bool] | Series[bool], level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex = ..., ) -> Series[float]: ... @overload + def rfloordiv( + self: Series[bool] | Series[int], + other: np_ndarray_anyint | Index[int] | Series[int], + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex = ..., + ) -> Series[int]: ... + @overload def rfloordiv( self: Series[float], + other: np_ndarray_anyint | Index[int] | Series[int], + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex = ..., + ) -> Series[float]: ... + @overload + def rfloordiv( + self: Series[int] | Series[float], other: ( - Just[int] - | Just[float] - | Sequence[Just[int]] - | Sequence[Just[float]] - | np_ndarray_anyint - | np_ndarray_float - | Index[int] - | Index[float] - | Series[int] - | Series[float] + float | Sequence[float] | np_ndarray_float | Index[float] | Series[float] ), level: Level | None = ..., fill_value: float | None = None, @@ -2448,11 +2499,10 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[float]: ... @overload def rfloordiv( - self: Series[Timedelta], + self: Series[int] | Series[float], other: ( timedelta | Sequence[timedelta] - | np.timedelta64 | np_ndarray_td | TimedeltaIndex | Series[Timedelta] @@ -2460,6 +2510,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex = ..., + ) -> Series[Timedelta]: ... + @overload + def rfloordiv( + self: Series[Timedelta], + other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex = ..., ) -> Series[int]: ... def __ge__( # type: ignore[override] self, other: S1 | ListLike | Series[S1] | datetime | timedelta | date @@ -3582,6 +3640,10 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def __truediv__(self: Series[bool], other: np_ndarray_bool) -> Never: ... @overload + def __truediv__(self, other: np_ndarray_dt) -> Never: ... + @overload + def __truediv__(self: Series[T_COMPLEX], other: np_ndarray_td) -> Never: ... + @overload def __truediv__( self: Series[Timedelta], other: np_ndarray_bool | np_ndarray_complex | np_ndarray_dt, @@ -3838,9 +3900,11 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def __rtruediv__(self: Series[bool], other: np_ndarray_bool) -> Never: ... @overload + def __rtruediv__(self, other: np_ndarray_dt) -> Never: ... + @overload def __rtruediv__( self: Series[Timedelta], - other: np_ndarray_bool | np_ndarray_complex | np_ndarray_dt, + other: np_ndarray_bool | np_ndarray_complex, ) -> Never: ... @overload def __rtruediv__( diff --git a/tests/indexes/arithmetic/float/test_floordiv.py b/tests/indexes/arithmetic/float/test_floordiv.py new file mode 100644 index 000000000..45faab573 --- /dev/null +++ b/tests/indexes/arithmetic/float/test_floordiv.py @@ -0,0 +1,131 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + +import numpy as np +import pandas as pd +import pytest +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) + + +@pytest.fixture +def left() -> "pd.Index[float]": + """Left operand""" + lo = pd.Index([1.2, 2.4, 3.6]) + return check(assert_type(lo, "pd.Index[float]"), pd.Index, np.floating) + + +def test_floordiv_py_scalar(left: "pd.Index[float]") -> None: + """Test pd.Index[float] // Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 27), timedelta(seconds=1) + + check(assert_type(left // b, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(left // i, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(left // f, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(i // left, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(f // left, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + +def test_floordiv_py_sequence(left: "pd.Index[float]") -> None: + """Test pd.Index[float] // Python native sequences""" + b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, 27 + d) for d in range(3)] + d = [timedelta(seconds=s) for s in range(3)] + + check(assert_type(left // b, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(left // i, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(left // f, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(i // left, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(f // left, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = d // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_floordiv_numpy_array(left: "pd.Index[float]") -> None: + """Test pd.Index[float] // numpy arrays""" + b = np.array([True, False, True], np.bool_) + i = np.array([2, 3, 5], np.int64) + f = np.array([1.0, 2.0, 3.0], np.float64) + c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array( + [np.datetime64(f"2025-10-{d:02d}") for d in (23, 24, 25)], np.datetime64 + ) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) + + check(assert_type(left // b, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(left // i, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(left // f, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left // c, Never) + assert_type(left // s, Never) + assert_type(left // d, Never) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to + # errors or pd.Index. + check(b // left, pd.Index, np.floating) + check(i // left, pd.Index, np.floating) + check(f // left, pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(c // left, Any) + assert_type(s // left, Any) + check( + assert_type(d // left, "np.typing.NDArray[np.int64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) + + +def test_floordiv_pd_index(left: "pd.Index[float]") -> None: + """Test pd.Index[float] // pandas Indexes""" + b = pd.Index([True, False, True]) + i = pd.Index([2, 3, 5]) + f = pd.Index([1.0, 2.0, 3.0]) + c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) + + check(assert_type(left // b, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(left // i, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(left // f, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(i // left, "pd.Index[float]"), pd.Index, np.floating) + check(assert_type(f // left, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) diff --git a/tests/indexes/arithmetic/float/test_truediv.py b/tests/indexes/arithmetic/float/test_truediv.py index 6e1cd074a..f26fe1070 100644 --- a/tests/indexes/arithmetic/float/test_truediv.py +++ b/tests/indexes/arithmetic/float/test_truediv.py @@ -1,8 +1,17 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + import numpy as np from numpy import typing as npt # noqa: F401 import pandas as pd import pytest -from typing_extensions import assert_type +from typing_extensions import ( + Never, + assert_type, +) from tests import ( TYPE_CHECKING_INVALID_USAGE, @@ -20,31 +29,46 @@ def left() -> "pd.Index[float]": def test_truediv_py_scalar(left: "pd.Index[float]") -> None: """Test pd.Index[float] / Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 10, 30), timedelta(seconds=1) check(assert_type(left / b, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / i, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / f, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(i / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(f / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(c / left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) def test_truediv_py_sequence(left: "pd.Index[float]") -> None: """Test pd.Index[float] / Python native sequences""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, d) for d in (27, 28, 29)] + d = [timedelta(seconds=s) for s in (1, 2, 3)] check(assert_type(left / b, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / i, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / f, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(i / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(f / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(c / left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = d / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] def test_truediv_numpy_array(left: "pd.Index[float]") -> None: @@ -53,11 +77,16 @@ def test_truediv_numpy_array(left: "pd.Index[float]") -> None: i = np.array([2, 3, 5], np.int64) f = np.array([1.0, 2.0, 3.0], np.float64) c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array([np.datetime64(f"2025-10-{d:02d}") for d in (1, 2, 3)], np.datetime64) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) check(assert_type(left / b, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / i, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / f, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left / s, Never) + assert_type(left / d, Never) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rtruediv__` cannot override. At runtime, they return @@ -70,6 +99,13 @@ def test_truediv_numpy_array(left: "pd.Index[float]") -> None: pd.Index, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s / left, Any) + check( + assert_type(d / left, "npt.NDArray[np.float64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) def test_truediv_pd_scalar(left: "pd.Index[float]") -> None: @@ -80,9 +116,8 @@ def test_truediv_pd_scalar(left: "pd.Index[float]") -> None: _00 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _01 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: _10 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _11 = d / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) def test_truediv_pd_index(left: "pd.Index[float]") -> None: @@ -91,13 +126,21 @@ def test_truediv_pd_index(left: "pd.Index[float]") -> None: i = pd.Index([2, 3, 5]) f = pd.Index([1.0, 2.0, 3.0]) c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (1, 2, 3)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left / b, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / i, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / f, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(i / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(f / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(c / left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) diff --git a/tests/indexes/arithmetic/int/test_floordiv.py b/tests/indexes/arithmetic/int/test_floordiv.py new file mode 100644 index 000000000..fe3d2766b --- /dev/null +++ b/tests/indexes/arithmetic/int/test_floordiv.py @@ -0,0 +1,127 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + +import numpy as np +import pandas as pd +import pytest +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) + + +@pytest.fixture +def left() -> "pd.Index[int]": + """Left operand""" + lo = pd.Index([1, 2, 3]) + return check(assert_type(lo, "pd.Index[int]"), pd.Index, np.integer) + + +def test_floordiv_py_scalar(left: "pd.Index[int]") -> None: + """Test pd.Index[int] // Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 27), timedelta(seconds=1) + + check(assert_type(left // b, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(left // i, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(left // f, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(i // left, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(f // left, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + +def test_floordiv_py_sequence(left: "pd.Index[int]") -> None: + """Test pd.Index[int] // Python native sequences""" + b, i, f, c = [True, True, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, 27 + d) for d in range(3)] + d = [timedelta(seconds=s) for s in range(3)] + + check(assert_type(left // b, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(left // i, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(left // f, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(i // left, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(f // left, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = d // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_floordiv_numpy_array(left: "pd.Index[int]") -> None: + """Test pd.Index[int] // numpy arrays""" + b = np.array([True, True, True], np.bool_) + i = np.array([2, 3, 5], np.int64) + f = np.array([1.0, 2.0, 3.0], np.float64) + c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array( + [np.datetime64(f"2025-10-{d:02d}") for d in (23, 24, 25)], np.datetime64 + ) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) + + check(assert_type(left // b, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(left // i, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(left // f, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left // c, Never) + assert_type(left // s, Never) + assert_type(left // d, Never) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to + # errors or pd.Index. + check(b // left, pd.Index, np.integer) + check(i // left, pd.Index, np.integer) + check(f // left, pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(c // left, Any) + assert_type(s // left, Any) + assert_type(d // left, "np.typing.NDArray[np.int64]") + + +def test_floordiv_pd_index(left: "pd.Index[int]") -> None: + """Test pd.Index[int] // pandas Indexes""" + b = pd.Index([True, True, True]) + i = pd.Index([2, 3, 5]) + f = pd.Index([1.0, 2.0, 3.0]) + c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) + + check(assert_type(left // b, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(left // i, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(left // f, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(i // left, "pd.Index[int]"), pd.Index, np.integer) + check(assert_type(f // left, "pd.Index[float]"), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) diff --git a/tests/indexes/arithmetic/int/test_truediv.py b/tests/indexes/arithmetic/int/test_truediv.py index 3b9c2d8a1..6df55ce33 100644 --- a/tests/indexes/arithmetic/int/test_truediv.py +++ b/tests/indexes/arithmetic/int/test_truediv.py @@ -1,8 +1,17 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + import numpy as np from numpy import typing as npt # noqa: F401 import pandas as pd import pytest -from typing_extensions import assert_type +from typing_extensions import ( + Never, + assert_type, +) from tests import ( TYPE_CHECKING_INVALID_USAGE, @@ -20,31 +29,46 @@ def left() -> "pd.Index[int]": def test_truediv_py_scalar(left: "pd.Index[int]") -> None: """Test pd.Index[int] / Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 10, 30), timedelta(seconds=1) check(assert_type(left / b, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / i, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / f, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(i / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(f / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(c / left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) def test_truediv_py_sequence(left: "pd.Index[int]") -> None: """Test pd.Index[int] / Python native sequences""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, d) for d in (27, 28, 29)] + d = [timedelta(seconds=s) for s in (1, 2, 3)] check(assert_type(left / b, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / i, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / f, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(i / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(f / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(c / left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = d / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] def test_truediv_numpy_array(left: "pd.Index[int]") -> None: @@ -53,11 +77,16 @@ def test_truediv_numpy_array(left: "pd.Index[int]") -> None: i = np.array([2, 3, 5], np.int64) f = np.array([1.0, 2.0, 3.0], np.float64) c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array([np.datetime64(f"2025-10-{d:02d}") for d in (1, 2, 3)], np.datetime64) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) check(assert_type(left / b, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / i, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / f, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left / s, Never) + assert_type(left / d, Never) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rtruediv__` cannot override. At runtime, they return @@ -70,6 +99,13 @@ def test_truediv_numpy_array(left: "pd.Index[int]") -> None: pd.Index, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s / left, Any) + check( + assert_type(d / left, "npt.NDArray[np.float64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) def test_truediv_pd_scalar(left: "pd.Index[int]") -> None: @@ -80,9 +116,8 @@ def test_truediv_pd_scalar(left: "pd.Index[int]") -> None: _00 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _01 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: _10 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _11 = d / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) def test_truediv_pd_index(left: "pd.Index[int]") -> None: @@ -91,13 +126,21 @@ def test_truediv_pd_index(left: "pd.Index[int]") -> None: i = pd.Index([2, 3, 5]) f = pd.Index([1.0, 2.0, 3.0]) c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (1, 2, 3)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left / b, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / i, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / f, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(left / c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(i / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(f / left, "pd.Index[float]"), pd.Index, np.floating) check(assert_type(c / left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) diff --git a/tests/indexes/arithmetic/test_floordiv.py b/tests/indexes/arithmetic/test_floordiv.py new file mode 100644 index 000000000..82f3dbc8a --- /dev/null +++ b/tests/indexes/arithmetic/test_floordiv.py @@ -0,0 +1,127 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + +import numpy as np +import pandas as pd +import pytest +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) + + +@pytest.fixture +def left_i() -> pd.Index: + """Left operand""" + lo = pd.MultiIndex.from_arrays([[1, 2, 3]]).levels[0] + return check(assert_type(lo, pd.Index), pd.Index, np.integer) + + +def test_floordiv_py_scalar(left_i: pd.Index) -> None: + """Test pd.Index[int] // Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 27), timedelta(seconds=1) + + check(assert_type(left_i // b, pd.Index), pd.Index, np.integer) + check(assert_type(left_i // i, pd.Index), pd.Index, np.integer) + check(assert_type(left_i // f, pd.Index), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left_i // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left_i // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left_i // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left_i, pd.Index), pd.Index, np.integer) + check(assert_type(i // left_i, pd.Index), pd.Index, np.integer) + check(assert_type(f // left_i, pd.Index), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left_i, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + +def test_floordiv_py_sequence(left_i: pd.Index) -> None: + """Test pd.Index[int] // Python native sequences""" + b, i, f, c = [True, True, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, 27 + d) for d in range(3)] + d = [timedelta(seconds=s) for s in range(3)] + + check(assert_type(left_i // b, pd.Index), pd.Index, np.integer) + check(assert_type(left_i // i, pd.Index), pd.Index, np.integer) + check(assert_type(left_i // f, pd.Index), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left_i // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left_i // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left_i // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left_i, pd.Index), pd.Index, np.integer) + check(assert_type(i // left_i, pd.Index), pd.Index, np.integer) + check(assert_type(f // left_i, pd.Index), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = d // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_floordiv_numpy_array(left_i: pd.Index) -> None: + """Test pd.Index[int] // numpy arrays""" + b = np.array([True, True, True], np.bool_) + i = np.array([2, 3, 5], np.int64) + f = np.array([1.0, 2.0, 3.0], np.float64) + c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array( + [np.datetime64(f"2025-10-{d:02d}") for d in (23, 24, 25)], np.datetime64 + ) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) + + check(assert_type(left_i // b, pd.Index), pd.Index, np.integer) + check(assert_type(left_i // i, pd.Index), pd.Index, np.integer) + check(assert_type(left_i // f, pd.Index), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left_i // c, Never) + assert_type(left_i // s, Never) + assert_type(left_i // d, Never) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to + # errors or pd.Index. + check(b // left_i, pd.Index, np.integer) + check(i // left_i, pd.Index, np.integer) + check(f // left_i, pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(c // left_i, Any) + assert_type(s // left_i, Any) + assert_type(d // left_i, Any) # pyright: ignore[reportAssertTypeFailure] + + +def test_floordiv_pd_index(left_i: pd.Index) -> None: + """Test pd.Index[int] // pandas Indexes""" + b = pd.Index([True, True, True]) + i = pd.Index([2, 3, 5]) + f = pd.Index([1.0, 2.0, 3.0]) + c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) + + check(assert_type(left_i // b, pd.Index), pd.Index, np.integer) + check(assert_type(left_i // i, pd.Index), pd.Index, np.integer) + check(assert_type(left_i // f, pd.Index), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left_i // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left_i // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left_i // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left_i, pd.Index), pd.Index, np.integer) + check(assert_type(i // left_i, pd.Index), pd.Index, np.integer) + check(assert_type(f // left_i, pd.Index), pd.Index, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left_i, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) diff --git a/tests/indexes/arithmetic/timedeltaindex/test_floordiv.py b/tests/indexes/arithmetic/timedeltaindex/test_floordiv.py new file mode 100644 index 000000000..ab2e7cb8e --- /dev/null +++ b/tests/indexes/arithmetic/timedeltaindex/test_floordiv.py @@ -0,0 +1,141 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + +import numpy as np +from numpy import typing as npt # noqa: F401 +import pandas as pd +import pytest +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) + + +@pytest.fixture +def left() -> pd.TimedeltaIndex: + """Left operand""" + lo = pd.Index([pd.Timedelta(1, "s")]) + return check(assert_type(lo, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + +def test_floordiv_py_scalar(left: pd.TimedeltaIndex) -> None: + """Test pd.TimedeltaIndex // Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 24), timedelta(seconds=1) + + if TYPE_CHECKING_INVALID_USAGE: + _00 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // i, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(left // f, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // d, "pd.Index[int]"), pd.Index, np.integer) + + if TYPE_CHECKING_INVALID_USAGE: + _10 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _11 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _12 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Index[int]"), pd.Index, np.integer) + + +def test_floordiv_py_sequence(left: pd.TimedeltaIndex) -> None: + """Test pd.TimedeltaIndex // Python native sequences""" + b, i, f, c = [True], [2], [1.5], [1.7j] + s, d = [datetime(2025, 9, 24)], [timedelta(seconds=1)] + + if TYPE_CHECKING_INVALID_USAGE: + _00 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // i, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(left // f, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // d, "pd.Index[int]"), pd.Index, int) + + if TYPE_CHECKING_INVALID_USAGE: + _10 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _11 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _12 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Index[int]"), pd.Index, np.integer) + + +def test_floordiv_numpy_array(left: pd.TimedeltaIndex) -> None: + """Test pd.TimedeltaIndex // numpy arrays""" + b = np.array([True], np.bool_) + i = np.array([2], np.int64) + f = np.array([1.5], np.float64) + c = np.array([1.7j], np.complex128) + s = np.array([datetime(2025, 9, 24)], np.datetime64) + d = np.array([timedelta(seconds=1)], np.timedelta64) + + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left // b, Never) + check(assert_type(left // i, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(left // f, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left // c, Never) + assert_type(left // s, Never) + check(assert_type(left // d, "pd.Index[int]"), pd.Index, np.integer) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to + # errors or pd.Series. + if TYPE_CHECKING_INVALID_USAGE: + assert_type(b // left, "npt.NDArray[np.int8]") + assert_type(i // left, "npt.NDArray[np.int64]") + assert_type(f // left, "npt.NDArray[np.float64]") + assert_type(c // left, Any) + assert_type(s // left, Any) + check(assert_type(d // left, "npt.NDArray[np.int64]"), pd.Index, np.integer) + + +def test_floordiv_pd_scalar(left: pd.TimedeltaIndex) -> None: + """Test pd.TimedeltaIndex // pandas scalars""" + s, d = pd.Timestamp(2025, 9, 24), pd.Timedelta(seconds=1) + + if TYPE_CHECKING_INVALID_USAGE: + _00 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // d, "pd.Index[int]"), pd.Index, np.integer) + + if TYPE_CHECKING_INVALID_USAGE: + _10 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Index[int]"), pd.Index, np.integer) + + +def test_floordiv_pd_index(left: pd.TimedeltaIndex) -> None: + """Test pd.TimedeltaIndex // pandas Indexes""" + b = pd.Index([True]) + i = pd.Index([2]) + f = pd.Index([1.5]) + c = pd.Index([1.7j]) + s, d = pd.Index([datetime(2025, 9, 24)]), pd.Index([timedelta(seconds=1)]) + + if TYPE_CHECKING_INVALID_USAGE: + _00 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // i, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(left // f, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // d, "pd.Index[int]"), pd.Index, np.integer) + + if TYPE_CHECKING_INVALID_USAGE: + _10 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _11 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _12 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Index[int]"), pd.Index, np.integer) diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index 045409474..c961b4dba 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -264,17 +264,6 @@ def test_types_to_numpy() -> None: ) -def test_index_arithmetic() -> None: - # GH 287 - idx = pd.Index([1, 2.2, 3], dtype=float) - check(assert_type(idx * 3, "pd.Index[float]"), pd.Index, np.float64) - check(assert_type(idx / 3, "pd.Index[float]"), pd.Index, np.float64) - check(assert_type(idx // 3, "pd.Index[float]"), pd.Index, np.float64) - check(assert_type(3 * idx, "pd.Index[float]"), pd.Index, np.float64) - check(assert_type(3 / idx, "pd.Index[float]"), pd.Index, np.float64) - check(assert_type(3 // idx, "pd.Index[float]"), pd.Index, np.float64) - - def test_range_index_union() -> None: check( assert_type( @@ -845,9 +834,6 @@ def test_index_operators() -> None: i1 = pd.Index([1, 2, 3]) i2 = pd.Index([4, 5, 6]) - check(assert_type(i1 // i2, "pd.Index[int]"), pd.Index) - check(assert_type(i1 // 10, "pd.Index[int]"), pd.Index) - check(assert_type(10 // i1, "pd.Index[int]"), pd.Index) check(assert_type(i1**i2, "pd.Index[int]"), pd.Index) check(assert_type(i1**2, "pd.Index[int]"), pd.Index) check(assert_type(2**i1, "pd.Index[int]"), pd.Index) @@ -1196,31 +1182,6 @@ def test_new() -> None: ) -def test_timedelta_div() -> None: - index = pd.Index([pd.Timedelta(days=1)], dtype="timedelta64[s]") - delta = dt.timedelta(1) - - check(assert_type(index / delta, "pd.Index[float]"), pd.Index, float) - check(assert_type(index / [delta], "pd.Index[float]"), pd.Index, float) - check(assert_type(index / 1, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) - check(assert_type(index / [1], pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) - check(assert_type(index // delta, "pd.Index[int]"), pd.Index, np.longlong) - check(assert_type(index // [delta], "pd.Index[int]"), pd.Index, int) - check(assert_type(index // 1, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) - check(assert_type(index // [1], pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) - - check(assert_type(delta / index, "pd.Index[float]"), pd.Index, float) - check(assert_type([delta] / index, "pd.Index[float]"), pd.Index, float) - check(assert_type(delta // index, "pd.Index[int]"), pd.Index, np.longlong) - check(assert_type([delta] // index, "pd.Index[int]"), pd.Index, np.signedinteger) - - if TYPE_CHECKING_INVALID_USAGE: - _0 = 1 / index # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _1 = [1] / index # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = 1 // index # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _3 = [1] // index # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - - def test_datetime_operators_builtin() -> None: time = pd.date_range("2022-01-01", "2022-01-31", freq="D") check(assert_type(time + dt.timedelta(0), pd.DatetimeIndex), pd.DatetimeIndex) diff --git a/tests/scalars/test_scalars.py b/tests/scalars/test_scalars.py index d4cafa390..61e3fd684 100644 --- a/tests/scalars/test_scalars.py +++ b/tests/scalars/test_scalars.py @@ -653,9 +653,6 @@ def test_timedelta_add_sub() -> None: def test_timedelta_mul_div() -> None: td = pd.Timedelta("1 day") - i_idx = pd.Index([1, 2, 3], dtype=int) - f_idx = 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]) @@ -663,11 +660,6 @@ def test_timedelta_mul_div() -> None: 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) @@ -709,23 +701,6 @@ def test_timedelta_mul_div() -> None: np.ndarray, np.timedelta64, ) - check( - assert_type(td // mp_series_int, "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) - check( - assert_type(td // md_series_float, "pd.Series[pd.Timedelta]"), - 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, - np.longlong, - ) check(assert_type(pd.NaT // td, float), float) # Note: None of the reverse floordiv work @@ -736,10 +711,6 @@ def test_timedelta_mul_div() -> None: _01 = md_float // td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _02 = md_ndarray_intp // td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _03 = md_ndarray_float // td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _04 = mp_series_int // td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _05 = md_series_float // td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = md_int64_index // td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _07 = md_float_index // td # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(td / td, float), float) check(assert_type(td / pd.NaT, float), float) diff --git a/tests/series/arithmetic/float/test_floordiv.py b/tests/series/arithmetic/float/test_floordiv.py index 2eedc4ef3..72a803da2 100644 --- a/tests/series/arithmetic/float/test_floordiv.py +++ b/tests/series/arithmetic/float/test_floordiv.py @@ -1,8 +1,12 @@ +from datetime import ( + datetime, + timedelta, +) from typing import Any import numpy as np -from numpy import typing as npt # noqa: F401 import pandas as pd +import pytest from typing_extensions import ( Never, assert_type, @@ -13,166 +17,239 @@ check, ) -left = pd.Series([1.2, 2.4, 3.6]) # left operand + +@pytest.fixture +def left() -> "pd.Series[float]": + """Left operand""" + lo = pd.Series([1.2, 2.4, 3.6]) + return check(assert_type(lo, "pd.Series[float]"), pd.Series, np.floating) -def test_floordiv_py_scalar() -> None: +def test_floordiv_py_scalar(left: "pd.Series[float]") -> None: """Test pd.Series[float] // Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 27), timedelta(seconds=1) - if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b // left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i // left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f // left, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _3 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) -def test_floordiv_py_sequence() -> None: +def test_floordiv_py_sequence(left: "pd.Series[float]") -> None: """Test pd.Series[float] // Python native sequences""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, 27 + d) for d in range(3)] + d = [timedelta(seconds=s) for s in range(3)] - if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b // left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i // left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f // left, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _3 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = d // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) -def test_floordiv_numpy_array() -> None: +def test_floordiv_numpy_array(left: "pd.Series[float]") -> None: """Test pd.Series[float] // numpy arrays""" b = np.array([True, False, True], np.bool_) i = np.array([2, 3, 5], np.int64) f = np.array([1.0, 2.0, 3.0], np.float64) c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array( + [np.datetime64(f"2025-10-{d:02d}") for d in (23, 24, 25)], np.datetime64 + ) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) - if TYPE_CHECKING_INVALID_USAGE: - assert_type(left // b, Never) + check(assert_type(left // b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: assert_type(left // c, Never) + assert_type(left // s, Never) + assert_type(left // d, Never) - # `numpy` typing gives the corresponding `ndarray`s in the static type - # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to - # errors or pd.Series. - assert_type(b // left, "npt.NDArray[np.int8]") + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to + # errors or pd.Series. + check(b // left, pd.Series, np.floating) check(i // left, pd.Series, np.floating) check(f // left, pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: assert_type(c // left, Any) + assert_type(s // left, Any) + check( + assert_type(d // left, "np.typing.NDArray[np.int64]"), pd.Series, pd.Timedelta + ) - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) -def test_floordiv_pd_index() -> None: +def test_floordiv_pd_index(left: "pd.Series[float]") -> None: """Test pd.Series[float] // pandas Indexes""" b = pd.Index([True, False, True]) i = pd.Index([2, 3, 5]) f = pd.Index([1.0, 2.0, 3.0]) c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) - if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b // left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i // left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f // left, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _3 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) -def test_floordiv_pd_series() -> None: +def test_floordiv_pd_series(left: "pd.Series[float]") -> None: """Test pd.Series[float] // pandas Series""" b = pd.Series([True, False, True]) i = pd.Series([2, 3, 5]) f = pd.Series([1.0, 2.0, 3.0]) c = pd.Series([1.1j, 2.2j, 4.1j]) + s = pd.Series([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) - if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b // left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i // left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f // left, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _3 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) diff --git a/tests/series/arithmetic/float/test_truediv.py b/tests/series/arithmetic/float/test_truediv.py index 83c3da2f5..9b330fce8 100644 --- a/tests/series/arithmetic/float/test_truediv.py +++ b/tests/series/arithmetic/float/test_truediv.py @@ -1,8 +1,17 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + import numpy as np from numpy import typing as npt # noqa: F401 import pandas as pd import pytest -from typing_extensions import assert_type +from typing_extensions import ( + Never, + assert_type, +) from tests import ( TYPE_CHECKING_INVALID_USAGE, @@ -20,16 +29,23 @@ def left() -> "pd.Series[float]": def test_truediv_py_scalar(left: "pd.Series[float]") -> None: """Test pd.Series[float] / Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 27), timedelta(seconds=1) check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(c / left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -39,11 +55,17 @@ def test_truediv_py_scalar(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -53,6 +75,13 @@ def test_truediv_py_scalar(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -60,21 +89,32 @@ def test_truediv_py_scalar(left: "pd.Series[float]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_truediv_py_sequence(left: "pd.Series[float]") -> None: """Test pd.Series[float] / Python native sequences""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, 27 + d) for d in range(3)] + d = [timedelta(seconds=s) for s in range(3)] check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(c / left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -84,11 +124,17 @@ def test_truediv_py_sequence(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -98,6 +144,13 @@ def test_truediv_py_sequence(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -105,6 +158,9 @@ def test_truediv_py_sequence(left: "pd.Series[float]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_truediv_numpy_array(left: "pd.Series[float]") -> None: @@ -113,11 +169,18 @@ def test_truediv_numpy_array(left: "pd.Series[float]") -> None: i = np.array([2, 3, 5], np.int64) f = np.array([1.0, 2.0, 3.0], np.float64) c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array( + [np.datetime64(f"2025-10-{d:02d}") for d in (28, 29, 30)], np.datetime64 + ) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left / s, Never) + assert_type(left / d, Never) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rtruediv__` cannot override. At runtime, they return @@ -130,6 +193,9 @@ def test_truediv_numpy_array(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s / left, Any) + check(assert_type(d / left, "npt.NDArray[np.float64]"), pd.Series, pd.Timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -139,11 +205,17 @@ def test_truediv_numpy_array(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -153,6 +225,13 @@ def test_truediv_numpy_array(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -160,6 +239,9 @@ def test_truediv_numpy_array(left: "pd.Series[float]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_truediv_pd_scalar(left: "pd.Series[float]") -> None: @@ -201,16 +283,24 @@ def test_truediv_pd_index(left: "pd.Series[float]") -> None: i = pd.Index([2, 3, 5]) f = pd.Index([1.0, 2.0, 3.0]) c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (28, 29, 30)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(c / left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -220,11 +310,17 @@ def test_truediv_pd_index(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -234,6 +330,13 @@ def test_truediv_pd_index(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -241,6 +344,9 @@ def test_truediv_pd_index(left: "pd.Series[float]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_truediv_pd_series(left: "pd.Series[float]") -> None: @@ -249,16 +355,24 @@ def test_truediv_pd_series(left: "pd.Series[float]") -> None: i = pd.Series([2, 3, 5]) f = pd.Series([1.0, 2.0, 3.0]) c = pd.Series([1.1j, 2.2j, 4.1j]) + s = pd.Series([datetime(2025, 10, d) for d in (28, 29, 30)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(c / left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -268,11 +382,17 @@ def test_truediv_pd_series(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -282,6 +402,13 @@ def test_truediv_pd_series(left: "pd.Series[float]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -289,3 +416,6 @@ def test_truediv_pd_series(left: "pd.Series[float]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) diff --git a/tests/series/arithmetic/int/test_floordiv.py b/tests/series/arithmetic/int/test_floordiv.py index 0504d1074..a5e810b44 100644 --- a/tests/series/arithmetic/int/test_floordiv.py +++ b/tests/series/arithmetic/int/test_floordiv.py @@ -1,8 +1,12 @@ +from datetime import ( + datetime, + timedelta, +) from typing import Any import numpy as np -from numpy import typing as npt # noqa: F401 import pandas as pd +import pytest from typing_extensions import ( Never, assert_type, @@ -13,166 +17,237 @@ check, ) -left = pd.Series([1, 2, 3]) # left operand + +@pytest.fixture +def left() -> "pd.Series[int]": + """Left operand""" + lo = pd.Series([1, 2, 3]) + return check(assert_type(lo, "pd.Series[int]"), pd.Series, np.integer) -def test_floordiv_py_scalar() -> None: +def test_floordiv_py_scalar(left: "pd.Series[int]") -> None: """Test pd.Series[int] // Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 27), timedelta(seconds=1) - if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // b, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // i, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b // left, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(i // left, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(f // left, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _3 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) -def test_floordiv_py_sequence() -> None: +def test_floordiv_py_sequence(left: "pd.Series[int]") -> None: """Test pd.Series[int] // Python native sequences""" - b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + b, i, f, c = [True, True, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, 27 + d) for d in range(3)] + d = [timedelta(seconds=s) for s in range(3)] - if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // b, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // i, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b // left, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(i // left, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(f // left, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _3 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = d // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) -def test_floordiv_numpy_array() -> None: +def test_floordiv_numpy_array(left: "pd.Series[int]") -> None: """Test pd.Series[int] // numpy arrays""" - b = np.array([True, False, True], np.bool_) + b = np.array([True, True, True], np.bool_) i = np.array([2, 3, 5], np.int64) f = np.array([1.0, 2.0, 3.0], np.float64) c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array( + [np.datetime64(f"2025-10-{d:02d}") for d in (23, 24, 25)], np.datetime64 + ) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) - if TYPE_CHECKING_INVALID_USAGE: - assert_type(left // b, Never) + check(assert_type(left // b, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // i, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: assert_type(left // c, Never) + assert_type(left // s, Never) + assert_type(left // d, Never) - # `numpy` typing gives the corresponding `ndarray`s in the static type - # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to - # errors or pd.Series. - assert_type(b // left, "npt.NDArray[np.int8]") + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to + # errors or pd.Series. + check(b // left, pd.Series, np.integer) check(i // left, pd.Series, np.integer) check(f // left, pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: assert_type(c // left, Any) + assert_type(s // left, Any) + assert_type(d // left, "np.typing.NDArray[np.int64]") - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) -def test_floordiv_pd_index() -> None: +def test_floordiv_pd_index(left: "pd.Series[int]") -> None: """Test pd.Series[int] // pandas Indexes""" - b = pd.Index([True, False, True]) + b = pd.Index([True, True, True]) i = pd.Index([2, 3, 5]) f = pd.Index([1.0, 2.0, 3.0]) c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) - if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // b, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // i, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b // left, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(i // left, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(f // left, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _3 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) -def test_floordiv_pd_series() -> None: +def test_floordiv_pd_series(left: "pd.Series[int]") -> None: """Test pd.Series[int] // pandas Series""" - b = pd.Series([True, False, True]) + b = pd.Series([True, True, True]) i = pd.Series([2, 3, 5]) f = pd.Series([1.0, 2.0, 3.0]) c = pd.Series([1.1j, 2.2j, 4.1j]) + s = pd.Series([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) - if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left // b, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // i, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left // f, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b // left, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(i // left, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(f // left, "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - _3 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) - left.floordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.floordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rfloordiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: left.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) diff --git a/tests/series/arithmetic/int/test_truediv.py b/tests/series/arithmetic/int/test_truediv.py index 757173a3a..1cda6bdb9 100644 --- a/tests/series/arithmetic/int/test_truediv.py +++ b/tests/series/arithmetic/int/test_truediv.py @@ -1,8 +1,17 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + import numpy as np from numpy import typing as npt # noqa: F401 import pandas as pd import pytest -from typing_extensions import assert_type +from typing_extensions import ( + Never, + assert_type, +) from tests import ( TYPE_CHECKING_INVALID_USAGE, @@ -20,16 +29,23 @@ def left() -> "pd.Series[int]": def test_truediv_py_scalar(left: "pd.Series[int]") -> None: """Test pd.Series[int] / Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 27), timedelta(seconds=1) check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(c / left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -39,11 +55,17 @@ def test_truediv_py_scalar(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -53,6 +75,13 @@ def test_truediv_py_scalar(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -60,21 +89,32 @@ def test_truediv_py_scalar(left: "pd.Series[int]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_truediv_py_sequence(left: "pd.Series[int]") -> None: """Test pd.Series[int] / Python native sequences""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, 27 + d) for d in range(3)] + d = [timedelta(seconds=s) for s in range(3)] check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(c / left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -84,11 +124,17 @@ def test_truediv_py_sequence(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -98,6 +144,13 @@ def test_truediv_py_sequence(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -105,6 +158,9 @@ def test_truediv_py_sequence(left: "pd.Series[int]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_truediv_numpy_array(left: "pd.Series[int]") -> None: @@ -113,11 +169,18 @@ def test_truediv_numpy_array(left: "pd.Series[int]") -> None: i = np.array([2, 3, 5], np.int64) f = np.array([1.0, 2.0, 3.0], np.float64) c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array( + [np.datetime64(f"2025-10-{d:02d}") for d in (28, 29, 30)], np.datetime64 + ) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left / s, Never) + assert_type(left / d, Never) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rtruediv__` cannot override. At runtime, they return @@ -130,6 +193,9 @@ def test_truediv_numpy_array(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s / left, Any) + check(assert_type(d / left, "npt.NDArray[np.float64]"), pd.Series, pd.Timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -139,11 +205,17 @@ def test_truediv_numpy_array(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -153,6 +225,13 @@ def test_truediv_numpy_array(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -160,6 +239,13 @@ def test_truediv_numpy_array(left: "pd.Series[int]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) def test_truediv_pd_scalar(left: "pd.Series[int]") -> None: @@ -201,16 +287,24 @@ def test_truediv_pd_index(left: "pd.Series[int]") -> None: i = pd.Index([2, 3, 5]) f = pd.Index([1.0, 2.0, 3.0]) c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (28, 29, 30)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(c / left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -220,11 +314,17 @@ def test_truediv_pd_index(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -234,6 +334,13 @@ def test_truediv_pd_index(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -241,6 +348,9 @@ def test_truediv_pd_index(left: "pd.Series[int]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_truediv_pd_series(left: "pd.Series[int]") -> None: @@ -249,16 +359,24 @@ def test_truediv_pd_series(left: "pd.Series[int]") -> None: i = pd.Series([2, 3, 5]) f = pd.Series([1.0, 2.0, 3.0]) c = pd.Series([1.1j, 2.2j, 4.1j]) + s = pd.Series([datetime(2025, 10, d) for d in (28, 29, 30)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left / b, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / i, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / f, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left / c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _04 = left / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left / d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(i / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(f / left, "pd.Series[float]"), pd.Series, np.floating) check(assert_type(c / left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.truediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.truediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -268,11 +386,17 @@ def test_truediv_pd_series(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.div(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.div(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rtruediv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -282,6 +406,13 @@ def test_truediv_pd_series(left: "pd.Series[int]") -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left.rtruediv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.rdiv(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rdiv(i), "pd.Series[float]"), pd.Series, np.floating) @@ -289,3 +420,6 @@ def test_truediv_pd_series(left: "pd.Series[int]") -> None: check( assert_type(left.rdiv(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rdiv(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) diff --git a/tests/series/arithmetic/test_floordiv.py b/tests/series/arithmetic/test_floordiv.py new file mode 100644 index 000000000..6f563bc14 --- /dev/null +++ b/tests/series/arithmetic/test_floordiv.py @@ -0,0 +1,253 @@ +from datetime import ( + datetime, + timedelta, +) +from typing import Any + +import numpy as np +import pandas as pd +import pytest +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) + + +@pytest.fixture +def left_i() -> pd.Series: + """Left operand""" + lo = pd.DataFrame({"a": [1, 2, 3]})["a"] + return check(assert_type(lo, pd.Series), pd.Series, np.integer) + + +def test_floordiv_py_scalar(left_i: pd.Series) -> None: + """Test pd.Series[int] // Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 27), timedelta(seconds=1) + + check(assert_type(left_i // b, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // i, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // f, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left_i // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left_i // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left_i // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left_i, pd.Series), pd.Series, np.integer) + check(assert_type(i // left_i, pd.Series), pd.Series, np.integer) + check(assert_type(f // left_i, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left_i, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) + + check(assert_type(left_i.floordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + check(assert_type(left_i.rfloordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rfloordiv(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.rfloordiv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left_i.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) + + +def test_floordiv_py_sequence(left_i: pd.Series) -> None: + """Test pd.Series[int] // Python native sequences""" + b, i, f, c = [True, True, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + s = [datetime(2025, 10, 27 + d) for d in range(3)] + d = [timedelta(seconds=s) for s in range(3)] + + check(assert_type(left_i // b, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // i, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // f, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left_i // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left_i // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left_i // d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b // left_i, pd.Series), pd.Series, np.integer) + check(assert_type(i // left_i, pd.Series), pd.Series, np.integer) + check(assert_type(f // left_i, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = d // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(left_i.floordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + check(assert_type(left_i.rfloordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left_i.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) + + +def test_floordiv_numpy_array(left_i: pd.Series) -> None: + """Test pd.Series[int] // numpy arrays""" + b = np.array([True, True, True], np.bool_) + i = np.array([2, 3, 5], np.int64) + f = np.array([1.0, 2.0, 3.0], np.float64) + c = np.array([1.1j, 2.2j, 4.1j], np.complex128) + s = np.array( + [np.datetime64(f"2025-10-{d:02d}") for d in (23, 24, 25)], np.datetime64 + ) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) + + check(assert_type(left_i // b, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // i, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // f, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left_i // c, Never) + assert_type(left_i // s, Never) + assert_type(left_i // d, Never) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rfloordiv__` cannot override. At runtime, they lead to + # errors or pd.Series. + check(b // left_i, pd.Series, np.integer) + check(i // left_i, pd.Series, np.integer) + check(f // left_i, pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(c // left_i, Any) + assert_type(s // left_i, Any) + assert_type(d // left_i, Any) # pyright: ignore[reportAssertTypeFailure] + + check(assert_type(left_i.floordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + # left_i.floordiv(d) # This invalid one cannot be detected by static type checking + + check(assert_type(left_i.rfloordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left_i.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) + + +def test_floordiv_pd_index(left_i: pd.Series) -> None: + """Test pd.Series[int] // pandas Indexes""" + b = pd.Index([True, True, True]) + i = pd.Index([2, 3, 5]) + f = pd.Index([1.0, 2.0, 3.0]) + c = pd.Index([1.1j, 2.2j, 4.1j]) + s = pd.Index([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) + + check(assert_type(left_i // b, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // i, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // f, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left_i // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left_i // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # _05 = left_i // d # This invalid one cannot be detected by static type checking + + check(assert_type(b // left_i, pd.Series), pd.Series, np.integer) + check(assert_type(i // left_i, pd.Series), pd.Series, np.integer) + check(assert_type(f // left_i, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left_i, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) + + check(assert_type(left_i.floordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + # left_i.floordiv(d) # This invalid one cannot be detected by static type checking + + check(assert_type(left_i.rfloordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left_i.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) + + +def test_floordiv_pd_series(left_i: pd.Series) -> None: + """Test pd.Series[int] // pandas Series""" + b = pd.Series([True, True, True]) + i = pd.Series([2, 3, 5]) + f = pd.Series([1.0, 2.0, 3.0]) + c = pd.Series([1.1j, 2.2j, 4.1j]) + s = pd.Series([datetime(2025, 10, d) for d in (27, 28, 29)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) + + check(assert_type(left_i // b, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // i, pd.Series), pd.Series, np.integer) + check(assert_type(left_i // f, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left_i // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left_i // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # _05 = left_i // d # This invalid one cannot be detected by static type checking + + check(assert_type(b // left_i, pd.Series), pd.Series, np.integer) + check(assert_type(i // left_i, pd.Series), pd.Series, np.integer) + check(assert_type(f // left_i, pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + _13 = c // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d // left_i, pd.Series), pd.Series, pd.Timedelta) + + check(assert_type(left_i.floordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + # left_i.floordiv(d) # This invalid one cannot be detected by static type checking + + check(assert_type(left_i.rfloordiv(b), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), pd.Series), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), pd.Series), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.rfloordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check( + assert_type(left_i.rfloordiv(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) diff --git a/tests/series/arithmetic/timedelta/test_floordiv.py b/tests/series/arithmetic/timedelta/test_floordiv.py index bb267d583..eb9a9935d 100644 --- a/tests/series/arithmetic/timedelta/test_floordiv.py +++ b/tests/series/arithmetic/timedelta/test_floordiv.py @@ -7,6 +7,7 @@ import numpy as np from numpy import typing as npt # noqa: F401 import pandas as pd +import pytest from typing_extensions import ( Never, assert_type, @@ -17,29 +18,34 @@ check, ) -left = pd.Series([pd.Timedelta(1, "s")]) # left operand +@pytest.fixture +def left() -> "pd.Series[pd.Timedelta]": + """Left operand""" + lo = pd.Series([pd.Timedelta(1, "s")]) + return check(assert_type(lo, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_floordiv_py_scalar() -> None: + +def test_floordiv_py_scalar(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] // Python native scalars""" b, i, f, c = True, 1, 1.0, 1j s, d = datetime(2025, 9, 24), timedelta(seconds=1) if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _00 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // i, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left // f, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // d, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: - _3 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _4 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _5 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _6 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _7 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _10 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _11 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _12 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d // left, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: @@ -68,26 +74,26 @@ def test_floordiv_py_scalar() -> None: check(assert_type(left.rfloordiv(d), "pd.Series[int]"), pd.Series, np.integer) -def test_floordiv_py_sequence() -> None: +def test_floordiv_py_sequence(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] // Python native sequences""" b, i, f, c = [True], [2], [1.5], [1.7j] s, d = [datetime(2025, 9, 24)], [timedelta(seconds=1)] if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _00 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // i, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left // f, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // d, "pd.Series[int]"), pd.Series, int) if TYPE_CHECKING_INVALID_USAGE: - _3 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _4 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _5 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _6 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _7 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _10 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _11 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _12 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d // left, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: @@ -116,7 +122,7 @@ def test_floordiv_py_sequence() -> None: check(assert_type(left.rfloordiv(d), "pd.Series[int]"), pd.Series, np.integer) -def test_floordiv_numpy_array() -> None: +def test_floordiv_numpy_array(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] // numpy arrays""" b = np.array([True], np.bool_) i = np.array([2], np.int64) @@ -171,16 +177,16 @@ def test_floordiv_numpy_array() -> None: check(assert_type(left.rfloordiv(d), "pd.Series[int]"), pd.Series, np.integer) -def test_floordiv_pd_scalar() -> None: +def test_floordiv_pd_scalar(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] // pandas scalars""" s, d = pd.Timestamp(2025, 9, 24), pd.Timedelta(seconds=1) if TYPE_CHECKING_INVALID_USAGE: - _0 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _00 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // d, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: - _1 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _10 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d // left, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: @@ -192,7 +198,7 @@ def test_floordiv_pd_scalar() -> None: check(assert_type(left.rfloordiv(d), "pd.Series[int]"), pd.Series, np.integer) -def test_floordiv_pd_index() -> None: +def test_floordiv_pd_index(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] // pandas Indexes""" b = pd.Index([True]) i = pd.Index([2]) @@ -201,20 +207,20 @@ def test_floordiv_pd_index() -> None: s, d = pd.Index([datetime(2025, 9, 24)]), pd.Index([timedelta(seconds=1)]) if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _00 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // i, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left // f, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // d, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: - _3 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _4 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _5 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _6 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _7 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _10 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _11 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _12 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d // left, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: @@ -243,7 +249,7 @@ def test_floordiv_pd_index() -> None: check(assert_type(left.rfloordiv(d), "pd.Series[int]"), pd.Series, np.integer) -def test_floordiv_pd_series() -> None: +def test_floordiv_pd_series(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] // pandas Series""" b = pd.Series([True]) i = pd.Series([2]) @@ -252,20 +258,20 @@ def test_floordiv_pd_series() -> None: s, d = pd.Series([datetime(2025, 9, 24)]), pd.Series([timedelta(seconds=1)]) if TYPE_CHECKING_INVALID_USAGE: - _0 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _00 = left // b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // i, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left // f, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - _1 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _2 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _03 = left // c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left // s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left // d, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: - _3 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _4 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _5 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _6 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _7 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _10 = b // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _11 = i // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _12 = f // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _13 = c // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s // left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d // left, "pd.Series[int]"), pd.Series, np.integer) if TYPE_CHECKING_INVALID_USAGE: diff --git a/tests/series/arithmetic/timedelta/test_truediv.py b/tests/series/arithmetic/timedelta/test_truediv.py index da7fad64f..724a17c8e 100644 --- a/tests/series/arithmetic/timedelta/test_truediv.py +++ b/tests/series/arithmetic/timedelta/test_truediv.py @@ -7,6 +7,7 @@ import numpy as np from numpy import typing as npt # noqa: F401 import pandas as pd +import pytest from typing_extensions import ( Never, assert_type, @@ -17,10 +18,15 @@ check, ) -left = pd.Series([pd.Timedelta(1, "s")]) # left operand +@pytest.fixture +def left() -> "pd.Series[pd.Timedelta]": + """Left operand""" + lo = pd.Series([pd.Timedelta(1, "s")]) + return check(assert_type(lo, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_truediv_py_scalar() -> None: + +def test_truediv_py_scalar(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] / Python native scalars""" b, i, f, c = True, 1, 1.0, 1j s, d = datetime(2025, 9, 24), timedelta(seconds=1) @@ -81,7 +87,7 @@ def test_truediv_py_scalar() -> None: check(assert_type(left.rdiv(d), "pd.Series[float]"), pd.Series, np.floating) -def test_truediv_py_sequence() -> None: +def test_truediv_py_sequence(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] / Python native sequences""" b, i, f, c = [True], [2], [1.5], [1.7j] s, d = [datetime(2025, 9, 24)], [timedelta(seconds=1)] @@ -142,7 +148,7 @@ def test_truediv_py_sequence() -> None: check(assert_type(left.rdiv(d), "pd.Series[float]"), pd.Series, np.floating) -def test_truediv_numpy_array() -> None: +def test_truediv_numpy_array(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] / numpy arrays""" b = np.array([True], np.bool_) i = np.array([2], np.int64) @@ -210,7 +216,7 @@ def test_truediv_numpy_array() -> None: check(assert_type(left.rdiv(d), "pd.Series[float]"), pd.Series, np.floating) -def test_truediv_pd_scalar() -> None: +def test_truediv_pd_scalar(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] / pandas scalars""" s, d = pd.Timestamp(2025, 9, 24), pd.Timedelta(seconds=1) @@ -239,7 +245,7 @@ def test_truediv_pd_scalar() -> None: check(assert_type(left.rdiv(d), "pd.Series[float]"), pd.Series, np.floating) -def test_truediv_pd_index() -> None: +def test_truediv_pd_index(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] / pandas Indexes""" b = pd.Index([True]) i = pd.Index([2]) @@ -303,7 +309,7 @@ def test_truediv_pd_index() -> None: check(assert_type(left.rdiv(d), "pd.Series[float]"), pd.Series, np.floating) -def test_truediv_pd_series() -> None: +def test_truediv_pd_series(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] / pandas Series""" b = pd.Series([True]) i = pd.Series([2]) diff --git a/tests/series/test_series.py b/tests/series/test_series.py index 73bc51bb5..474649999 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -824,7 +824,6 @@ def test_types_element_wise_arithmetic() -> None: assert_type(s.div(s2, fill_value=0), "pd.Series[float]"), pd.Series, np.float64 ) - _res_floordiv: pd.Series = s // s2 _res_floordiv2: pd.Series = s.floordiv(s2, fill_value=0) _res_mod: pd.Series = s % s2 @@ -854,7 +853,6 @@ def test_types_scalar_arithmetic() -> None: assert_type(s.div(2, fill_value=0), "pd.Series[float]"), pd.Series, np.floating ) - _res_floordiv: pd.Series = s // 2 _res_floordiv2: pd.Series = s.floordiv(2, fill_value=0) _res_mod: pd.Series = s % 2