From a0741239e5bfb60c9804830e767485d12e54073e Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 19 Oct 2025 22:49:04 +0200 Subject: [PATCH 01/23] floordiv --- pandas-stubs/core/base.pyi | 79 +++++- pandas-stubs/core/indexes/base.pyi | 127 +++++++-- pandas-stubs/core/indexes/datetimes.pyi | 27 +- pandas-stubs/core/indexes/timedeltas.pyi | 59 ++-- pandas-stubs/core/series.pyi | 259 +++++++++--------- .../indexes/arithmetic/float/test_truediv.py | 49 +++- tests/indexes/arithmetic/int/test_floordiv.py | 127 +++++++++ tests/indexes/arithmetic/int/test_truediv.py | 49 +++- .../timedeltaindex/test_floordiv.py | 141 ++++++++++ .../series/arithmetic/float/test_floordiv.py | 167 ++++++++--- tests/series/arithmetic/float/test_truediv.py | 132 ++++++++- tests/series/arithmetic/int/test_floordiv.py | 173 ++++++++---- tests/series/arithmetic/int/test_truediv.py | 28 ++ .../arithmetic/timedelta/test_floordiv.py | 88 +++--- tests/test_natype.py | 17 +- 15 files changed, 1180 insertions(+), 342 deletions(-) create mode 100644 tests/indexes/arithmetic/int/test_floordiv.py create mode 100644 tests/indexes/arithmetic/timedeltaindex/test_floordiv.py diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index ea3865add..55af19d4f 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -29,6 +29,7 @@ from pandas._libs.tslibs.timedeltas import Timedelta from pandas._typing import ( S1, S2, + S3, AxisIndex, DropKeep, DTypeLike, @@ -280,7 +281,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 +297,56 @@ 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]: ... + @overload + def _proto_mod( + self: ElementOpsMixin[int], other: int | np.integer + ) -> ElementOpsMixin[int]: ... + @overload + def _proto_mod( + self: ElementOpsMixin[float], other: float | np.floating + ) -> ElementOpsMixin[float]: ... + @overload + def _proto_mod( + self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta + ) -> ElementOpsMixin[Timedelta]: ... + @overload + def _proto_rmod( + self: ElementOpsMixin[int], other: int | np.integer + ) -> ElementOpsMixin[int]: ... + @overload + def _proto_rmod( + self: ElementOpsMixin[float], other: float | np.floating + ) -> ElementOpsMixin[float]: ... + @overload + def _proto_rmod( + self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta + ) -> ElementOpsMixin[Timedelta]: ... @type_check_only class Supports_ProtoAdd(Protocol[_T_contra, S2]): @@ -322,3 +371,29 @@ 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]: ... + +@type_check_only +class Supports_ProtoMod(Protocol[_T_contra, S2]): + def _proto_mod(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... + +@type_check_only +class Supports_ProtoRMod(Protocol[_T_contra, S2]): + def _proto_rmod(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... + +@type_check_only +class Supports_ProtoDivMod(Protocol[_T_contra, S2, S3]): + def _proto_floordiv(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... + def _proto_mod(self, other: _T_contra, /) -> ElementOpsMixin[S3]: ... + +@type_check_only +class Supports_ProtoRDivMod(Protocol[_T_contra, S2, S3]): + def _proto_rfloordiv(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... + def _proto_rmod(self, other: _T_contra, /) -> ElementOpsMixin[S3]: ... diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 21aa39db3..0c9f4a445 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -29,37 +29,38 @@ 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.arrays.boolean import BooleanArray 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, @@ -97,6 +98,7 @@ from pandas._typing import ( TimedeltaDtypeArg, TimestampDtypeArg, np_1darray, + np_ndarray, np_ndarray_anyint, np_ndarray_bool, np_ndarray_complex, @@ -107,6 +109,8 @@ from pandas._typing import ( type_t, ) +from pandas.core.dtypes.dtypes import PeriodDtype + class InvalidIndexError(Exception): ... class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @@ -942,14 +946,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__( @@ -993,10 +1000,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], @@ -1041,13 +1050,91 @@ 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: Index[Never]) -> Index: ... + @overload def __floordiv__( - self, other: float | Sequence[float] | Index[int] | Index[float] - ) -> Self: ... + 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: Index[Never]) -> Index: ... # type: ignore[overload-overlap] + @overload def __rfloordiv__( - self, other: float | Sequence[float] | Index[int] | Index[float] - ) -> Self: ... + 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 58166f29f..0ecf7a9a0 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..1eec0d158 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 # type: ignore[override] + 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 c05af4813..29b345631 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, @@ -2153,7 +2155,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @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 +2163,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 +2201,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,14 +2213,7 @@ 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], ) -> Series[int]: ... @overload def floordiv( @@ -2239,47 +2224,50 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): 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 +2279,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,14 +2294,7 @@ 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, @@ -2324,7 +2304,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @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 +2312,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,16 +2351,14 @@ 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: ( - timedelta - | Sequence[timedelta] - | np.timedelta64 - | np_ndarray_td - | TimedeltaIndex - | Series[Timedelta] - ), + other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], ) -> Series[int]: ... @overload def rfloordiv( @@ -2400,47 +2369,50 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): 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 +2420,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 +2431,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 +3561,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 +3821,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_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/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/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..18d38e661 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, 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) @@ -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..52c3f66a0 100644 --- a/tests/series/arithmetic/int/test_truediv.py +++ b/tests/series/arithmetic/int/test_truediv.py @@ -1,3 +1,8 @@ +from datetime import ( + datetime, + timedelta, +) + import numpy as np from numpy import typing as npt # noqa: F401 import pandas as pd @@ -20,16 +25,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 +51,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 +71,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,6 +85,9 @@ 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: 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/test_natype.py b/tests/test_natype.py index 7a524bc37..c55d07a47 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -83,11 +83,8 @@ def test_arithmetic() -> None: # __divmod__ # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 # check( - # assert_type( - # divmod(na, s_int), - # tuple[pd.Series, pd.Series], - # ), - # tuple, + assert_type(divmod(na, s_int), tuple[pd.Series, pd.Series]) + # , tuple # ) # check( # assert_type( @@ -110,13 +107,13 @@ def test_arithmetic() -> None: # __rdivmod__ # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 # check( - # assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), - # tuple, + assert_type(divmod(s_int, na), "tuple[pd.Series[int], pd.Series[int]]") + # , tuple, # ) - # https://github.com/pandas-dev/pandas-stubs/issues/1347 + # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 # check( - # assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), - # tuple, + assert_type(divmod(idx_int, na), "tuple[pd.Index[int], pd.Index[int]]") + # , tuple, # ) check(assert_type(divmod(1, na), tuple[NAType, NAType]), tuple) From 7a32e45f6d094928319f9895d63b8c890f3d671b Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 28 Oct 2025 11:22:29 +0100 Subject: [PATCH 02/23] remove irrelevant changes --- pandas-stubs/core/base.pyi | 43 -------------------------------------- tests/test_natype.py | 16 ++++++++++---- 2 files changed, 12 insertions(+), 47 deletions(-) diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index 55af19d4f..e9447a76f 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -29,7 +29,6 @@ from pandas._libs.tslibs.timedeltas import Timedelta from pandas._typing import ( S1, S2, - S3, AxisIndex, DropKeep, DTypeLike, @@ -323,30 +322,6 @@ class ElementOpsMixin(Generic[S2]): def _proto_rfloordiv( self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta ) -> ElementOpsMixin[int]: ... - @overload - def _proto_mod( - self: ElementOpsMixin[int], other: int | np.integer - ) -> ElementOpsMixin[int]: ... - @overload - def _proto_mod( - self: ElementOpsMixin[float], other: float | np.floating - ) -> ElementOpsMixin[float]: ... - @overload - def _proto_mod( - self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta - ) -> ElementOpsMixin[Timedelta]: ... - @overload - def _proto_rmod( - self: ElementOpsMixin[int], other: int | np.integer - ) -> ElementOpsMixin[int]: ... - @overload - def _proto_rmod( - self: ElementOpsMixin[float], other: float | np.floating - ) -> ElementOpsMixin[float]: ... - @overload - def _proto_rmod( - self: ElementOpsMixin[Timedelta], other: timedelta | np.timedelta64 | Timedelta - ) -> ElementOpsMixin[Timedelta]: ... @type_check_only class Supports_ProtoAdd(Protocol[_T_contra, S2]): @@ -379,21 +354,3 @@ class Supports_ProtoFloorDiv(Protocol[_T_contra, S2]): @type_check_only class Supports_ProtoRFloorDiv(Protocol[_T_contra, S2]): def _proto_rfloordiv(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... - -@type_check_only -class Supports_ProtoMod(Protocol[_T_contra, S2]): - def _proto_mod(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... - -@type_check_only -class Supports_ProtoRMod(Protocol[_T_contra, S2]): - def _proto_rmod(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... - -@type_check_only -class Supports_ProtoDivMod(Protocol[_T_contra, S2, S3]): - def _proto_floordiv(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... - def _proto_mod(self, other: _T_contra, /) -> ElementOpsMixin[S3]: ... - -@type_check_only -class Supports_ProtoRDivMod(Protocol[_T_contra, S2, S3]): - def _proto_rfloordiv(self, other: _T_contra, /) -> ElementOpsMixin[S2]: ... - def _proto_rmod(self, other: _T_contra, /) -> ElementOpsMixin[S3]: ... diff --git a/tests/test_natype.py b/tests/test_natype.py index c55d07a47..f1016374f 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -83,8 +83,11 @@ def test_arithmetic() -> None: # __divmod__ # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 # check( - assert_type(divmod(na, s_int), tuple[pd.Series, pd.Series]) - # , tuple + # assert_type( + # divmod(na, s_int), + # tuple[pd.Series, pd.Series], + # ), + # tuple, # ) # check( # assert_type( @@ -107,8 +110,13 @@ def test_arithmetic() -> None: # __rdivmod__ # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 # check( - assert_type(divmod(s_int, na), "tuple[pd.Series[int], pd.Series[int]]") - # , tuple, + # assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), + # tuple, + # ) + # https://github.com/pandas-dev/pandas-stubs/issues/1347 + # check( + # assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), + # tuple, # , tuple, # ) # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 # check( From cb1506ad9fa2faefdaf99d46a5769da2d3463db6 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 28 Oct 2025 11:59:50 +0100 Subject: [PATCH 03/23] floordiv --- pandas-stubs/core/indexes/base.pyi | 34 ++- pandas-stubs/core/series.pyi | 26 ++ .../indexes/arithmetic/float/test_floordiv.py | 131 +++++++++ tests/indexes/arithmetic/test_floordiv.py | 127 +++++++++ tests/series/arithmetic/test_floordiv.py | 253 ++++++++++++++++++ 5 files changed, 569 insertions(+), 2 deletions(-) create mode 100644 tests/indexes/arithmetic/float/test_floordiv.py create mode 100644 tests/indexes/arithmetic/test_floordiv.py create mode 100644 tests/series/arithmetic/test_floordiv.py diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 0c9f4a445..534ac4825 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -1057,7 +1057,23 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @overload def __rtruediv__(self, other: Path) -> Index: ... @overload - def __floordiv__(self, other: Index[Never]) -> Index: ... + def __floordiv__( + 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], @@ -1094,7 +1110,21 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): other: float | Sequence[float] | np_ndarray_float | Index[float], ) -> Index[float]: ... @overload - def __rfloordiv__(self, other: Index[Never]) -> Index: ... # type: ignore[overload-overlap] + def __rfloordiv__( + 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], diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 29b345631..40b4c20cd 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2151,6 +2151,19 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): 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: Series[Never], + other: ( + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index + | Series + ), + ) -> Series: ... + @overload def __floordiv__(self, other: Index[Never] | Series[Never]) -> Series: ... @overload def __floordiv__( @@ -2300,6 +2313,19 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): axis: AxisIndex | None = 0, ) -> Series[int]: ... @overload + def __rfloordiv__( + self: Series[Never], + other: ( + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index + | Series + ), + ) -> Series: ... + @overload def __rfloordiv__(self, other: Index[Never] | Series[Never]) -> Series: ... @overload def __rfloordiv__( 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/test_floordiv.py b/tests/indexes/arithmetic/test_floordiv.py new file mode 100644 index 000000000..76a3bed1e --- /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, "np.typing.NDArray[np.int64]") + + +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/series/arithmetic/test_floordiv.py b/tests/series/arithmetic/test_floordiv.py new file mode 100644 index 000000000..12cc69322 --- /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[int]"), pd.Series, np.integer) + check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i // f, "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(i // left_i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(f // left_i, "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) + if TYPE_CHECKING_INVALID_USAGE: + left_i.floordiv(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.floordiv(d) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + + check(assert_type(left_i.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i // f, "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(i // left_i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(f // left_i, "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i // f, "pd.Series[float]"), 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, "np.typing.NDArray[np.int64]") + + check(assert_type(left_i.floordiv(b), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i // f, "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(i // left_i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(f // left_i, "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i // f, "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(i // left_i, "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(f // left_i, "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.floordiv(f), "pd.Series[float]"), 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[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) + check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), 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, + ) From 0f86bc870560ab9012b4a3ae8fac7732ecde4681 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 28 Oct 2025 12:03:58 +0100 Subject: [PATCH 04/23] remove irrelevant change --- tests/test_natype.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/test_natype.py b/tests/test_natype.py index f1016374f..f9bc17162 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -116,12 +116,6 @@ def test_arithmetic() -> None: # https://github.com/pandas-dev/pandas-stubs/issues/1347 # check( # assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), - # tuple, # , tuple, - # ) - # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 - # check( - assert_type(divmod(idx_int, na), "tuple[pd.Index[int], pd.Index[int]]") - # , tuple, # ) check(assert_type(divmod(1, na), tuple[NAType, NAType]), tuple) From e1090cf07499fcfd64e05b2c724e0c7998069444 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 28 Oct 2025 13:46:59 +0100 Subject: [PATCH 05/23] floordiv --- pandas-stubs/core/indexes/timedeltas.pyi | 2 +- pandas-stubs/core/series.pyi | 77 ++++++++-- tests/indexes/arithmetic/test_floordiv.py | 2 +- tests/indexes/test_indexes.py | 39 ----- tests/scalars/test_scalars.py | 29 ---- tests/series/arithmetic/float/test_truediv.py | 2 +- tests/series/arithmetic/int/test_truediv.py | 108 +++++++++++++- tests/series/arithmetic/test_floordiv.py | 134 +++++++++--------- .../arithmetic/timedelta/test_truediv.py | 20 ++- tests/series/test_series.py | 2 - tests/test_natype.py | 1 + 11 files changed, 256 insertions(+), 160 deletions(-) diff --git a/pandas-stubs/core/indexes/timedeltas.pyi b/pandas-stubs/core/indexes/timedeltas.pyi index 1eec0d158..2f632cd8a 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -133,7 +133,7 @@ class TimedeltaIndex( def __floordiv__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: _DT_FACTOR_SEQ | Self ) -> Index[int]: ... - @overload # type: ignore[override] + @overload def __rfloordiv__( # pyrefly: ignore[bad-override] self, other: ( diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 40b4c20cd..9d99f09cb 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2143,15 +2143,14 @@ 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__( + def __floordiv__( # type: ignore[overload-overlap] self: Series[Never], other: ( float @@ -2159,12 +2158,19 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): | np_ndarray_bool | np_ndarray_anyint | np_ndarray_float - | Index - | Series + | Index[bool] + | Index[int] + | Index[float] + | Series[bool] + | Series[int] + | Series[float] ), ) -> Series: ... @overload - def __floordiv__(self, other: Index[Never] | Series[Never]) -> Series: ... + 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], @@ -2230,7 +2236,27 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[int]: ... @overload def floordiv( - self, + 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] + ), + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, + ) -> Series: ... + @overload + def floordiv( + self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], other: Index[Never] | Series[Never], level: Level | None = ..., fill_value: float | None = None, @@ -2313,7 +2339,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): axis: AxisIndex | None = 0, ) -> Series[int]: ... @overload - def __rfloordiv__( + def __rfloordiv__( # type: ignore[overload-overlap] self: Series[Never], other: ( float @@ -2321,12 +2347,19 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): | np_ndarray_bool | np_ndarray_anyint | np_ndarray_float - | Index - | Series + | Index[bool] + | Index[int] + | Index[float] + | Series[bool] + | Series[int] + | Series[float] ), ) -> Series: ... @overload - def __rfloordiv__(self, other: Index[Never] | Series[Never]) -> Series: ... + 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], @@ -2388,7 +2421,27 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[int]: ... @overload def rfloordiv( - self, + 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] + ), + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, + ) -> Series: ... + @overload + def rfloordiv( + self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], other: Index[Never] | Series[Never], level: Level | None = ..., fill_value: float | None = None, diff --git a/tests/indexes/arithmetic/test_floordiv.py b/tests/indexes/arithmetic/test_floordiv.py index 76a3bed1e..82f3dbc8a 100644 --- a/tests/indexes/arithmetic/test_floordiv.py +++ b/tests/indexes/arithmetic/test_floordiv.py @@ -98,7 +98,7 @@ def test_floordiv_numpy_array(left_i: pd.Index) -> None: if TYPE_CHECKING_INVALID_USAGE: assert_type(c // left_i, Any) assert_type(s // left_i, Any) - assert_type(d // left_i, "np.typing.NDArray[np.int64]") + assert_type(d // left_i, Any) # pyright: ignore[reportAssertTypeFailure] def test_floordiv_pd_index(left_i: pd.Index) -> None: diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index 6c25d5e13..486bb82ad 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -265,17 +265,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( @@ -846,9 +835,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) @@ -1197,31 +1183,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_truediv.py b/tests/series/arithmetic/float/test_truediv.py index 18d38e661..9b330fce8 100644 --- a/tests/series/arithmetic/float/test_truediv.py +++ b/tests/series/arithmetic/float/test_truediv.py @@ -114,7 +114,7 @@ def test_truediv_py_sequence(left: "pd.Series[float]") -> None: 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(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) diff --git a/tests/series/arithmetic/int/test_truediv.py b/tests/series/arithmetic/int/test_truediv.py index 52c3f66a0..1cda6bdb9 100644 --- a/tests/series/arithmetic/int/test_truediv.py +++ b/tests/series/arithmetic/int/test_truediv.py @@ -2,12 +2,16 @@ 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, @@ -93,16 +97,24 @@ def test_truediv_py_scalar(left: "pd.Series[int]") -> None: 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) @@ -112,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) @@ -126,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) @@ -133,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: @@ -141,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 @@ -158,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) @@ -167,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) @@ -181,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) @@ -188,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: @@ -229,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) @@ -248,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) @@ -262,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) @@ -269,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: @@ -277,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) @@ -296,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) @@ -310,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) @@ -317,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 index 12cc69322..6f563bc14 100644 --- a/tests/series/arithmetic/test_floordiv.py +++ b/tests/series/arithmetic/test_floordiv.py @@ -30,33 +30,33 @@ def test_floordiv_py_scalar(left_i: pd.Series) -> None: 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[int]"), pd.Series, np.integer) - check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i // f, "pd.Series[float]"), pd.Series, np.floating) + 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[int]"), pd.Series, np.integer) - check(assert_type(i // left_i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(f // left_i, "pd.Series[float]"), pd.Series, np.floating) + 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[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] - left_i.floordiv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] - left_i.floordiv(d) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + 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[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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] @@ -73,33 +73,33 @@ def test_floordiv_py_sequence(left_i: pd.Series) -> None: 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[int]"), pd.Series, np.integer) - check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i // f, "pd.Series[float]"), pd.Series, np.floating) + 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[int]"), pd.Series, np.integer) - check(assert_type(i // left_i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(f // left_i, "pd.Series[float]"), pd.Series, np.floating) + 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[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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] @@ -121,9 +121,9 @@ def test_floordiv_numpy_array(left_i: pd.Series) -> None: ) d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) - check(assert_type(left_i // b, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i // f, "pd.Series[float]"), pd.Series, np.floating) + 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) @@ -138,19 +138,19 @@ def test_floordiv_numpy_array(left_i: pd.Series) -> None: if TYPE_CHECKING_INVALID_USAGE: assert_type(c // left_i, Any) assert_type(s // left_i, Any) - assert_type(d // left_i, "np.typing.NDArray[np.int64]") + assert_type(d // left_i, Any) # pyright: ignore[reportAssertTypeFailure] - check(assert_type(left_i.floordiv(b), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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] + # left_i.floordiv(d) # This invalid one cannot be detected by static type checking - check(assert_type(left_i.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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] @@ -170,33 +170,33 @@ def test_floordiv_pd_index(left_i: pd.Series) -> None: 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[int]"), pd.Series, np.integer) - check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i // f, "pd.Series[float]"), pd.Series, np.floating) + 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] + # _05 = left_i // d # This invalid one cannot be detected by static type checking - check(assert_type(b // left_i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(i // left_i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(f // left_i, "pd.Series[float]"), pd.Series, np.floating) + 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[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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] + # left_i.floordiv(d) # This invalid one cannot be detected by static type checking - check(assert_type(left_i.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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] @@ -216,33 +216,33 @@ def test_floordiv_pd_series(left_i: pd.Series) -> None: 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[int]"), pd.Series, np.integer) - check(assert_type(left_i // i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i // f, "pd.Series[float]"), pd.Series, np.floating) + 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] + # _05 = left_i // d # This invalid one cannot be detected by static type checking - check(assert_type(b // left_i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(i // left_i, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(f // left_i, "pd.Series[float]"), pd.Series, np.floating) + 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(d // left_i, pd.Series), pd.Series, pd.Timedelta) - check(assert_type(left_i.floordiv(b), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.floordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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] + # left_i.floordiv(d) # This invalid one cannot be detected by static type checking - check(assert_type(left_i.rfloordiv(b), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(i), "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(left_i.rfloordiv(f), "pd.Series[float]"), pd.Series, np.floating) + 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] 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 diff --git a/tests/test_natype.py b/tests/test_natype.py index f9bc17162..7a524bc37 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -116,6 +116,7 @@ def test_arithmetic() -> None: # https://github.com/pandas-dev/pandas-stubs/issues/1347 # check( # assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), + # tuple, # ) check(assert_type(divmod(1, na), tuple[NAType, NAType]), tuple) From 32bf36c6e33dc092311fb05928b63fff1ec5aff6 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 29 Oct 2025 14:10:00 +0100 Subject: [PATCH 06/23] pyright --- pandas-stubs/core/indexes/range.pyi | 15 +++++++-------- tests/indexes/test_indexes.py | 13 +++++-------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/pandas-stubs/core/indexes/range.pyi b/pandas-stubs/core/indexes/range.pyi index 8194dac79..0c66af309 100644 --- a/pandas-stubs/core/indexes/range.pyi +++ b/pandas-stubs/core/indexes/range.pyi @@ -4,7 +4,6 @@ from collections.abc import ( ) from typing import ( Any, - final, overload, ) @@ -66,16 +65,16 @@ class RangeIndex(_IndexSubclassBase[int, np.int64]): ) -> tuple[np_1darray[np.intp], RangeIndex]: ... @property def size(self) -> int: ... - # Base class returns `Self`, but for `RangeIndex` that's not true. - def __floordiv__( # type: ignore[override] - self, other: float | Sequence[float] | Index[int] | Index[float] - ) -> Index[int]: ... def all(self, *args: Any, **kwargs: Any) -> bool: ... def any(self, *args: Any, **kwargs: Any) -> bool: ... - @final + @overload + def union( # type: ignore[override] + self, other: Sequence[int] | Index[int] | Self, sort: bool | None = None + ) -> Index[int] | Self: ... + @overload def union( # type: ignore[override] - self, other: list[HashableT] | Index, sort: bool | None = None - ) -> Index | Index[int] | RangeIndex: ... + self, other: Sequence[HashableT] | Index, sort: bool | None = None + ) -> Index: ... @overload # type: ignore[override] # pyrefly: ignore # bad-override def __getitem__( diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index 486bb82ad..13aada23e 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -5,7 +5,6 @@ from typing import ( TYPE_CHECKING, Any, - Union, cast, ) @@ -269,23 +268,21 @@ def test_range_index_union() -> None: check( assert_type( pd.RangeIndex(0, 10).union(pd.RangeIndex(10, 20)), - Union[pd.Index, "pd.Index[int]", pd.RangeIndex], + "pd.Index[int] | pd.RangeIndex", ), pd.RangeIndex, ) check( assert_type( - pd.RangeIndex(0, 10).union([11, 12, 13]), - Union[pd.Index, "pd.Index[int]", pd.RangeIndex], + pd.RangeIndex(0, 10).union([11, 12, 13]), "pd.Index[int] | pd.RangeIndex" ), pd.Index, + int, ) check( - assert_type( - pd.RangeIndex(0, 10).union(["a", "b", "c"]), - Union[pd.Index, "pd.Index[int]", pd.RangeIndex], - ), + assert_type(pd.RangeIndex(0, 10).union(["a", "b", "c"]), pd.Index), pd.Index, + str, ) From 7f7cab4e942644a17713e9eada01a667d37de36f Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 29 Oct 2025 14:15:11 +0100 Subject: [PATCH 07/23] mypy --- pandas-stubs/core/indexes/range.pyi | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pandas-stubs/core/indexes/range.pyi b/pandas-stubs/core/indexes/range.pyi index 0c66af309..ce0b4e613 100644 --- a/pandas-stubs/core/indexes/range.pyi +++ b/pandas-stubs/core/indexes/range.pyi @@ -67,16 +67,15 @@ class RangeIndex(_IndexSubclassBase[int, np.int64]): def size(self) -> int: ... def all(self, *args: Any, **kwargs: Any) -> bool: ... def any(self, *args: Any, **kwargs: Any) -> bool: ... - @overload - def union( # type: ignore[override] + @overload # type: ignore[override] + def union( self, other: Sequence[int] | Index[int] | Self, sort: bool | None = None ) -> Index[int] | Self: ... @overload - def union( # type: ignore[override] + def union( self, other: Sequence[HashableT] | Index, sort: bool | None = None ) -> Index: ... - @overload # type: ignore[override] - # pyrefly: ignore # bad-override + @overload # type: ignore[override] # pyrefly: ignore[bad-override] def __getitem__( self, idx: slice | np_ndarray_anyint | Sequence[int] | Index | MaskType, From 5b997b686ef48d66259c36e7f088b1064a566131 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 29 Oct 2025 14:20:24 +0100 Subject: [PATCH 08/23] pytest --- tests/indexes/test_indexes.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index 13aada23e..0b5cb6fc1 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -279,11 +279,7 @@ def test_range_index_union() -> None: pd.Index, int, ) - check( - assert_type(pd.RangeIndex(0, 10).union(["a", "b", "c"]), pd.Index), - pd.Index, - str, - ) + check(assert_type(pd.RangeIndex(0, 10).union(["a", "b", "c"]), pd.Index), pd.Index) def test_index_union_sort() -> None: From dca5fa2316b80430cfaa2934c944f3588e6e5fce Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 29 Oct 2025 15:07:29 +0100 Subject: [PATCH 09/23] pyrefly --- pandas-stubs/_typing.pyi | 3 +-- pandas-stubs/core/indexes/range.pyi | 6 +++--- pandas-stubs/core/series.pyi | 15 +++++---------- tests/indexes/test_indexes.py | 2 +- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 5f0277185..8b9ec6264 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -1114,8 +1114,7 @@ Incomplete: TypeAlias = Any class Just(Protocol, Generic[T]): @property # type: ignore[override] @override - # pyrefly: ignore # bad-override - def __class__(self, /) -> type[T]: ... + def __class__(self, /) -> type[T]: ... # pyrefly: ignore[bad-override] @__class__.setter @override def __class__(self, t: type[T], /) -> None: ... diff --git a/pandas-stubs/core/indexes/range.pyi b/pandas-stubs/core/indexes/range.pyi index ce0b4e613..8ffb2e0fa 100644 --- a/pandas-stubs/core/indexes/range.pyi +++ b/pandas-stubs/core/indexes/range.pyi @@ -68,15 +68,15 @@ class RangeIndex(_IndexSubclassBase[int, np.int64]): def all(self, *args: Any, **kwargs: Any) -> bool: ... def any(self, *args: Any, **kwargs: Any) -> bool: ... @overload # type: ignore[override] - def union( + def union( # pyrefly: ignore[bad-override] self, other: Sequence[int] | Index[int] | Self, sort: bool | None = None ) -> Index[int] | Self: ... @overload def union( self, other: Sequence[HashableT] | Index, sort: bool | None = None ) -> Index: ... - @overload # type: ignore[override] # pyrefly: ignore[bad-override] - def __getitem__( + @overload # type: ignore[override] + def __getitem__( # pyrefly: ignore[bad-override] self, idx: slice | np_ndarray_anyint | Sequence[int] | Index | MaskType, ) -> Index: ... diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 9d99f09cb..7955ba33a 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2966,16 +2966,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): def __pow__(self, other: num | ListLike | Series[S1]) -> Series[S1]: ... # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] - # pyrefly: ignore # bad-override - def __or__( # pyright: ignore[reportOverlappingOverload] + def __or__( # pyright: ignore[reportOverlappingOverload] # pyrefly: ignore[bad-override] self, other: bool | list[int] | MaskType ) -> Series[bool]: ... @overload def __or__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] - # pyrefly: ignore # bad-override - def __rand__( # pyright: ignore[reportOverlappingOverload] + def __rand__( # pyright: ignore[reportOverlappingOverload] # pyrefly: ignore[bad-override] self, other: bool | MaskType | list[int] ) -> Series[bool]: ... @overload @@ -2985,16 +2983,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): def __rpow__(self, other: num | ListLike | Series[S1]) -> Series[S1]: ... # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] - # pyrefly: ignore # bad-override - def __ror__( # pyright: ignore[reportOverlappingOverload] + def __ror__( # pyright: ignore[reportOverlappingOverload] # pyrefly: ignore[bad-override] self, other: bool | MaskType | list[int] ) -> Series[bool]: ... @overload def __ror__(self, other: int | np_ndarray_anyint | Series[int]) -> Series[int]: ... # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] - # pyrefly: ignore # bad-override - def __rxor__( # pyright: ignore[reportOverlappingOverload] + def __rxor__( # pyright: ignore[reportOverlappingOverload] # pyrefly: ignore[bad-override] self, other: bool | MaskType | list[int] ) -> Series[bool]: ... @overload @@ -4140,8 +4136,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): rdiv = rtruediv # ignore needed for mypy as we want different results based on the arguments @overload # type: ignore[override] - # pyrefly: ignore # bad-override - def __xor__( # pyright: ignore[reportOverlappingOverload] + def __xor__( # pyright: ignore[reportOverlappingOverload] # pyrefly: ignore[bad-override] self, other: bool | MaskType | list[int] ) -> Series[bool]: ... @overload diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index 0b5cb6fc1..92df8721f 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -277,7 +277,7 @@ def test_range_index_union() -> None: pd.RangeIndex(0, 10).union([11, 12, 13]), "pd.Index[int] | pd.RangeIndex" ), pd.Index, - int, + np.integer, ) check(assert_type(pd.RangeIndex(0, 10).union(["a", "b", "c"]), pd.Index), pd.Index) From c95aa395feaf6ec1f0da7e61f39469a2e0288508 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 5 Nov 2025 13:31:07 +0100 Subject: [PATCH 10/23] fix: np.ndarray // pd.IndexOpsMixin --- tests/indexes/arithmetic/float/test_floordiv.py | 8 +++++--- tests/indexes/arithmetic/int/test_floordiv.py | 14 ++++++++++---- tests/indexes/arithmetic/test_floordiv.py | 14 ++++++++++---- tests/series/arithmetic/int/test_floordiv.py | 12 ++++++++---- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/tests/indexes/arithmetic/float/test_floordiv.py b/tests/indexes/arithmetic/float/test_floordiv.py index 45faab573..e52d58dfa 100644 --- a/tests/indexes/arithmetic/float/test_floordiv.py +++ b/tests/indexes/arithmetic/float/test_floordiv.py @@ -92,9 +92,11 @@ def test_floordiv_numpy_array(left: "pd.Index[float]") -> None: # `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) + check(assert_type(b // left, "np.typing.NDArray[np.int8]"), pd.Index, np.floating) + check(assert_type(i // left, "np.typing.NDArray[np.int64]"), pd.Index, np.floating) + check( + assert_type(f // left, "np.typing.NDArray[np.float64]"), pd.Index, np.floating + ) if TYPE_CHECKING_INVALID_USAGE: assert_type(c // left, Any) assert_type(s // left, Any) diff --git a/tests/indexes/arithmetic/int/test_floordiv.py b/tests/indexes/arithmetic/int/test_floordiv.py index fe3d2766b..d0578248d 100644 --- a/tests/indexes/arithmetic/int/test_floordiv.py +++ b/tests/indexes/arithmetic/int/test_floordiv.py @@ -92,13 +92,19 @@ def test_floordiv_numpy_array(left: "pd.Index[int]") -> None: # `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) + check(assert_type(b // left, "np.typing.NDArray[np.int8]"), pd.Index, np.integer) + check(assert_type(i // left, "np.typing.NDArray[np.int64]"), pd.Index, np.integer) + check( + assert_type(f // left, "np.typing.NDArray[np.float64]"), 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]") + check( + assert_type(d // left, "np.typing.NDArray[np.int64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) def test_floordiv_pd_index(left: "pd.Index[int]") -> None: diff --git a/tests/indexes/arithmetic/test_floordiv.py b/tests/indexes/arithmetic/test_floordiv.py index 82f3dbc8a..da78dd79c 100644 --- a/tests/indexes/arithmetic/test_floordiv.py +++ b/tests/indexes/arithmetic/test_floordiv.py @@ -92,13 +92,19 @@ def test_floordiv_numpy_array(left_i: pd.Index) -> None: # `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) + check(assert_type(b // left_i, "np.typing.NDArray[np.int8]"), pd.Index, np.integer) + check(assert_type(i // left_i, "np.typing.NDArray[np.int64]"), pd.Index, np.integer) + check( + assert_type(f // left_i, "np.typing.NDArray[np.float64]"), 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] + check( + assert_type(d // left_i, "np.typing.NDArray[np.int64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) def test_floordiv_pd_index(left_i: pd.Index) -> None: diff --git a/tests/series/arithmetic/int/test_floordiv.py b/tests/series/arithmetic/int/test_floordiv.py index a5e810b44..d3ef5d86b 100644 --- a/tests/series/arithmetic/int/test_floordiv.py +++ b/tests/series/arithmetic/int/test_floordiv.py @@ -132,13 +132,17 @@ def test_floordiv_numpy_array(left: "pd.Series[int]") -> None: # `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) + check(assert_type(b // left, "np.typing.NDArray[np.int8]"), pd.Series, np.integer) + check(assert_type(i // left, "np.typing.NDArray[np.int64]"), pd.Series, np.integer) + check( + assert_type(f // left, "np.typing.NDArray[np.float64]"), 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]") + check( + assert_type(d // left, "np.typing.NDArray[np.int64]"), pd.Series, pd.Timedelta + ) 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) From eb648fb9cdb886d63f88a43a9a8e1ec8199e3f71 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 5 Nov 2025 13:35:08 +0100 Subject: [PATCH 11/23] mypy --- tests/indexes/arithmetic/test_floordiv.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/indexes/arithmetic/test_floordiv.py b/tests/indexes/arithmetic/test_floordiv.py index da78dd79c..1809b0920 100644 --- a/tests/indexes/arithmetic/test_floordiv.py +++ b/tests/indexes/arithmetic/test_floordiv.py @@ -92,16 +92,26 @@ def test_floordiv_numpy_array(left_i: pd.Index) -> None: # `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(assert_type(b // left_i, "np.typing.NDArray[np.int8]"), pd.Index, np.integer) - check(assert_type(i // left_i, "np.typing.NDArray[np.int64]"), pd.Index, np.integer) check( - assert_type(f // left_i, "np.typing.NDArray[np.float64]"), pd.Index, np.floating + assert_type(b // left_i, Any), # pyright: ignore[reportAssertTypeFailure] + pd.Index, + np.integer, + ) + check( + assert_type(i // left_i, Any), # pyright: ignore[reportAssertTypeFailure] + pd.Index, + np.integer, + ) + check( + assert_type(f // left_i, Any), # pyright: ignore[reportAssertTypeFailure] + pd.Index, + np.floating, ) if TYPE_CHECKING_INVALID_USAGE: assert_type(c // left_i, Any) assert_type(s // left_i, Any) check( - assert_type(d // left_i, "np.typing.NDArray[np.int64]"), + assert_type(d // left_i, Any), # pyright: ignore[reportAssertTypeFailure] pd.TimedeltaIndex, pd.Timedelta, ) From c70a3ce8e11ab44e5f9c71e193be7badd7371c9a Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 5 Nov 2025 14:42:34 +0100 Subject: [PATCH 12/23] series --- pandas-stubs/core/series.pyi | 155 +++++++++++------- tests/series/arithmetic/test_floordiv.py | 38 ++++- tests/series/arithmetic/test_truediv.py | 138 +++++++++++++++- .../arithmetic/timedelta/test_truediv.py | 20 +-- 4 files changed, 268 insertions(+), 83 deletions(-) diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 7955ba33a..5062d66ea 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -302,6 +302,30 @@ _DataLike: TypeAlias = ArrayLike | dict[str, np.ndarray] | SequenceNotStr[S1] _DataLikeS1: TypeAlias = ( ArrayLike | dict[_str, np.ndarray] | Sequence[S1] | IndexOpsMixin[S1] ) +_OtherFloorDivNumPyGeneric: TypeAlias = np.bool | np.integer | np.floating +_OtherFloorDiv: TypeAlias = ( + float + | _OtherFloorDivNumPyGeneric + | Sequence[float | _OtherFloorDivNumPyGeneric] + | np_ndarray[tuple[int, ...], _OtherFloorDivNumPyGeneric] + | Index[bool] + | Index[int] + | Index[float] + | Series[bool] + | Series[int] + | Series[float] +) +_OtherTrueDivNumPyGeneric: TypeAlias = _OtherFloorDivNumPyGeneric | np.complex128 +_OtherTrueDiv: TypeAlias = ( + _OtherFloorDiv + | complex + | _OtherTrueDivNumPyGeneric + | Sequence[complex | _OtherTrueDivNumPyGeneric] + | np_ndarray_complex + | Index[complex] + | Series[complex] +) +_OtherRTrueDiv: TypeAlias = _OtherTrueDiv class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): # Define __index__ because mypy thinks Series follows protocol `SupportsIndex` https://github.com/pandas-dev/pandas-stubs/pull/1332#discussion_r2285648790 @@ -2150,33 +2174,22 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): 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__( # 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: ... + self: Series[Never], other: np_ndarray_td | TimedeltaIndex + ) -> Never: ... @overload def __floordiv__( self: Series[int] | Series[float], other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, ) -> Never: ... @overload + def __floordiv__(self: Series[Never], other: _OtherFloorDiv) -> Series: ... + @overload + def __floordiv__( + self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], + other: Index[Never] | Series[Never], + ) -> Series: ... + @overload def __floordiv__( self: Series[bool] | Series[complex], other: np_ndarray ) -> Never: ... @@ -2237,19 +2250,15 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def floordiv( 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] - ), + other: np_ndarray_td | TimedeltaIndex, + level: Level | None = None, + fill_value: float | None = None, + axis: AxisIndex = 0, + ) -> Never: ... + @overload + def floordiv( + self: Series[Never], + other: _OtherFloorDiv, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, @@ -2356,20 +2365,21 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ), ) -> Series: ... @overload - def __rfloordiv__( - self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], - other: Index[Never] | Series[Never], - ) -> Series: ... + def __rfloordiv__(self, other: np_ndarray_complex | np_ndarray_dt) -> Never: ... @overload def __rfloordiv__( - self: Series[int] | Series[float], - other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + self: Series[int] | Series[float], other: np_ndarray_td ) -> Never: ... @overload def __rfloordiv__( self: Series[bool] | Series[complex], other: np_ndarray ) -> Never: ... @overload + def __rfloordiv__( + self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], + other: Index[Never] | Series[Never], + ) -> Series: ... + @overload def __rfloordiv__( self: Supports_ProtoRFloorDiv[_T_contra, S2], other: _T_contra | Sequence[_T_contra], @@ -3628,17 +3638,23 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): axis: int = 0, ) -> Series[BaseOffset]: ... @overload + def __truediv__(self, other: np_ndarray_dt) -> Never: ... + @overload def __truediv__( # type: ignore[overload-overlap] - self: Series[Never], other: complex | NumListLike | Index | Series + self: Series[Never], other: _OtherTrueDiv ) -> Series: ... @overload - def __truediv__(self, other: Index[Never] | Series[Never]) -> Series: ... + def __truediv__( + self: Series[Never], other: np_ndarray_td | TimedeltaIndex + ) -> Never: ... @overload - def __truediv__(self: Series[bool], other: np_ndarray_bool) -> Never: ... + def __truediv__(self: Series[T_COMPLEX], other: np_ndarray_td) -> Never: ... @overload - def __truediv__(self, other: np_ndarray_dt) -> Never: ... + def __truediv__(self: Series[bool], other: np_ndarray_bool) -> Never: ... @overload - def __truediv__(self: Series[T_COMPLEX], other: np_ndarray_td) -> Never: ... + def __truediv__( + self: Series[T_COMPLEX], other: Index[Never] | Series[Never] + ) -> Series: ... @overload def __truediv__( self: Series[Timedelta], @@ -3738,18 +3754,26 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], ) -> Series[float]: ... @overload - def __truediv__(self, other: Path) -> Series: ... + def __truediv__(self: Series[_str], other: Path) -> Series: ... @overload def truediv( self: Series[Never], - other: complex | ListLike, + other: _OtherTrueDiv, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, ) -> Series: ... @overload def truediv( - self, + self: Series[Never], + other: np_ndarray_td | TimedeltaIndex, + level: Level | None = None, + fill_value: float | None = None, + axis: AxisIndex = 0, + ) -> Never: ... + @overload + def truediv( + self: Series[bool] | Series[int] | Series[float] | Series[complex], other: Index[Never] | Series[Never], level: Level | None = None, fill_value: float | None = None, @@ -3880,7 +3904,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[float]: ... @overload def truediv( - self, + self: Series[_str], other: Path, level: Level | None = None, fill_value: float | None = None, @@ -3888,21 +3912,20 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series: ... div = truediv @overload - def __rtruediv__( # type: ignore[overload-overlap] - self: Series[Never], other: complex | NumListLike | Index | Series - ) -> Series: ... - @overload - def __rtruediv__(self, other: Index[Never] | Series[Never]) -> Series: ... - @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, + self: Series[Never], + other: timedelta | Sequence[timedelta] | np_ndarray_td | TimedeltaIndex, ) -> Never: ... @overload + def __rtruediv__(self: Series[Never], other: _OtherRTrueDiv) -> Series: ... + @overload + def __rtruediv__( + self: Series[bool] | Series[int] | Series[float] | Series[complex], + other: Index[Never] | Series[Never], + ) -> Series: ... + @overload def __rtruediv__( self: Supports_ProtoRTrueDiv[_T_contra, S2], other: _T_contra | Sequence[_T_contra], @@ -3990,18 +4013,26 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ), ) -> Series[Timedelta]: ... @overload - def __rtruediv__(self, other: Path) -> Series: ... + def __rtruediv__(self: Series[_str], other: Path) -> Series: ... @overload def rtruediv( self: Series[Never], - other: complex | ListLike, + other: _OtherRTrueDiv, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, ) -> Series: ... @overload def rtruediv( - self, + self: Series[Never], + other: timedelta | Sequence[timedelta] | np_ndarray_td | TimedeltaIndex, + level: Level | None = None, + fill_value: float | None = None, + axis: AxisIndex = 0, + ) -> Never: ... + @overload + def rtruediv( + self: Series[bool] | Series[int] | Series[float] | Series[complex], other: Index[Never] | Series[Never], level: Level | None = None, fill_value: float | None = None, @@ -4127,7 +4158,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[Timedelta]: ... @overload def rtruediv( - self, + self: Series[_str], other: Path, level: Level | None = None, fill_value: float | None = None, diff --git a/tests/series/arithmetic/test_floordiv.py b/tests/series/arithmetic/test_floordiv.py index 6f563bc14..276f0e518 100644 --- a/tests/series/arithmetic/test_floordiv.py +++ b/tests/series/arithmetic/test_floordiv.py @@ -124,9 +124,14 @@ def test_floordiv_numpy_array(left_i: pd.Series) -> None: 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: + + def _03() -> None: # pyright: ignore[reportUnusedFunction] assert_type(left_i // c, Never) + + def _04() -> None: # pyright: ignore[reportUnusedFunction] assert_type(left_i // s, Never) + + def _05() -> None: # pyright: ignore[reportUnusedFunction] assert_type(left_i // d, Never) # `numpy` typing gives the corresponding `ndarray`s in the static type @@ -143,17 +148,26 @@ def test_floordiv_numpy_array(left_i: pd.Series) -> None: 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: + + def _23() -> None: # pyright: ignore[reportUnusedFunction] left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _24() -> None: # pyright: ignore[reportUnusedFunction] 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 + + def _25() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.floordiv(d), Never) 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: + + def _33() -> None: # pyright: ignore[reportUnusedFunction] left_i.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _34() -> None: # pyright: ignore[reportUnusedFunction] 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, @@ -176,7 +190,9 @@ def test_floordiv_pd_index(left_i: pd.Series) -> None: 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 + + def _05() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i // d, Never) check(assert_type(b // left_i, pd.Series), pd.Series, np.integer) check(assert_type(i // left_i, pd.Series), pd.Series, np.integer) @@ -192,7 +208,9 @@ def test_floordiv_pd_index(left_i: pd.Series) -> None: 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 + + def _25() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.floordiv(d), Never) 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) @@ -222,7 +240,7 @@ def test_floordiv_pd_series(left_i: pd.Series) -> None: 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 + # 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) @@ -235,8 +253,11 @@ def test_floordiv_pd_series(left_i: pd.Series) -> None: 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: + + def _23() -> None: # pyright: ignore[reportUnusedFunction] left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + if TYPE_CHECKING_INVALID_USAGE: 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 @@ -246,6 +267,7 @@ def test_floordiv_pd_series(left_i: pd.Series) -> None: 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, diff --git a/tests/series/arithmetic/test_truediv.py b/tests/series/arithmetic/test_truediv.py index d0802d1c2..a21da7e7d 100644 --- a/tests/series/arithmetic/test_truediv.py +++ b/tests/series/arithmetic/test_truediv.py @@ -1,10 +1,17 @@ +from datetime import ( + datetime, + timedelta, +) from pathlib import Path from typing import Any import numpy as np 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, @@ -22,71 +29,118 @@ def left_i() -> pd.Series: def test_truediv_py_scalar(left_i: pd.Series) -> None: """Test pd.Series[Any] (int) / Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 11, 5), timedelta(seconds=1) check(assert_type(left_i / b, pd.Series), pd.Series) check(assert_type(left_i / i, pd.Series), pd.Series) check(assert_type(left_i / f, pd.Series), pd.Series) check(assert_type(left_i / c, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + _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) check(assert_type(i / left_i, pd.Series), pd.Series) check(assert_type(f / left_i, pd.Series), pd.Series) check(assert_type(c / left_i, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + assert_type(d / left_i, Never) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) check(assert_type(left_i.truediv(i), pd.Series), pd.Series) check(assert_type(left_i.truediv(f), pd.Series), pd.Series) check(assert_type(left_i.truediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left_i.div(b), pd.Series), pd.Series) check(assert_type(left_i.div(i), pd.Series), pd.Series) check(assert_type(left_i.div(f), pd.Series), pd.Series) check(assert_type(left_i.div(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _45() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.rtruediv(d), Never) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _55() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.rdiv(d), Never) def test_truediv_py_sequence(left_i: pd.Series) -> None: """Test pd.Series[Any] (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, 11, 1 + 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) check(assert_type(left_i / i, pd.Series), pd.Series) check(assert_type(left_i / f, pd.Series), pd.Series) check(assert_type(left_i / c, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + _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) check(assert_type(i / left_i, pd.Series), pd.Series) check(assert_type(f / left_i, pd.Series), pd.Series) check(assert_type(c / left_i, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + _14 = s / left_i # type: ignore[var-annotated] # pyright: ignore[reportOperatorIssue] + assert_type(d / left_i, Never) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) check(assert_type(left_i.truediv(i), pd.Series), pd.Series) check(assert_type(left_i.truediv(f), pd.Series), pd.Series) check(assert_type(left_i.truediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.truediv(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left_i.div(b), pd.Series), pd.Series) check(assert_type(left_i.div(i), pd.Series), pd.Series) check(assert_type(left_i.div(f), pd.Series), pd.Series) check(assert_type(left_i.div(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.div(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _45() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.rtruediv(d), Never) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _55() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.rdiv(d), Never) def test_truediv_numpy_array(left_i: pd.Series) -> None: @@ -95,11 +149,18 @@ def test_truediv_numpy_array(left_i: pd.Series) -> 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.complex64) + 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) check(assert_type(left_i / i, pd.Series), pd.Series) check(assert_type(left_i / f, pd.Series), pd.Series) check(assert_type(left_i / c, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + 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 `__rtruediv__` cannot override. At runtime, they return @@ -121,26 +182,49 @@ def test_truediv_numpy_array(left_i: pd.Series) -> None: assert_type(c / left_i, Any), # pyright: ignore[reportAssertTypeFailure] pd.Series, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s / left_i, Any) + assert_type(d / left_i, Any) # pyright: ignore[reportAssertTypeFailure] check(assert_type(left_i.truediv(b), pd.Series), pd.Series) check(assert_type(left_i.truediv(i), pd.Series), pd.Series) check(assert_type(left_i.truediv(f), pd.Series), pd.Series) check(assert_type(left_i.truediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _25() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.truediv(d), Never) check(assert_type(left_i.div(b), pd.Series), pd.Series) check(assert_type(left_i.div(i), pd.Series), pd.Series) check(assert_type(left_i.div(f), pd.Series), pd.Series) check(assert_type(left_i.div(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _35() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.div(d), Never) check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _45() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.rtruediv(d), Never) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _55() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.rdiv(d), Never) def test_truediv_pd_index(left_i: pd.Series) -> None: @@ -150,42 +234,70 @@ def test_truediv_pd_index(left_i: pd.Series) -> 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, 11, 1 + d) for d in range(3)]) + d = pd.Index([timedelta(seconds=s) for s in range(3)]) check(assert_type(left_i / a, pd.Series), pd.Series) check(assert_type(left_i / b, pd.Series), pd.Series) check(assert_type(left_i / i, pd.Series), pd.Series) check(assert_type(left_i / f, pd.Series), pd.Series) check(assert_type(left_i / c, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left_i / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + assert_type(left_i / d, Never) check(assert_type(a / left_i, pd.Series), pd.Series) check(assert_type(b / left_i, pd.Series), pd.Series) check(assert_type(i / left_i, pd.Series), pd.Series) check(assert_type(f / left_i, pd.Series), pd.Series) check(assert_type(c / left_i, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + assert_type(d / left_i, Never) check(assert_type(left_i.truediv(a), pd.Series), pd.Series) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) check(assert_type(left_i.truediv(i), pd.Series), pd.Series) check(assert_type(left_i.truediv(f), pd.Series), pd.Series) check(assert_type(left_i.truediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _26() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.truediv(d), Never) check(assert_type(left_i.div(a), pd.Series), pd.Series) check(assert_type(left_i.div(b), pd.Series), pd.Series) check(assert_type(left_i.div(i), pd.Series), pd.Series) check(assert_type(left_i.div(f), pd.Series), pd.Series) check(assert_type(left_i.div(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _36() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.div(d), Never) check(assert_type(left_i.rtruediv(a), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _46() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.rtruediv(d), Never) check(assert_type(left_i.rdiv(a), pd.Series), pd.Series) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + def _56() -> None: # pyright: ignore[reportUnusedFunction] + assert_type(left_i.rdiv(d), Never) def test_truediv_pd_series(left_i: pd.Series) -> None: @@ -195,42 +307,62 @@ def test_truediv_pd_series(left_i: pd.Series) -> 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, 11, 1 + d) for d in range(3)]) + # d = pd.Series([timedelta(seconds=s) for s in range(3)]) check(assert_type(left_i / a, pd.Series), pd.Series) check(assert_type(left_i / b, pd.Series), pd.Series) check(assert_type(left_i / i, pd.Series), pd.Series) check(assert_type(left_i / f, pd.Series), pd.Series) check(assert_type(left_i / c, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left_i / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # left_i / d # This invalid one cannot be detected by static type checking check(assert_type(a / left_i, pd.Series), pd.Series) check(assert_type(b / left_i, pd.Series), pd.Series) check(assert_type(i / left_i, pd.Series), pd.Series) check(assert_type(f / left_i, pd.Series), pd.Series) check(assert_type(c / left_i, pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # d / left_i # This invalid one cannot be detected by static type checking check(assert_type(left_i.truediv(a), pd.Series), pd.Series) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) check(assert_type(left_i.truediv(i), pd.Series), pd.Series) check(assert_type(left_i.truediv(f), pd.Series), pd.Series) check(assert_type(left_i.truediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + # left_i.truediv(d) # This invalid one cannot be detected by static type checking check(assert_type(left_i.div(a), pd.Series), pd.Series) check(assert_type(left_i.div(b), pd.Series), pd.Series) check(assert_type(left_i.div(i), pd.Series), pd.Series) check(assert_type(left_i.div(f), pd.Series), pd.Series) check(assert_type(left_i.div(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + # left_i.div(d) # This invalid one cannot be detected by static type checking check(assert_type(left_i.rtruediv(a), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(b), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(i), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(f), pd.Series), pd.Series) check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + # left_i.rtruediv(d) # This invalid one cannot be detected by static type checking check(assert_type(left_i.rdiv(a), pd.Series), pd.Series) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) check(assert_type(left_i.rdiv(f), pd.Series), pd.Series) check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) + if TYPE_CHECKING_INVALID_USAGE: + left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + # left_i.rdiv(d) # This invalid one cannot be detected by static type checking def test_truediv_paths(tmp_path: Path) -> None: @@ -271,8 +403,8 @@ def test_truediv_str_py_str(left_i: pd.Series) -> None: s = "abc" if TYPE_CHECKING_INVALID_USAGE: - _0 = left_i / s # type: ignore[operator] # pyright:ignore[reportOperatorIssue] - _1 = s / left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + _00 = left_i / s # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + _01 = s / left_i # type: ignore[var-annotated] # pyright:ignore[reportOperatorIssue] left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] diff --git a/tests/series/arithmetic/timedelta/test_truediv.py b/tests/series/arithmetic/timedelta/test_truediv.py index 724a17c8e..6167ad679 100644 --- a/tests/series/arithmetic/timedelta/test_truediv.py +++ b/tests/series/arithmetic/timedelta/test_truediv.py @@ -293,19 +293,19 @@ def test_truediv_pd_index(left: "pd.Series[pd.Timedelta]") -> None: check(assert_type(left.div(d), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - left.rtruediv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rtruediv(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rtruediv(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rtruediv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rtruediv(b) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rtruediv(i) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rtruediv(f) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rtruediv(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rtruediv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rtruediv(d), "pd.Series[float]"), pd.Series, np.floating) if TYPE_CHECKING_INVALID_USAGE: - left.rdiv(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rdiv(i) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rdiv(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rdiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rdiv(b) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rdiv(i) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rdiv(f) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rdiv(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rdiv(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rdiv(d), "pd.Series[float]"), pd.Series, np.floating) From e2482cb8a1eb82db9359d11f95116588f3b87c87 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 5 Nov 2025 18:21:47 +0100 Subject: [PATCH 13/23] mypy --- tests/series/arithmetic/test_truediv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/series/arithmetic/test_truediv.py b/tests/series/arithmetic/test_truediv.py index a21da7e7d..f87b9549e 100644 --- a/tests/series/arithmetic/test_truediv.py +++ b/tests/series/arithmetic/test_truediv.py @@ -103,7 +103,7 @@ def test_truediv_py_sequence(left_i: pd.Series) -> None: check(assert_type(f / left_i, pd.Series), pd.Series) check(assert_type(c / left_i, pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: - _14 = s / left_i # type: ignore[var-annotated] # pyright: ignore[reportOperatorIssue] + _14 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] assert_type(d / left_i, Never) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) @@ -404,7 +404,7 @@ def test_truediv_str_py_str(left_i: pd.Series) -> None: if TYPE_CHECKING_INVALID_USAGE: _00 = left_i / s # type: ignore[operator] # pyright:ignore[reportOperatorIssue] - _01 = s / left_i # type: ignore[var-annotated] # pyright:ignore[reportOperatorIssue] + _01 = s / left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] From ea5d6bf5a003c17af319b7e97fdaacf08332c69a Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 5 Nov 2025 23:17:46 +0100 Subject: [PATCH 14/23] series --- pandas-stubs/core/indexes/base.pyi | 33 ++++- pandas-stubs/core/series.pyi | 140 ++++++------------ tests/series/arithmetic/float/test_truediv.py | 2 +- tests/series/arithmetic/int/test_truediv.py | 2 +- tests/series/arithmetic/test_truediv.py | 54 +++---- 5 files changed, 101 insertions(+), 130 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 534ac4825..88cdcfdd9 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -16,6 +16,7 @@ from typing import ( ClassVar, Generic, Literal, + TypeAlias, final, overload, type_check_only, @@ -29,7 +30,9 @@ from _typeshed import ( _T_contra, ) import numpy as np +from pandas.core.arrays.base import ExtensionArray from pandas.core.arrays.boolean import BooleanArray +from pandas.core.arrays.timedeltas import TimedeltaArray from pandas.core.base import ( ElementOpsMixin, IndexOpsMixin, @@ -111,6 +114,32 @@ from pandas._typing import ( from pandas.core.dtypes.dtypes import PeriodDtype +NumpyRealScalar: TypeAlias = np.bool | np.integer | np.floating +IndexReal: TypeAlias = Index[bool] | Index[int] | Index[float] # ty: ignore[unresolved-reference] +ScalarArrayIndexReal: TypeAlias = ( + float + | Sequence[float | NumpyRealScalar] + | NumpyRealScalar + | np_ndarray[tuple[int, ...], NumpyRealScalar] + | ExtensionArray # TODO: NumpyExtensionArray after pandas-dev/pandas-stubs#1469 + | IndexReal +) +NumpyComplexScalar: TypeAlias = NumpyRealScalar | np.complexfloating +IndexComplex: TypeAlias = IndexReal | Index[complex] # ty: ignore[unresolved-reference] +ScalarArrayIndexComplex: TypeAlias = ( + complex + | Sequence[complex | NumpyComplexScalar] + | NumpyComplexScalar + | np_ndarray[tuple[int, ...], NumpyComplexScalar] + | ExtensionArray # TODO: NumpyExtensionArray after pandas-dev/pandas-stubs#1469 + | IndexComplex +) + +ArrayIndexTimedeltaNoSeq: TypeAlias = np_ndarray_td | TimedeltaArray | TimedeltaIndex +ScalarArrayIndexTimedelta: TypeAlias = ( + timedelta | Sequence[timedelta | np.timedelta64] | ArrayIndexTimedeltaNoSeq +) + class InvalidIndexError(Exception): ... class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @@ -1124,7 +1153,9 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ), ) -> Index: ... @overload - def __rfloordiv__(self: Index[bool] | Index[int] | Index[float], other: Index[Never]) -> Index: ... # type: ignore[overload-overlap] + def __rfloordiv__( # type: ignore[overload-overlap] + self: Index[bool] | Index[int] | Index[float], other: Index[Never] + ) -> Index: ... @overload def __rfloordiv__( self: Index[int] | Index[float], diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 5062d66ea..f3aa028a4 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -83,6 +83,12 @@ from pandas.core.groupby.generic import SeriesGroupBy from pandas.core.groupby.groupby import BaseGroupBy from pandas.core.indexers import BaseIndexer from pandas.core.indexes.accessors import DtDescriptor +from pandas.core.indexes.base import ( + ArrayIndexTimedeltaNoSeq, + ScalarArrayIndexComplex, + ScalarArrayIndexReal, + ScalarArrayIndexTimedelta, +) from pandas.core.indexes.category import CategoricalIndex from pandas.core.indexes.datetimes import DatetimeIndex from pandas.core.indexes.interval import IntervalIndex @@ -302,30 +308,15 @@ _DataLike: TypeAlias = ArrayLike | dict[str, np.ndarray] | SequenceNotStr[S1] _DataLikeS1: TypeAlias = ( ArrayLike | dict[_str, np.ndarray] | Sequence[S1] | IndexOpsMixin[S1] ) -_OtherFloorDivNumPyGeneric: TypeAlias = np.bool | np.integer | np.floating -_OtherFloorDiv: TypeAlias = ( - float - | _OtherFloorDivNumPyGeneric - | Sequence[float | _OtherFloorDivNumPyGeneric] - | np_ndarray[tuple[int, ...], _OtherFloorDivNumPyGeneric] - | Index[bool] - | Index[int] - | Index[float] - | Series[bool] - | Series[int] - | Series[float] -) -_OtherTrueDivNumPyGeneric: TypeAlias = _OtherFloorDivNumPyGeneric | np.complex128 -_OtherTrueDiv: TypeAlias = ( - _OtherFloorDiv - | complex - | _OtherTrueDivNumPyGeneric - | Sequence[complex | _OtherTrueDivNumPyGeneric] - | np_ndarray_complex - | Index[complex] - | Series[complex] + +SeriesReal: TypeAlias = Series[bool] | Series[int] | Series[float] # ty: ignore[unresolved-reference] +ScalarArrayIndexSeriesReal: TypeAlias = ScalarArrayIndexReal | SeriesReal +SeriesComplex: TypeAlias = SeriesReal | Series[complex] # ty: ignore[unresolved-reference] +ScalarArrayIndexSeriesComplex: TypeAlias = ScalarArrayIndexComplex | SeriesComplex +ArrayIndexSeriesTimedeltaNoSeq: TypeAlias = ArrayIndexTimedeltaNoSeq | Series[Timedelta] # ty: ignore[unresolved-reference] +ScalarArrayIndexSeriesTimedelta: TypeAlias = ( + ScalarArrayIndexTimedelta | Series[Timedelta] # ty: ignore[unresolved-reference] ) -_OtherRTrueDiv: TypeAlias = _OtherTrueDiv class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): # Define __index__ because mypy thinks Series follows protocol `SupportsIndex` https://github.com/pandas-dev/pandas-stubs/pull/1332#discussion_r2285648790 @@ -2183,7 +2174,9 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, ) -> Never: ... @overload - def __floordiv__(self: Series[Never], other: _OtherFloorDiv) -> Series: ... + def __floordiv__( + self: Series[Never], other: ScalarArrayIndexSeriesReal + ) -> Series: ... @overload def __floordiv__( self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], @@ -2244,8 +2237,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[Timedelta]: ... @overload def __floordiv__( - self: Series[Timedelta], - other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + self: Series[Timedelta], other: ArrayIndexSeriesTimedeltaNoSeq ) -> Series[int]: ... @overload def floordiv( @@ -2258,7 +2250,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def floordiv( self: Series[Never], - other: _OtherFloorDiv, + other: ScalarArrayIndexSeriesReal, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, @@ -2342,27 +2334,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def floordiv( self: Series[Timedelta], - other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + other: ArrayIndexSeriesTimedeltaNoSeq, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, ) -> Series[int]: ... @overload - 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] - ), + def __rfloordiv__( + self: Series[Never], other: ScalarArrayIndexSeriesReal ) -> Series: ... @overload def __rfloordiv__(self, other: np_ndarray_complex | np_ndarray_dt) -> Never: ... @@ -2422,29 +2401,16 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def __rfloordiv__( self: Series[int] | Series[float], - other: timedelta | np_ndarray_td | TimedeltaIndex | Series[Timedelta], + other: timedelta | np.timedelta64 | ArrayIndexSeriesTimedeltaNoSeq, ) -> Series[Timedelta]: ... @overload def __rfloordiv__( - self: Series[Timedelta], - other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + self: Series[Timedelta], other: ArrayIndexSeriesTimedeltaNoSeq ) -> Series[int]: ... @overload def rfloordiv( 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] - ), + other: ScalarArrayIndexSeriesReal, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, @@ -2524,7 +2490,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rfloordiv( self: Series[Timedelta], - other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + other: ArrayIndexSeriesTimedeltaNoSeq, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex = ..., @@ -3641,19 +3607,17 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): def __truediv__(self, other: np_ndarray_dt) -> Never: ... @overload def __truediv__( # type: ignore[overload-overlap] - self: Series[Never], other: _OtherTrueDiv + self: Series[Never], other: ScalarArrayIndexSeriesComplex ) -> Series: ... @overload - def __truediv__( - self: Series[Never], other: np_ndarray_td | TimedeltaIndex - ) -> Never: ... + def __truediv__(self: Series[Never], other: ArrayIndexTimedeltaNoSeq) -> Never: ... @overload def __truediv__(self: Series[T_COMPLEX], other: np_ndarray_td) -> Never: ... @overload def __truediv__(self: Series[bool], other: np_ndarray_bool) -> Never: ... @overload def __truediv__( - self: Series[T_COMPLEX], other: Index[Never] | Series[Never] + self: SeriesComplex | Series[Timedelta], other: Index[Never] | Series[Never] ) -> Series: ... @overload def __truediv__( @@ -3723,7 +3687,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[T_COMPLEX]: ... @overload def __truediv__( - self: Series[T_COMPLEX], + self: SeriesComplex, other: ( Just[complex] | Sequence[Just[complex]] @@ -3750,15 +3714,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[Timedelta]: ... @overload def __truediv__( - self: Series[Timedelta], - other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + self: Series[Timedelta], other: ArrayIndexSeriesTimedeltaNoSeq ) -> Series[float]: ... @overload def __truediv__(self: Series[_str], other: Path) -> Series: ... @overload - def truediv( + def truediv( # type: ignore[overload-overlap] self: Series[Never], - other: _OtherTrueDiv, + other: ScalarArrayIndexSeriesComplex, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3766,14 +3729,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[Never], - other: np_ndarray_td | TimedeltaIndex, + other: ArrayIndexTimedeltaNoSeq, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, ) -> Never: ... @overload def truediv( - self: Series[bool] | Series[int] | Series[float] | Series[complex], + self: SeriesComplex | Series[Timedelta], other: Index[Never] | Series[Never], level: Level | None = None, fill_value: float | None = None, @@ -3863,7 +3826,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[T_COMPLEX]: ... @overload def truediv( - self: Series[T_COMPLEX], + self: SeriesComplex, other: ( Just[complex] | Sequence[Just[complex]] @@ -3897,7 +3860,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[Timedelta], - other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + other: ArrayIndexSeriesTimedeltaNoSeq, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3916,16 +3879,18 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def __rtruediv__( self: Series[Never], - other: timedelta | Sequence[timedelta] | np_ndarray_td | TimedeltaIndex, - ) -> Never: ... - @overload - def __rtruediv__(self: Series[Never], other: _OtherRTrueDiv) -> Series: ... + other: ScalarArrayIndexSeriesComplex | ScalarArrayIndexSeriesTimedelta, + ) -> Series: ... @overload def __rtruediv__( self: Series[bool] | Series[int] | Series[float] | Series[complex], other: Index[Never] | Series[Never], ) -> Series: ... @overload + def __rtruediv__( + self: Series[int] | Series[float], other: Sequence[timedelta | np.timedelta64] + ) -> Series: ... + @overload def __rtruediv__( self: Supports_ProtoRTrueDiv[_T_contra, S2], other: _T_contra | Sequence[_T_contra], @@ -3987,7 +3952,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[T_COMPLEX]: ... @overload def __rtruediv__( - self: Series[T_COMPLEX], + self: SeriesComplex, other: ( Just[complex] | Sequence[Just[complex]] @@ -3998,8 +3963,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[complex]: ... @overload def __rtruediv__( - self: Series[Timedelta], - other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + self: Series[Timedelta], other: ArrayIndexSeriesTimedeltaNoSeq ) -> Series[float]: ... @overload def __rtruediv__( @@ -4017,20 +3981,12 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[Never], - other: _OtherRTrueDiv, + other: ScalarArrayIndexSeriesComplex | ScalarArrayIndexSeriesTimedelta, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, ) -> Series: ... @overload - def rtruediv( - self: Series[Never], - other: timedelta | Sequence[timedelta] | np_ndarray_td | TimedeltaIndex, - level: Level | None = None, - fill_value: float | None = None, - axis: AxisIndex = 0, - ) -> Never: ... - @overload def rtruediv( self: Series[bool] | Series[int] | Series[float] | Series[complex], other: Index[Never] | Series[Never], @@ -4122,7 +4078,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[T_COMPLEX]: ... @overload def rtruediv( - self: Series[T_COMPLEX], + self: SeriesComplex, other: ( Just[complex] | Sequence[Just[complex]] @@ -4137,7 +4093,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[Timedelta], - other: np_ndarray_td | TimedeltaIndex | Series[Timedelta], + other: ArrayIndexSeriesTimedeltaNoSeq, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, diff --git a/tests/series/arithmetic/float/test_truediv.py b/tests/series/arithmetic/float/test_truediv.py index 9b330fce8..09ecf5955 100644 --- a/tests/series/arithmetic/float/test_truediv.py +++ b/tests/series/arithmetic/float/test_truediv.py @@ -114,7 +114,7 @@ def test_truediv_py_sequence(left: "pd.Series[float]") -> None: 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(d / left, pd.Series), pd.Series, timedelta) # dtype object 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) diff --git a/tests/series/arithmetic/int/test_truediv.py b/tests/series/arithmetic/int/test_truediv.py index 1cda6bdb9..19aeabf78 100644 --- a/tests/series/arithmetic/int/test_truediv.py +++ b/tests/series/arithmetic/int/test_truediv.py @@ -114,7 +114,7 @@ def test_truediv_py_sequence(left: "pd.Series[int]") -> None: 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(d / left, pd.Series), pd.Series, timedelta) # dtype object 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) diff --git a/tests/series/arithmetic/test_truediv.py b/tests/series/arithmetic/test_truediv.py index f87b9549e..cd08b9e39 100644 --- a/tests/series/arithmetic/test_truediv.py +++ b/tests/series/arithmetic/test_truediv.py @@ -45,7 +45,7 @@ def test_truediv_py_scalar(left_i: pd.Series) -> None: check(assert_type(c / left_i, pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: _14 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - assert_type(d / left_i, Never) + check(assert_type(d / left_i, pd.Series), pd.Series) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) check(assert_type(left_i.truediv(i), pd.Series), pd.Series) @@ -69,9 +69,7 @@ def test_truediv_py_scalar(left_i: pd.Series) -> None: check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _45() -> None: # pyright: ignore[reportUnusedFunction] - assert_type(left_i.rtruediv(d), Never) + check(assert_type(left_i.rtruediv(d), pd.Series), pd.Series) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) @@ -79,9 +77,7 @@ def _45() -> None: # pyright: ignore[reportUnusedFunction] check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _55() -> None: # pyright: ignore[reportUnusedFunction] - assert_type(left_i.rdiv(d), Never) + check(assert_type(left_i.rdiv(d), pd.Series), pd.Series) def test_truediv_py_sequence(left_i: pd.Series) -> None: @@ -104,7 +100,7 @@ def test_truediv_py_sequence(left_i: pd.Series) -> None: check(assert_type(c / left_i, pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: _14 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - assert_type(d / left_i, Never) + check(assert_type(d / left_i, pd.Series), pd.Series) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) check(assert_type(left_i.truediv(i), pd.Series), pd.Series) @@ -128,9 +124,7 @@ def test_truediv_py_sequence(left_i: pd.Series) -> None: check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _45() -> None: # pyright: ignore[reportUnusedFunction] - assert_type(left_i.rtruediv(d), Never) + check(assert_type(left_i.rtruediv(d), pd.Series), pd.Series) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) @@ -138,9 +132,7 @@ def _45() -> None: # pyright: ignore[reportUnusedFunction] check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _55() -> None: # pyright: ignore[reportUnusedFunction] - assert_type(left_i.rdiv(d), Never) + check(assert_type(left_i.rdiv(d), pd.Series), pd.Series) def test_truediv_numpy_array(left_i: pd.Series) -> None: @@ -212,9 +204,7 @@ def _35() -> None: # pyright: ignore[reportUnusedFunction] check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _45() -> None: # pyright: ignore[reportUnusedFunction] - assert_type(left_i.rtruediv(d), Never) + check(assert_type(left_i.rtruediv(d), pd.Series), pd.Series) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) check(assert_type(left_i.rdiv(i), pd.Series), pd.Series) @@ -222,9 +212,7 @@ def _45() -> None: # pyright: ignore[reportUnusedFunction] check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _55() -> None: # pyright: ignore[reportUnusedFunction] - assert_type(left_i.rdiv(d), Never) + check(assert_type(left_i.rdiv(d), pd.Series), pd.Series) def test_truediv_pd_index(left_i: pd.Series) -> None: @@ -253,7 +241,7 @@ def test_truediv_pd_index(left_i: pd.Series) -> None: check(assert_type(c / left_i, pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: _15 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - assert_type(d / left_i, Never) + check(assert_type(d / left_i, pd.Series), pd.Series) check(assert_type(left_i.truediv(a), pd.Series), pd.Series) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) @@ -284,9 +272,7 @@ def _36() -> None: # pyright: ignore[reportUnusedFunction] check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _46() -> None: # pyright: ignore[reportUnusedFunction] - assert_type(left_i.rtruediv(d), Never) + check(assert_type(left_i.rtruediv(d), pd.Series), pd.Series) check(assert_type(left_i.rdiv(a), pd.Series), pd.Series) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) @@ -295,9 +281,7 @@ def _46() -> None: # pyright: ignore[reportUnusedFunction] check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _56() -> None: # pyright: ignore[reportUnusedFunction] - assert_type(left_i.rdiv(d), Never) + check(assert_type(left_i.rdiv(d), pd.Series), pd.Series) def test_truediv_pd_series(left_i: pd.Series) -> None: @@ -308,7 +292,7 @@ def test_truediv_pd_series(left_i: pd.Series) -> None: f = pd.Series([1.0, 2.0, 3.0]) c = pd.Series([1.1j, 2.2j, 4.1j]) s = pd.Series([datetime(2025, 11, 1 + d) for d in range(3)]) - # d = pd.Series([timedelta(seconds=s) for s in range(3)]) + d = pd.Series([timedelta(seconds=s) for s in range(3)]) check(assert_type(left_i / a, pd.Series), pd.Series) check(assert_type(left_i / b, pd.Series), pd.Series) @@ -316,8 +300,8 @@ def test_truediv_pd_series(left_i: pd.Series) -> None: check(assert_type(left_i / f, pd.Series), pd.Series) check(assert_type(left_i / c, pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: - _05 = left_i / s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - # left_i / d # This invalid one cannot be detected by static type checking + _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(a / left_i, pd.Series), pd.Series) check(assert_type(b / left_i, pd.Series), pd.Series) @@ -325,8 +309,8 @@ def test_truediv_pd_series(left_i: pd.Series) -> None: check(assert_type(f / left_i, pd.Series), pd.Series) check(assert_type(c / left_i, pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: - _15 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - # d / left_i # This invalid one cannot be detected by static type checking + _14 = s / left_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d / left_i, pd.Series), pd.Series) check(assert_type(left_i.truediv(a), pd.Series), pd.Series) check(assert_type(left_i.truediv(b), pd.Series), pd.Series) @@ -353,7 +337,7 @@ def test_truediv_pd_series(left_i: pd.Series) -> None: check(assert_type(left_i.rtruediv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rtruediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - # left_i.rtruediv(d) # This invalid one cannot be detected by static type checking + check(assert_type(left_i.rtruediv(d), pd.Series), pd.Series) check(assert_type(left_i.rdiv(a), pd.Series), pd.Series) check(assert_type(left_i.rdiv(b), pd.Series), pd.Series) @@ -362,7 +346,7 @@ def test_truediv_pd_series(left_i: pd.Series) -> None: check(assert_type(left_i.rdiv(c), pd.Series), pd.Series) if TYPE_CHECKING_INVALID_USAGE: left_i.rdiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - # left_i.rdiv(d) # This invalid one cannot be detected by static type checking + check(assert_type(left_i.rdiv(d), pd.Series), pd.Series) def test_truediv_paths(tmp_path: Path) -> None: @@ -404,7 +388,7 @@ def test_truediv_str_py_str(left_i: pd.Series) -> None: if TYPE_CHECKING_INVALID_USAGE: _00 = left_i / s # type: ignore[operator] # pyright:ignore[reportOperatorIssue] - _01 = s / left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + _01: pd.Series = s / left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] From 5d1c228491f4bee1e890cf555f3270a580c657bf Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 5 Nov 2025 23:32:52 +0100 Subject: [PATCH 15/23] series --- pandas-stubs/core/indexes/base.pyi | 32 +++----------- pandas-stubs/core/series.pyi | 44 ++++++++----------- .../series/arithmetic/float/test_floordiv.py | 2 +- tests/series/arithmetic/int/test_floordiv.py | 2 +- tests/series/arithmetic/test_floordiv.py | 2 +- 5 files changed, 26 insertions(+), 56 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 88cdcfdd9..9cdf21f67 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -115,7 +115,9 @@ from pandas._typing import ( from pandas.core.dtypes.dtypes import PeriodDtype NumpyRealScalar: TypeAlias = np.bool | np.integer | np.floating -IndexReal: TypeAlias = Index[bool] | Index[int] | Index[float] # ty: ignore[unresolved-reference] +IndexReal: TypeAlias = ( + Index[bool] | Index[int] | Index[float] # ty: ignore[unresolved-reference] +) ScalarArrayIndexReal: TypeAlias = ( float | Sequence[float | NumpyRealScalar] @@ -1086,19 +1088,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @overload def __rtruediv__(self, other: Path) -> Index: ... @overload - def __floordiv__( - self: Index[Never], - other: ( - float - | Sequence[float] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[bool] - | Index[int] - | Index[float] - ), - ) -> Index: ... + def __floordiv__(self: Index[Never], other: ScalarArrayIndexReal) -> Index: ... @overload def __floordiv__( self: Index[bool] | Index[int] | Index[float], other: Index[Never] @@ -1139,19 +1129,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): other: float | Sequence[float] | np_ndarray_float | Index[float], ) -> Index[float]: ... @overload - def __rfloordiv__( - self: Index[Never], - other: ( - float - | Sequence[float] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[bool] - | Index[int] - | Index[float] - ), - ) -> Index: ... + def __rfloordiv__(self: Index[Never], other: ScalarArrayIndexReal) -> Index: ... @overload def __rfloordiv__( # type: ignore[overload-overlap] self: Index[bool] | Index[int] | Index[float], other: Index[Never] diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index f3aa028a4..4f28151ed 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -309,11 +309,17 @@ _DataLikeS1: TypeAlias = ( ArrayLike | dict[_str, np.ndarray] | Sequence[S1] | IndexOpsMixin[S1] ) -SeriesReal: TypeAlias = Series[bool] | Series[int] | Series[float] # ty: ignore[unresolved-reference] +SeriesReal: TypeAlias = ( + Series[bool] | Series[int] | Series[float] # ty: ignore[unresolved-reference] +) ScalarArrayIndexSeriesReal: TypeAlias = ScalarArrayIndexReal | SeriesReal -SeriesComplex: TypeAlias = SeriesReal | Series[complex] # ty: ignore[unresolved-reference] +SeriesComplex: TypeAlias = ( + SeriesReal | Series[complex] # ty: ignore[unresolved-reference] +) ScalarArrayIndexSeriesComplex: TypeAlias = ScalarArrayIndexComplex | SeriesComplex -ArrayIndexSeriesTimedeltaNoSeq: TypeAlias = ArrayIndexTimedeltaNoSeq | Series[Timedelta] # ty: ignore[unresolved-reference] +ArrayIndexSeriesTimedeltaNoSeq: TypeAlias = ( + ArrayIndexTimedeltaNoSeq | Series[Timedelta] # ty: ignore[unresolved-reference] +) ScalarArrayIndexSeriesTimedelta: TypeAlias = ( ScalarArrayIndexTimedelta | Series[Timedelta] # ty: ignore[unresolved-reference] ) @@ -2404,6 +2410,11 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): other: timedelta | np.timedelta64 | ArrayIndexSeriesTimedeltaNoSeq, ) -> Series[Timedelta]: ... @overload + def __rfloordiv__( + self: Series[int] | Series[float], + other: Sequence[timedelta | np.timedelta64], + ) -> Series: ... + @overload def __rfloordiv__( self: Series[Timedelta], other: ArrayIndexSeriesTimedeltaNoSeq ) -> Series[int]: ... @@ -2476,13 +2487,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rfloordiv( self: Series[int] | Series[float], - other: ( - timedelta - | Sequence[timedelta] - | np_ndarray_td - | TimedeltaIndex - | Series[Timedelta] - ), + other: ScalarArrayIndexSeriesTimedelta, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex = ..., @@ -2490,7 +2495,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rfloordiv( self: Series[Timedelta], - other: ArrayIndexSeriesTimedeltaNoSeq, + other: timedelta | np.timedelta64 | ArrayIndexSeriesTimedeltaNoSeq, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex = ..., @@ -3967,14 +3972,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[float]: ... @overload def __rtruediv__( - self: Series[int] | Series[float], - other: ( - timedelta - | Sequence[timedelta] - | np_ndarray_td - | TimedeltaIndex - | Series[Timedelta] - ), + self: Series[int] | Series[float], other: ScalarArrayIndexSeriesTimedelta ) -> Series[Timedelta]: ... @overload def __rtruediv__(self: Series[_str], other: Path) -> Series: ... @@ -4101,13 +4099,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[bool] | Series[int] | Series[float], - other: ( - timedelta - | Sequence[timedelta] - | np_ndarray_td - | TimedeltaIndex - | Series[Timedelta] - ), + other: ScalarArrayIndexSeriesTimedelta, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, diff --git a/tests/series/arithmetic/float/test_floordiv.py b/tests/series/arithmetic/float/test_floordiv.py index 72a803da2..6db9bbb0f 100644 --- a/tests/series/arithmetic/float/test_floordiv.py +++ b/tests/series/arithmetic/float/test_floordiv.py @@ -87,7 +87,7 @@ def test_floordiv_py_sequence(left: "pd.Series[float]") -> None: 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] + check(assert_type(d // left, pd.Series), pd.Series, timedelta) 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) diff --git a/tests/series/arithmetic/int/test_floordiv.py b/tests/series/arithmetic/int/test_floordiv.py index d3ef5d86b..5b50316ff 100644 --- a/tests/series/arithmetic/int/test_floordiv.py +++ b/tests/series/arithmetic/int/test_floordiv.py @@ -87,7 +87,7 @@ def test_floordiv_py_sequence(left: "pd.Series[int]") -> None: 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] + check(assert_type(d // left, pd.Series), pd.Series, timedelta) 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) diff --git a/tests/series/arithmetic/test_floordiv.py b/tests/series/arithmetic/test_floordiv.py index 276f0e518..de5f1901f 100644 --- a/tests/series/arithmetic/test_floordiv.py +++ b/tests/series/arithmetic/test_floordiv.py @@ -87,7 +87,7 @@ def test_floordiv_py_sequence(left_i: pd.Series) -> None: 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(d // left_i, pd.Series), pd.Series, 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) From adc611879f1f1b59fe2ab1805c02b7c33111fd3a Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 6 Nov 2025 11:42:29 +0100 Subject: [PATCH 16/23] fix: pandas-dev/pandas#63007 pytest --- pandas-stubs/core/base.pyi | 82 ++++++++- pandas-stubs/core/indexes/base.pyi | 32 +--- pandas-stubs/core/series.pyi | 169 +++--------------- .../series/arithmetic/float/test_floordiv.py | 2 +- 4 files changed, 111 insertions(+), 174 deletions(-) diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index e9447a76f..88de997b4 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -20,8 +20,11 @@ import numpy as np from pandas.core.arraylike import OpsMixin from pandas.core.arrays import ExtensionArray from pandas.core.arrays.categorical import Categorical +from pandas.core.arrays.integer import IntegerArray +from pandas.core.arrays.timedeltas import TimedeltaArray from pandas.core.indexes.accessors import ArrayDescriptor from pandas.core.indexes.base import Index +from pandas.core.indexes.timedeltas import TimedeltaIndex from pandas.core.series import Series from typing_extensions import Self @@ -40,10 +43,12 @@ from pandas._typing import ( Scalar, SupportsDType, np_1darray, + np_ndarray, np_ndarray_anyint, np_ndarray_bool, np_ndarray_complex, np_ndarray_float, + np_ndarray_td, ) from pandas.util._decorators import cache_readonly @@ -168,7 +173,82 @@ class IndexOpsMixin(OpsMixin, Generic[S1, GenericT_co]): ) -> np.intp: ... def drop_duplicates(self, *, keep: DropKeep = ...) -> Self: ... -NumListLike: TypeAlias = ( +ScalarArrayIndexJustInt: TypeAlias = ( + Just[int] + | np.integer + | Sequence[Just[int] | np.integer] + | np_ndarray_anyint + | IntegerArray + | Index[int] +) +ScalarArraySeriesJustInt: TypeAlias = ScalarArrayIndexJustInt | Series[int] +ScalarArrayIndexJustFloat: TypeAlias = ( + Just[float] + | np.floating + | Sequence[Just[float] | np.floating] + | np_ndarray_float + # | FloatingArray # TODO: after pandas-dev/pandas-stubs#1469 + | Index[float] +) +ScalarArraySeriesJustFloat: TypeAlias = ScalarArrayIndexJustFloat | Series[float] +ScalarArrayIndexJustComplex: TypeAlias = ( + Just[complex] + | np.complexfloating + | Sequence[Just[complex] | np.complexfloating] + | np_ndarray_complex + | Index[complex] +) +ScalarArraySeriesJustComplex: TypeAlias = ScalarArrayIndexJustComplex | Series[complex] + +ScalarArrayIndexIntNoBool: TypeAlias = ( + Just[int] + | np.integer + | Sequence[int | np.integer] + | np_ndarray_anyint + | IntegerArray + | Index[int] +) +ScalarArraySeriesIntNoBool: TypeAlias = ScalarArrayIndexIntNoBool | Series[int] + +NumpyRealScalar: TypeAlias = np.bool | np.integer | np.floating +IndexReal: TypeAlias = Index[bool] | Index[int] | Index[float] +ScalarArrayIndexReal: TypeAlias = ( + float + | Sequence[float | NumpyRealScalar] + | NumpyRealScalar + | np_ndarray[tuple[int, ...], NumpyRealScalar] + | ExtensionArray + | IndexReal +) +SeriesReal: TypeAlias = Series[bool] | Series[int] | Series[float] +ScalarArrayIndexSeriesReal: TypeAlias = ScalarArrayIndexReal | SeriesReal + +NumpyComplexScalar: TypeAlias = NumpyRealScalar | np.complexfloating +IndexComplex: TypeAlias = IndexReal | Index[complex] +ScalarArrayIndexComplex: TypeAlias = ( + complex + | Sequence[complex | NumpyComplexScalar] + | NumpyComplexScalar + | np_ndarray[tuple[int, ...], NumpyComplexScalar] + | ExtensionArray + | IndexComplex +) +SeriesComplex: TypeAlias = SeriesReal | Series[complex] +ScalarArrayIndexSeriesComplex: TypeAlias = ScalarArrayIndexComplex | SeriesComplex + +ArrayIndexTimedeltaNoSeq: TypeAlias = np_ndarray_td | TimedeltaArray | TimedeltaIndex +ScalarArrayIndexTimedelta: TypeAlias = ( + timedelta + | np.timedelta64 + | Sequence[timedelta | np.timedelta64] + | ArrayIndexTimedeltaNoSeq +) +ArrayIndexSeriesTimedeltaNoSeq: TypeAlias = ArrayIndexTimedeltaNoSeq | Series[Timedelta] +ScalarArrayIndexSeriesTimedelta: TypeAlias = ( + ScalarArrayIndexTimedelta | Series[Timedelta] +) + +NumListLike: TypeAlias = ( # deprecated, do not use ExtensionArray | np_ndarray_bool | np_ndarray_anyint diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 9cdf21f67..229e24996 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -16,7 +16,6 @@ from typing import ( ClassVar, Generic, Literal, - TypeAlias, final, overload, type_check_only, @@ -30,12 +29,11 @@ from _typeshed import ( _T_contra, ) import numpy as np -from pandas.core.arrays.base import ExtensionArray from pandas.core.arrays.boolean import BooleanArray -from pandas.core.arrays.timedeltas import TimedeltaArray from pandas.core.base import ( ElementOpsMixin, IndexOpsMixin, + ScalarArrayIndexReal, Supports_ProtoAdd, Supports_ProtoFloorDiv, Supports_ProtoMul, @@ -114,34 +112,6 @@ from pandas._typing import ( from pandas.core.dtypes.dtypes import PeriodDtype -NumpyRealScalar: TypeAlias = np.bool | np.integer | np.floating -IndexReal: TypeAlias = ( - Index[bool] | Index[int] | Index[float] # ty: ignore[unresolved-reference] -) -ScalarArrayIndexReal: TypeAlias = ( - float - | Sequence[float | NumpyRealScalar] - | NumpyRealScalar - | np_ndarray[tuple[int, ...], NumpyRealScalar] - | ExtensionArray # TODO: NumpyExtensionArray after pandas-dev/pandas-stubs#1469 - | IndexReal -) -NumpyComplexScalar: TypeAlias = NumpyRealScalar | np.complexfloating -IndexComplex: TypeAlias = IndexReal | Index[complex] # ty: ignore[unresolved-reference] -ScalarArrayIndexComplex: TypeAlias = ( - complex - | Sequence[complex | NumpyComplexScalar] - | NumpyComplexScalar - | np_ndarray[tuple[int, ...], NumpyComplexScalar] - | ExtensionArray # TODO: NumpyExtensionArray after pandas-dev/pandas-stubs#1469 - | IndexComplex -) - -ArrayIndexTimedeltaNoSeq: TypeAlias = np_ndarray_td | TimedeltaArray | TimedeltaIndex -ScalarArrayIndexTimedelta: TypeAlias = ( - timedelta | Sequence[timedelta | np.timedelta64] | ArrayIndexTimedeltaNoSeq -) - class InvalidIndexError(Exception): ... class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 4f28151ed..38b1c9014 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -65,9 +65,19 @@ from pandas.core.arrays.categorical import CategoricalAccessor from pandas.core.arrays.datetimes import DatetimeArray from pandas.core.arrays.timedeltas import TimedeltaArray from pandas.core.base import ( + ArrayIndexSeriesTimedeltaNoSeq, + ArrayIndexTimedeltaNoSeq, ElementOpsMixin, IndexOpsMixin, NumListLike, + ScalarArrayIndexSeriesComplex, + ScalarArrayIndexSeriesReal, + ScalarArrayIndexSeriesTimedelta, + ScalarArraySeriesIntNoBool, + ScalarArraySeriesJustComplex, + ScalarArraySeriesJustFloat, + ScalarArraySeriesJustInt, + SeriesComplex, Supports_ProtoAdd, Supports_ProtoFloorDiv, Supports_ProtoMul, @@ -83,12 +93,6 @@ from pandas.core.groupby.generic import SeriesGroupBy from pandas.core.groupby.groupby import BaseGroupBy from pandas.core.indexers import BaseIndexer from pandas.core.indexes.accessors import DtDescriptor -from pandas.core.indexes.base import ( - ArrayIndexTimedeltaNoSeq, - ScalarArrayIndexComplex, - ScalarArrayIndexReal, - ScalarArrayIndexTimedelta, -) from pandas.core.indexes.category import CategoricalIndex from pandas.core.indexes.datetimes import DatetimeIndex from pandas.core.indexes.interval import IntervalIndex @@ -309,21 +313,6 @@ _DataLikeS1: TypeAlias = ( ArrayLike | dict[_str, np.ndarray] | Sequence[S1] | IndexOpsMixin[S1] ) -SeriesReal: TypeAlias = ( - Series[bool] | Series[int] | Series[float] # ty: ignore[unresolved-reference] -) -ScalarArrayIndexSeriesReal: TypeAlias = ScalarArrayIndexReal | SeriesReal -SeriesComplex: TypeAlias = ( - SeriesReal | Series[complex] # ty: ignore[unresolved-reference] -) -ScalarArrayIndexSeriesComplex: TypeAlias = ScalarArrayIndexComplex | SeriesComplex -ArrayIndexSeriesTimedeltaNoSeq: TypeAlias = ( - ArrayIndexTimedeltaNoSeq | Series[Timedelta] # ty: ignore[unresolved-reference] -) -ScalarArrayIndexSeriesTimedelta: TypeAlias = ( - ScalarArrayIndexTimedelta | Series[Timedelta] # ty: ignore[unresolved-reference] -) - class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): # Define __index__ because mypy thinks Series follows protocol `SupportsIndex` https://github.com/pandas-dev/pandas-stubs/pull/1332#discussion_r2285648790 __index__: ClassVar[None] @@ -3641,8 +3630,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[float]: ... @overload def __truediv__( - self: Series[bool] | Series[int], - other: Just[int] | Sequence[int] | np_ndarray_anyint | Index[int] | Series[int], + self: Series[bool] | Series[int], other: ScalarArraySeriesIntNoBool ) -> Series[float]: ... @overload def __truediv__( @@ -3670,52 +3658,20 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[complex]: ... @overload def __truediv__( - self: Series[bool] | Series[int], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + self: Series[bool] | Series[int], other: ScalarArraySeriesJustFloat ) -> Series[float]: ... @overload def __truediv__( - self: Series[T_COMPLEX], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + self: Series[T_COMPLEX], other: ScalarArraySeriesJustFloat ) -> Series[T_COMPLEX]: ... @overload def __truediv__( - self: SeriesComplex, - other: ( - Just[complex] - | Sequence[Just[complex]] - | np_ndarray_complex - | Index[complex] - | Series[complex] - ), + self: SeriesComplex, other: ScalarArraySeriesJustComplex ) -> Series[complex]: ... @overload def __truediv__( self: Series[Timedelta], - 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] - ), + other: ScalarArraySeriesJustInt | ScalarArraySeriesJustFloat, ) -> Series[Timedelta]: ... @overload def __truediv__( @@ -3766,7 +3722,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[bool] | Series[int], - other: Just[int] | Sequence[int] | np_ndarray_anyint | Index[int] | Series[int], + other: ScalarArraySeriesIntNoBool, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3804,13 +3760,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[bool] | Series[int], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + other: ScalarArraySeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3818,13 +3768,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[T_COMPLEX], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + other: ScalarArraySeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3832,13 +3776,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: SeriesComplex, - other: ( - Just[complex] - | Sequence[Just[complex]] - | np_ndarray_complex - | Index[complex] - | Series[complex] - ), + other: ScalarArraySeriesJustComplex, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3846,18 +3784,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[Timedelta], - 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] - ), + other: ScalarArraySeriesJustInt | ScalarArraySeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3906,8 +3833,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[float]: ... @overload def __rtruediv__( - self: Series[bool] | Series[int], - other: Just[int] | Sequence[int] | np_ndarray_anyint | Index[int] | Series[int], + self: Series[bool] | Series[int], other: ScalarArraySeriesIntNoBool ) -> Series[float]: ... @overload def __rtruediv__( # type: ignore[misc] @@ -3935,36 +3861,15 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[complex]: ... @overload def __rtruediv__( - self: Series[bool] | Series[int], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + self: Series[bool] | Series[int], other: ScalarArraySeriesJustFloat ) -> Series[float]: ... @overload def __rtruediv__( - self: Series[T_COMPLEX], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + self: Series[T_COMPLEX], other: ScalarArraySeriesJustFloat ) -> Series[T_COMPLEX]: ... @overload def __rtruediv__( - self: SeriesComplex, - other: ( - Just[complex] - | Sequence[Just[complex]] - | np_ndarray_complex - | Index[complex] - | Series[complex] - ), + self: SeriesComplex, other: ScalarArraySeriesJustComplex ) -> Series[complex]: ... @overload def __rtruediv__( @@ -4011,7 +3916,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[bool] | Series[int], - other: Just[int] | Sequence[int] | np_ndarray_anyint | Index[int] | Series[int], + other: ScalarArraySeriesIntNoBool, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -4049,13 +3954,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[bool] | Series[int], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + other: ScalarArraySeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -4063,13 +3962,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[T_COMPLEX], - other: ( - Just[float] - | Sequence[Just[float]] - | np_ndarray_float - | Index[float] - | Series[float] - ), + other: ScalarArraySeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -4077,13 +3970,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: SeriesComplex, - other: ( - Just[complex] - | Sequence[Just[complex]] - | np_ndarray_complex - | Index[complex] - | Series[complex] - ), + other: ScalarArraySeriesJustComplex, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, diff --git a/tests/series/arithmetic/float/test_floordiv.py b/tests/series/arithmetic/float/test_floordiv.py index 6db9bbb0f..1eeed3f75 100644 --- a/tests/series/arithmetic/float/test_floordiv.py +++ b/tests/series/arithmetic/float/test_floordiv.py @@ -87,7 +87,7 @@ def test_floordiv_py_sequence(left: "pd.Series[float]") -> None: 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.Series), pd.Series, timedelta) + # check(assert_type(d // left, pd.Series), pd.Series, timedelta) TODO: uncomment after pandas-dev/pandas#63007 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) From cf7e9416c1bfe8240ea348873156635fe6116869 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 6 Nov 2025 12:07:56 +0100 Subject: [PATCH 17/23] py310 --- pandas-stubs/_typing.pyi | 3 ++ pandas-stubs/core/series.pyi | 85 +++++++++++++++--------------------- 2 files changed, 38 insertions(+), 50 deletions(-) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 8b9ec6264..ef1398965 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -854,6 +854,9 @@ np_ndarray_anyint: TypeAlias = npt.NDArray[np.integer] np_ndarray_float: TypeAlias = npt.NDArray[np.floating] np_ndarray_complex: TypeAlias = npt.NDArray[np.complexfloating] np_ndarray_bool: TypeAlias = npt.NDArray[np.bool_] +np_ndarray_num: TypeAlias = npt.NDArray[ + np.bool | np.integer | np.floating | np.complexfloating +] np_ndarray_str: TypeAlias = npt.NDArray[np.str_] np_ndarray_dt: TypeAlias = npt.NDArray[np.datetime64] np_ndarray_td: TypeAlias = npt.NDArray[np.timedelta64] diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 38b1c9014..f645d54c4 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -20,6 +20,7 @@ from datetime import ( timedelta, ) from pathlib import Path +import sys from typing import ( Any, ClassVar, @@ -78,6 +79,7 @@ from pandas.core.base import ( ScalarArraySeriesJustFloat, ScalarArraySeriesJustInt, SeriesComplex, + SeriesReal, Supports_ProtoAdd, Supports_ProtoFloorDiv, Supports_ProtoMul, @@ -220,6 +222,7 @@ from pandas._typing import ( np_ndarray_complex, np_ndarray_dt, np_ndarray_float, + np_ndarray_num, np_ndarray_str, np_ndarray_td, npt, @@ -2160,13 +2163,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): 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: np_ndarray_dt) -> Never: ... + @overload def __floordiv__( self: Series[Never], other: np_ndarray_td | TimedeltaIndex ) -> Never: ... @overload def __floordiv__( - self: Series[int] | Series[float], - other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + self: Series[int] | Series[float], other: np_ndarray_complex | np_ndarray_td ) -> Never: ... @overload def __floordiv__( @@ -2174,8 +2178,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series: ... @overload def __floordiv__( - self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], - other: Index[Never] | Series[Never], + self: SeriesReal | Series[Timedelta], other: Index[Never] | Series[Never] ) -> Series: ... @overload def __floordiv__( @@ -2210,25 +2213,21 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): float | Sequence[float] | np_ndarray_float | Index[float] | Series[float] ), ) -> Series[float]: ... + if sys.version_info >= (3, 11): + @overload + def __floordiv__( + self: Series[Timedelta], other: np_ndarray_bool | np_ndarray_complex + ) -> Never: ... + else: + @overload + def __floordiv__( # type: ignore[overload-overlap] + self: Series[Timedelta], other: np_ndarray_bool | np_ndarray_complex + ) -> Never: ... + @overload def __floordiv__( self: Series[Timedelta], - other: np_ndarray_bool | np_ndarray_complex | np_ndarray_dt, - ) -> Never: ... - @overload - def __floordiv__( - self: Series[Timedelta], - other: ( - Just[int] - | Just[float] - | Sequence[Just[int] | Just[float]] - | np_ndarray_anyint - | np_ndarray_float - | Index[int] - | Index[float] - | Series[int] - | Series[float] - ), + other: ScalarArraySeriesJustInt | ScalarArraySeriesJustFloat, ) -> Series[Timedelta]: ... @overload def __floordiv__( @@ -2252,7 +2251,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series: ... @overload def floordiv( - self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], + self: SeriesReal | Series[Timedelta], other: Index[Never] | Series[Never], level: Level | None = ..., fill_value: float | None = None, @@ -2311,17 +2310,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def floordiv( self: Series[Timedelta], - other: ( - Just[int] - | Just[float] - | Sequence[Just[int] | Just[float]] - | np_ndarray_anyint - | np_ndarray_float - | Index[int] - | Index[float] - | Series[int] - | Series[float] - ), + other: ScalarArraySeriesJustInt | ScalarArraySeriesJustFloat, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, @@ -2350,8 +2339,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Never: ... @overload def __rfloordiv__( - self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], - other: Index[Never] | Series[Never], + self: SeriesReal | Series[Timedelta], other: Index[Never] | Series[Never] ) -> Series: ... @overload def __rfloordiv__( @@ -2382,17 +2370,15 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): float | Sequence[float] | np_ndarray_float | Index[float] | Series[float] ), ) -> Series[float]: ... - @overload - def __rfloordiv__( - self: Series[Timedelta], - other: ( - np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | np_ndarray_complex - | np_ndarray_dt - ), - ) -> Never: ... + if sys.version_info >= (3, 11): + @overload + def __rfloordiv__(self: Series[Timedelta], other: np_ndarray_num) -> Never: ... + else: + @overload + def __rfloordiv__( # type: ignore[overload-overlap] + self: Series[Timedelta], other: np_ndarray_num + ) -> Never: ... + @overload def __rfloordiv__( self: Series[int] | Series[float], @@ -2417,7 +2403,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series: ... @overload def rfloordiv( - self: Series[bool] | Series[int] | Series[float] | Series[Timedelta], + self: SeriesReal | Series[Timedelta], other: Index[Never] | Series[Never], level: Level | None = ..., fill_value: float | None = None, @@ -3815,8 +3801,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series: ... @overload def __rtruediv__( - self: Series[bool] | Series[int] | Series[float] | Series[complex], - other: Index[Never] | Series[Never], + self: SeriesComplex, other: Index[Never] | Series[Never] ) -> Series: ... @overload def __rtruediv__( @@ -3891,7 +3876,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series: ... @overload def rtruediv( - self: Series[bool] | Series[int] | Series[float] | Series[complex], + self: SeriesComplex, other: Index[Never] | Series[Never], level: Level | None = None, fill_value: float | None = None, @@ -3985,7 +3970,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[float]: ... @overload def rtruediv( - self: Series[bool] | Series[int] | Series[float], + self: SeriesReal, other: ScalarArrayIndexSeriesTimedelta, level: Level | None = None, fill_value: float | None = None, From 24deb3762d57bf41e4ac6ab772382fa193d78efd Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 6 Nov 2025 15:25:50 +0100 Subject: [PATCH 18/23] index --- pandas-stubs/core/base.pyi | 15 +-- pandas-stubs/core/indexes/base.pyi | 111 +++++++++--------- pandas-stubs/core/indexes/datetimes.pyi | 4 +- pandas-stubs/core/indexes/timedeltas.pyi | 14 +-- pandas-stubs/core/series.pyi | 79 +++++-------- .../indexes/arithmetic/float/test_floordiv.py | 2 +- .../indexes/arithmetic/float/test_truediv.py | 2 +- tests/indexes/arithmetic/int/test_floordiv.py | 2 +- tests/indexes/arithmetic/int/test_truediv.py | 2 +- tests/indexes/arithmetic/test_floordiv.py | 2 +- 10 files changed, 110 insertions(+), 123 deletions(-) diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index 88de997b4..b31d16502 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -43,7 +43,6 @@ from pandas._typing import ( Scalar, SupportsDType, np_1darray, - np_ndarray, np_ndarray_anyint, np_ndarray_bool, np_ndarray_complex, @@ -181,7 +180,7 @@ ScalarArrayIndexJustInt: TypeAlias = ( | IntegerArray | Index[int] ) -ScalarArraySeriesJustInt: TypeAlias = ScalarArrayIndexJustInt | Series[int] +ScalarArrayIndexSeriesJustInt: TypeAlias = ScalarArrayIndexJustInt | Series[int] ScalarArrayIndexJustFloat: TypeAlias = ( Just[float] | np.floating @@ -190,7 +189,7 @@ ScalarArrayIndexJustFloat: TypeAlias = ( # | FloatingArray # TODO: after pandas-dev/pandas-stubs#1469 | Index[float] ) -ScalarArraySeriesJustFloat: TypeAlias = ScalarArrayIndexJustFloat | Series[float] +ScalarArrayIndexSeriesJustFloat: TypeAlias = ScalarArrayIndexJustFloat | Series[float] ScalarArrayIndexJustComplex: TypeAlias = ( Just[complex] | np.complexfloating @@ -198,7 +197,9 @@ ScalarArrayIndexJustComplex: TypeAlias = ( | np_ndarray_complex | Index[complex] ) -ScalarArraySeriesJustComplex: TypeAlias = ScalarArrayIndexJustComplex | Series[complex] +ScalarArrayIndexSeriesJustComplex: TypeAlias = ( + ScalarArrayIndexJustComplex | Series[complex] +) ScalarArrayIndexIntNoBool: TypeAlias = ( Just[int] @@ -208,7 +209,7 @@ ScalarArrayIndexIntNoBool: TypeAlias = ( | IntegerArray | Index[int] ) -ScalarArraySeriesIntNoBool: TypeAlias = ScalarArrayIndexIntNoBool | Series[int] +ScalarArrayIndexSeriesIntNoBool: TypeAlias = ScalarArrayIndexIntNoBool | Series[int] NumpyRealScalar: TypeAlias = np.bool | np.integer | np.floating IndexReal: TypeAlias = Index[bool] | Index[int] | Index[float] @@ -216,7 +217,7 @@ ScalarArrayIndexReal: TypeAlias = ( float | Sequence[float | NumpyRealScalar] | NumpyRealScalar - | np_ndarray[tuple[int, ...], NumpyRealScalar] + | np.typing.NDArray[NumpyRealScalar] | ExtensionArray | IndexReal ) @@ -229,7 +230,7 @@ ScalarArrayIndexComplex: TypeAlias = ( complex | Sequence[complex | NumpyComplexScalar] | NumpyComplexScalar - | np_ndarray[tuple[int, ...], NumpyComplexScalar] + | np.typing.NDArray[NumpyComplexScalar] | ExtensionArray | IndexComplex ) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 229e24996..8715182b5 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -31,9 +31,17 @@ from _typeshed import ( import numpy as np from pandas.core.arrays.boolean import BooleanArray from pandas.core.base import ( + ArrayIndexTimedeltaNoSeq, ElementOpsMixin, + IndexComplex, IndexOpsMixin, + IndexReal, + ScalarArrayIndexComplex, + ScalarArrayIndexIntNoBool, + ScalarArrayIndexJustComplex, + ScalarArrayIndexJustFloat, ScalarArrayIndexReal, + ScalarArrayIndexTimedelta, Supports_ProtoAdd, Supports_ProtoFloorDiv, Supports_ProtoMul, @@ -939,17 +947,19 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): self: Index[T_COMPLEX], other: np_ndarray_complex | Index[complex] ) -> Index[complex]: ... @overload - def __truediv__( - self: Index[Never], other: complex | ArrayLike | SequenceNotStr[S1] | Index + def __truediv__(self, other: np_ndarray_dt) -> Never: ... + @overload + def __truediv__( # type: ignore[overload-overlap] + self: Index[Never], other: ScalarArrayIndexComplex ) -> Index: ... @overload - def __truediv__(self, other: Index[Never]) -> Index: ... + def __truediv__(self: Index[Never], other: ArrayIndexTimedeltaNoSeq) -> Never: ... @overload - def __truediv__(self: Index[bool], other: np_ndarray_bool) -> Never: ... + def __truediv__(self: Index[T_COMPLEX], other: np_ndarray_td) -> Never: ... @overload - def __truediv__(self, other: np_ndarray_dt) -> Never: ... + def __truediv__(self: Index[bool], other: np_ndarray_bool) -> Never: ... @overload - def __truediv__(self: Index[T_COMPLEX], other: np_ndarray_td) -> Never: ... + def __truediv__(self: IndexComplex, other: Index[Never]) -> Index: ... @overload def __truediv__( self: Supports_ProtoTrueDiv[_T_contra, S2], @@ -961,8 +971,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ) -> Index[float]: ... @overload def __truediv__( - self: Index[bool] | Index[int], - other: Just[int] | Sequence[int] | np_ndarray_anyint | Index[int], + self: Index[bool] | Index[int], other: ScalarArrayIndexIntNoBool ) -> Index[float]: ... @overload def __truediv__( @@ -976,36 +985,32 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ) -> Index[complex]: ... @overload def __truediv__( - self: Index[bool] | Index[int], - other: Just[float] | Sequence[Just[float]] | np_ndarray_float | Index[float], + self: Index[bool] | Index[int], other: ScalarArrayIndexJustFloat ) -> Index[float]: ... @overload def __truediv__( - self: Index[T_COMPLEX], - other: Just[float] | Sequence[Just[float]] | np_ndarray_float | Index[float], + self: Index[T_COMPLEX], other: ScalarArrayIndexJustFloat ) -> Index[T_COMPLEX]: ... @overload def __truediv__( - self: Index[T_COMPLEX], - other: ( - Just[complex] - | Sequence[Just[complex]] - | np_ndarray_complex - | Index[complex] - ), + self: IndexComplex, other: ScalarArrayIndexJustComplex ) -> Index[complex]: ... @overload - def __truediv__(self, other: Path) -> Index: ... + def __truediv__(self: Index[_str], other: Path) -> Index: ... @overload - def __rtruediv__( - self: Index[Never], other: complex | ArrayLike | SequenceNotStr[S1] | Index - ) -> Index: ... + def __rtruediv__(self, other: np_ndarray_dt) -> Never: ... @overload - def __rtruediv__(self, other: Index[Never]) -> Index: ... # type: ignore[overload-overlap] + def __rtruediv__( # type: ignore[overload-overlap] + self: Index[Never], other: ScalarArrayIndexComplex | ScalarArrayIndexTimedelta + ) -> Index: ... @overload - def __rtruediv__(self: Index[bool], other: np_ndarray_bool) -> Never: ... + def __rtruediv__( # type: ignore[overload-overlap] + self: IndexComplex, other: Index[Never] + ) -> Index: ... @overload - def __rtruediv__(self, other: np_ndarray_dt) -> Never: ... + def __rtruediv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self: Index[int] | Index[float], other: Sequence[timedelta | np.timedelta64] + ) -> Index: ... @overload def __rtruediv__( self: Supports_ProtoRTrueDiv[_T_contra, S2], @@ -1017,8 +1022,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ) -> Index[float]: ... @overload def __rtruediv__( - self: Index[bool] | Index[int], - other: Just[int] | Sequence[int] | np_ndarray_anyint | Index[int], + self: Index[bool] | Index[int], other: ScalarArrayIndexIntNoBool ) -> Index[float]: ... @overload def __rtruediv__( # type: ignore[misc] @@ -1032,43 +1036,35 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ) -> Index[complex]: ... @overload def __rtruediv__( - self: Index[bool] | Index[int], - other: Just[float] | Sequence[Just[float]] | np_ndarray_float | Index[float], + self: Index[bool] | Index[int], other: ScalarArrayIndexJustFloat ) -> Index[float]: ... @overload def __rtruediv__( - self: Index[T_COMPLEX], - other: Just[float] | Sequence[Just[float]] | np_ndarray_float | Index[float], + self: Index[T_COMPLEX], other: ScalarArrayIndexJustFloat ) -> Index[T_COMPLEX]: ... @overload def __rtruediv__( - self: Index[T_COMPLEX], - other: ( - Just[complex] - | Sequence[Just[complex]] - | np_ndarray_complex - | Index[complex] - ), + self: IndexComplex, other: ScalarArrayIndexJustComplex ) -> Index[complex]: ... @overload def __rtruediv__( - self: Index[int] | Index[float], - other: timedelta | np.timedelta64 | np_ndarray_td | TimedeltaIndex, + self: Index[int] | Index[float], other: ScalarArrayIndexTimedelta ) -> TimedeltaIndex: ... @overload - def __rtruediv__(self, other: Path) -> Index: ... + def __rtruediv__(self: Index[_str], other: Path) -> Index: ... @overload - def __floordiv__(self: Index[Never], other: ScalarArrayIndexReal) -> Index: ... + def __floordiv__(self, other: np_ndarray_dt) -> Never: ... @overload - def __floordiv__( - self: Index[bool] | Index[int] | Index[float], other: Index[Never] - ) -> Index: ... + def __floordiv__(self: Index[Never], other: np_ndarray_td) -> Never: ... @overload def __floordiv__( - self: Index[int] | Index[float], - other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + self: Index[int] | Index[float], other: np_ndarray_complex | np_ndarray_td ) -> Never: ... @overload + def __floordiv__(self: Index[Never], other: ScalarArrayIndexReal) -> Index: ... + @overload + def __floordiv__(self: IndexReal, other: Index[Never]) -> Index: ... + @overload def __floordiv__( self: Index[bool] | Index[complex], other: np_ndarray ) -> Never: ... @@ -1099,21 +1095,24 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): other: float | Sequence[float] | np_ndarray_float | Index[float], ) -> Index[float]: ... @overload - def __rfloordiv__(self: Index[Never], other: ScalarArrayIndexReal) -> Index: ... - @overload def __rfloordiv__( # type: ignore[overload-overlap] - self: Index[bool] | Index[int] | Index[float], other: Index[Never] + self: Index[Never], other: ScalarArrayIndexReal ) -> Index: ... @overload + def __rfloordiv__(self, other: np_ndarray_complex | np_ndarray_dt) -> Never: ... + @overload def __rfloordiv__( - self: Index[int] | Index[float], - other: np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + self: Index[int] | Index[float], other: np_ndarray_td ) -> Never: ... @overload def __rfloordiv__( self: Index[bool] | Index[complex], other: np_ndarray ) -> Never: ... @overload + def __rfloordiv__( # type: ignore[overload-overlap] + self: IndexReal, other: Index[Never] + ) -> Index: ... + @overload def __rfloordiv__( self: Supports_ProtoRFloorDiv[_T_contra, S2], other: _T_contra | Sequence[_T_contra], @@ -1142,8 +1141,12 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @overload def __rfloordiv__( self: Index[int] | Index[float], - other: timedelta | np_ndarray_td | TimedeltaIndex, + other: timedelta | np.timedelta64 | ArrayIndexTimedeltaNoSeq, ) -> TimedeltaIndex: ... + @overload + def __rfloordiv__( + self: Index[int] | Index[float], other: Sequence[timedelta | np.timedelta64] + ) -> Index: ... 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 0ecf7a9a0..f0d1df255 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -76,10 +76,10 @@ class DatetimeIndex( 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] + def __truediv__( # type: ignore[override] # pyrefly: ignore[bad-override] self, other: np_ndarray ) -> Never: ... - def __rtruediv__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override] + def __rtruediv__( # type: ignore[override] # pyrefly: ignore[bad-override] self, other: np_ndarray ) -> Never: ... @final diff --git a/pandas-stubs/core/indexes/timedeltas.pyi b/pandas-stubs/core/indexes/timedeltas.pyi index 2f632cd8a..46d861bdf 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -38,6 +38,7 @@ from pandas._typing import ( np_ndarray_complex, np_ndarray_dt, np_ndarray_float, + np_ndarray_num, np_ndarray_td, ) @@ -106,6 +107,10 @@ class TimedeltaIndex( @overload def __rmul__(self, other: _NUM_FACTOR_SEQ) -> Self: ... @overload # type: ignore[override] + def __truediv__( # type: ignore[overload-overlap] + self, other: Index[Never] + ) -> Index: ... + @overload def __truediv__( # pyrefly: ignore[bad-override] self, other: np_ndarray_bool | np_ndarray_complex | np_ndarray_dt ) -> Never: ... @@ -135,14 +140,7 @@ class TimedeltaIndex( ) -> 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 - ), + self, other: np_ndarray_num | np_ndarray_dt ) -> Never: ... @overload def __rfloordiv__( # pyright: ignore[reportIncompatibleMethodOverride] diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index f645d54c4..5498339e6 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -20,7 +20,6 @@ from datetime import ( timedelta, ) from pathlib import Path -import sys from typing import ( Any, ClassVar, @@ -72,12 +71,12 @@ from pandas.core.base import ( IndexOpsMixin, NumListLike, ScalarArrayIndexSeriesComplex, + ScalarArrayIndexSeriesIntNoBool, + ScalarArrayIndexSeriesJustComplex, + ScalarArrayIndexSeriesJustFloat, + ScalarArrayIndexSeriesJustInt, ScalarArrayIndexSeriesReal, ScalarArrayIndexSeriesTimedelta, - ScalarArraySeriesIntNoBool, - ScalarArraySeriesJustComplex, - ScalarArraySeriesJustFloat, - ScalarArraySeriesJustInt, SeriesComplex, SeriesReal, Supports_ProtoAdd, @@ -2173,7 +2172,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): self: Series[int] | Series[float], other: np_ndarray_complex | np_ndarray_td ) -> Never: ... @overload - def __floordiv__( + def __floordiv__( # type: ignore[overload-overlap] self: Series[Never], other: ScalarArrayIndexSeriesReal ) -> Series: ... @overload @@ -2213,21 +2212,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): float | Sequence[float] | np_ndarray_float | Index[float] | Series[float] ), ) -> Series[float]: ... - if sys.version_info >= (3, 11): - @overload - def __floordiv__( - self: Series[Timedelta], other: np_ndarray_bool | np_ndarray_complex - ) -> Never: ... - else: - @overload - def __floordiv__( # type: ignore[overload-overlap] - self: Series[Timedelta], other: np_ndarray_bool | np_ndarray_complex - ) -> Never: ... - + @overload + def __floordiv__( + self: Series[Timedelta], other: np_ndarray_bool | np_ndarray_complex + ) -> Never: ... @overload def __floordiv__( self: Series[Timedelta], - other: ScalarArraySeriesJustInt | ScalarArraySeriesJustFloat, + other: ScalarArrayIndexSeriesJustInt | ScalarArrayIndexSeriesJustFloat, ) -> Series[Timedelta]: ... @overload def __floordiv__( @@ -2310,7 +2302,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def floordiv( self: Series[Timedelta], - other: ScalarArraySeriesJustInt | ScalarArraySeriesJustFloat, + other: ScalarArrayIndexSeriesJustInt | ScalarArrayIndexSeriesJustFloat, level: Level | None = ..., fill_value: float | None = None, axis: AxisIndex | None = 0, @@ -2324,7 +2316,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): axis: AxisIndex | None = 0, ) -> Series[int]: ... @overload - def __rfloordiv__( + def __rfloordiv__( # type: ignore[overload-overlap] self: Series[Never], other: ScalarArrayIndexSeriesReal ) -> Series: ... @overload @@ -2370,15 +2362,8 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): float | Sequence[float] | np_ndarray_float | Index[float] | Series[float] ), ) -> Series[float]: ... - if sys.version_info >= (3, 11): - @overload - def __rfloordiv__(self: Series[Timedelta], other: np_ndarray_num) -> Never: ... - else: - @overload - def __rfloordiv__( # type: ignore[overload-overlap] - self: Series[Timedelta], other: np_ndarray_num - ) -> Never: ... - + @overload + def __rfloordiv__(self: Series[Timedelta], other: np_ndarray_num) -> Never: ... @overload def __rfloordiv__( self: Series[int] | Series[float], @@ -3616,7 +3601,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[float]: ... @overload def __truediv__( - self: Series[bool] | Series[int], other: ScalarArraySeriesIntNoBool + self: Series[bool] | Series[int], other: ScalarArrayIndexSeriesIntNoBool ) -> Series[float]: ... @overload def __truediv__( @@ -3644,20 +3629,20 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[complex]: ... @overload def __truediv__( - self: Series[bool] | Series[int], other: ScalarArraySeriesJustFloat + self: Series[bool] | Series[int], other: ScalarArrayIndexSeriesJustFloat ) -> Series[float]: ... @overload def __truediv__( - self: Series[T_COMPLEX], other: ScalarArraySeriesJustFloat + self: Series[T_COMPLEX], other: ScalarArrayIndexSeriesJustFloat ) -> Series[T_COMPLEX]: ... @overload def __truediv__( - self: SeriesComplex, other: ScalarArraySeriesJustComplex + self: SeriesComplex, other: ScalarArrayIndexSeriesJustComplex ) -> Series[complex]: ... @overload def __truediv__( self: Series[Timedelta], - other: ScalarArraySeriesJustInt | ScalarArraySeriesJustFloat, + other: ScalarArrayIndexSeriesJustInt | ScalarArrayIndexSeriesJustFloat, ) -> Series[Timedelta]: ... @overload def __truediv__( @@ -3708,7 +3693,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[bool] | Series[int], - other: ScalarArraySeriesIntNoBool, + other: ScalarArrayIndexSeriesIntNoBool, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3746,7 +3731,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[bool] | Series[int], - other: ScalarArraySeriesJustFloat, + other: ScalarArrayIndexSeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3754,7 +3739,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[T_COMPLEX], - other: ScalarArraySeriesJustFloat, + other: ScalarArrayIndexSeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3762,7 +3747,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: SeriesComplex, - other: ScalarArraySeriesJustComplex, + other: ScalarArrayIndexSeriesJustComplex, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3770,7 +3755,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def truediv( self: Series[Timedelta], - other: ScalarArraySeriesJustInt | ScalarArraySeriesJustFloat, + other: ScalarArrayIndexSeriesJustInt | ScalarArrayIndexSeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3818,7 +3803,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[float]: ... @overload def __rtruediv__( - self: Series[bool] | Series[int], other: ScalarArraySeriesIntNoBool + self: Series[bool] | Series[int], other: ScalarArrayIndexSeriesIntNoBool ) -> Series[float]: ... @overload def __rtruediv__( # type: ignore[misc] @@ -3846,15 +3831,15 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ) -> Series[complex]: ... @overload def __rtruediv__( - self: Series[bool] | Series[int], other: ScalarArraySeriesJustFloat + self: Series[bool] | Series[int], other: ScalarArrayIndexSeriesJustFloat ) -> Series[float]: ... @overload def __rtruediv__( - self: Series[T_COMPLEX], other: ScalarArraySeriesJustFloat + self: Series[T_COMPLEX], other: ScalarArrayIndexSeriesJustFloat ) -> Series[T_COMPLEX]: ... @overload def __rtruediv__( - self: SeriesComplex, other: ScalarArraySeriesJustComplex + self: SeriesComplex, other: ScalarArrayIndexSeriesJustComplex ) -> Series[complex]: ... @overload def __rtruediv__( @@ -3901,7 +3886,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[bool] | Series[int], - other: ScalarArraySeriesIntNoBool, + other: ScalarArrayIndexSeriesIntNoBool, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3939,7 +3924,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[bool] | Series[int], - other: ScalarArraySeriesJustFloat, + other: ScalarArrayIndexSeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3947,7 +3932,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: Series[T_COMPLEX], - other: ScalarArraySeriesJustFloat, + other: ScalarArrayIndexSeriesJustFloat, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, @@ -3955,7 +3940,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def rtruediv( self: SeriesComplex, - other: ScalarArraySeriesJustComplex, + other: ScalarArrayIndexSeriesJustComplex, level: Level | None = None, fill_value: float | None = None, axis: AxisIndex = 0, diff --git a/tests/indexes/arithmetic/float/test_floordiv.py b/tests/indexes/arithmetic/float/test_floordiv.py index e52d58dfa..502b148b6 100644 --- a/tests/indexes/arithmetic/float/test_floordiv.py +++ b/tests/indexes/arithmetic/float/test_floordiv.py @@ -67,7 +67,7 @@ def test_floordiv_py_sequence(left: "pd.Index[float]") -> None: 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] + # check(assert_type(d // left, pd.Index), pd.Index, timedelta) TODO: pandas-dev/pandas#63007 def test_floordiv_numpy_array(left: "pd.Index[float]") -> None: diff --git a/tests/indexes/arithmetic/float/test_truediv.py b/tests/indexes/arithmetic/float/test_truediv.py index f26fe1070..5840191c2 100644 --- a/tests/indexes/arithmetic/float/test_truediv.py +++ b/tests/indexes/arithmetic/float/test_truediv.py @@ -68,7 +68,7 @@ def test_truediv_py_sequence(left: "pd.Index[float]") -> None: 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] + check(assert_type(d / left, pd.Index), pd.Index, timedelta) def test_truediv_numpy_array(left: "pd.Index[float]") -> None: diff --git a/tests/indexes/arithmetic/int/test_floordiv.py b/tests/indexes/arithmetic/int/test_floordiv.py index d0578248d..f1942d637 100644 --- a/tests/indexes/arithmetic/int/test_floordiv.py +++ b/tests/indexes/arithmetic/int/test_floordiv.py @@ -67,7 +67,7 @@ def test_floordiv_py_sequence(left: "pd.Index[int]") -> None: 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] + check(assert_type(d // left, pd.Index), pd.Index, timedelta) def test_floordiv_numpy_array(left: "pd.Index[int]") -> None: diff --git a/tests/indexes/arithmetic/int/test_truediv.py b/tests/indexes/arithmetic/int/test_truediv.py index 6df55ce33..9775359e6 100644 --- a/tests/indexes/arithmetic/int/test_truediv.py +++ b/tests/indexes/arithmetic/int/test_truediv.py @@ -68,7 +68,7 @@ def test_truediv_py_sequence(left: "pd.Index[int]") -> None: 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] + check(assert_type(d / left, pd.Index), pd.Index, timedelta) def test_truediv_numpy_array(left: "pd.Index[int]") -> None: diff --git a/tests/indexes/arithmetic/test_floordiv.py b/tests/indexes/arithmetic/test_floordiv.py index 1809b0920..4b56ec51c 100644 --- a/tests/indexes/arithmetic/test_floordiv.py +++ b/tests/indexes/arithmetic/test_floordiv.py @@ -67,7 +67,7 @@ def test_floordiv_py_sequence(left_i: pd.Index) -> None: 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(d // left_i, pd.Index), pd.Index, timedelta) def test_floordiv_numpy_array(left_i: pd.Index) -> None: From ef55cacc2463122113df6429e2d706a3d47dd4c2 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 6 Nov 2025 15:54:13 +0100 Subject: [PATCH 19/23] comment --- tests/series/arithmetic/test_floordiv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/series/arithmetic/test_floordiv.py b/tests/series/arithmetic/test_floordiv.py index de5f1901f..73bdb55d2 100644 --- a/tests/series/arithmetic/test_floordiv.py +++ b/tests/series/arithmetic/test_floordiv.py @@ -143,7 +143,7 @@ def _05() -> None: # pyright: ignore[reportUnusedFunction] 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(d // left_i, Any), pd.Series, pd.Timedelta) # 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) From ae8e3381958fddbb3e128ee2b4fe05bedc45c417 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 6 Nov 2025 16:01:19 +0100 Subject: [PATCH 20/23] pre-commit --- tests/series/arithmetic/test_floordiv.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/series/arithmetic/test_floordiv.py b/tests/series/arithmetic/test_floordiv.py index 73bdb55d2..03a5f607d 100644 --- a/tests/series/arithmetic/test_floordiv.py +++ b/tests/series/arithmetic/test_floordiv.py @@ -143,7 +143,11 @@ def _05() -> None: # pyright: ignore[reportUnusedFunction] if TYPE_CHECKING_INVALID_USAGE: assert_type(c // left_i, Any) assert_type(s // left_i, Any) - check(assert_type(d // left_i, Any), pd.Series, pd.Timedelta) # pyright: ignore[reportAssertTypeFailure] + check( + assert_type(d // left_i, Any), # pyright: ignore[reportAssertTypeFailure] + 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) From bddadcbcb1b5d5dc12aff4460b1987d34c2e9168 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 7 Nov 2025 10:57:13 +0100 Subject: [PATCH 21/23] comments --- tests/series/arithmetic/test_floordiv.py | 21 ++++++++++----------- tests/series/arithmetic/test_truediv.py | 2 +- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/series/arithmetic/test_floordiv.py b/tests/series/arithmetic/test_floordiv.py index 03a5f607d..57073b7ef 100644 --- a/tests/series/arithmetic/test_floordiv.py +++ b/tests/series/arithmetic/test_floordiv.py @@ -154,10 +154,16 @@ def _05() -> None: # pyright: ignore[reportUnusedFunction] check(assert_type(left_i.floordiv(f), pd.Series), pd.Series, np.floating) def _23() -> None: # pyright: ignore[reportUnusedFunction] - left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + assert_type( + left_i.floordiv(c), # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportAssertTypeFailure,reportCallIssue] + Never, + ) def _24() -> None: # pyright: ignore[reportUnusedFunction] - left_i.floordiv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + assert_type( + left_i.floordiv(s), # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportAssertTypeFailure,reportCallIssue] + Never, + ) def _25() -> None: # pyright: ignore[reportUnusedFunction] assert_type(left_i.floordiv(d), Never) @@ -165,13 +171,9 @@ def _25() -> None: # pyright: ignore[reportUnusedFunction] 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) - - def _33() -> None: # pyright: ignore[reportUnusedFunction] + if TYPE_CHECKING_INVALID_USAGE: left_i.rfloordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - - def _34() -> None: # pyright: ignore[reportUnusedFunction] 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, @@ -257,11 +259,8 @@ def test_floordiv_pd_series(left_i: pd.Series) -> None: 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) - - def _23() -> None: # pyright: ignore[reportUnusedFunction] - left_i.floordiv(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - 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 diff --git a/tests/series/arithmetic/test_truediv.py b/tests/series/arithmetic/test_truediv.py index cd08b9e39..05e08f4d9 100644 --- a/tests/series/arithmetic/test_truediv.py +++ b/tests/series/arithmetic/test_truediv.py @@ -388,7 +388,7 @@ def test_truediv_str_py_str(left_i: pd.Series) -> None: if TYPE_CHECKING_INVALID_USAGE: _00 = left_i / s # type: ignore[operator] # pyright:ignore[reportOperatorIssue] - _01: pd.Series = s / left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] + _01 = s / left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] left_i.truediv(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left_i.div(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] From e342c8e7f43274cd20a7349a5d7b39a49b7434a7 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 7 Nov 2025 11:27:10 +0100 Subject: [PATCH 22/23] pandas-dev/pandas-stubs#1474 --- pandas-stubs/core/base.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index b31d16502..826805678 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -249,7 +249,7 @@ ScalarArrayIndexSeriesTimedelta: TypeAlias = ( ScalarArrayIndexTimedelta | Series[Timedelta] ) -NumListLike: TypeAlias = ( # deprecated, do not use +NumListLike: TypeAlias = ( # TODO: pandas-dev/pandas-stubs#1474 deprecated, do not use ExtensionArray | np_ndarray_bool | np_ndarray_anyint From b85a68a99ece4ce072c4ca4c602991861ffab2bd Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Fri, 7 Nov 2025 17:08:54 +0100 Subject: [PATCH 23/23] numpy/numpy#30173 --- tests/series/arithmetic/test_truediv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/series/arithmetic/test_truediv.py b/tests/series/arithmetic/test_truediv.py index 05e08f4d9..1d1f1f609 100644 --- a/tests/series/arithmetic/test_truediv.py +++ b/tests/series/arithmetic/test_truediv.py @@ -175,7 +175,7 @@ def test_truediv_numpy_array(left_i: pd.Series) -> None: pd.Series, ) if TYPE_CHECKING_INVALID_USAGE: - assert_type(s / left_i, Any) + assert_type(s / left_i, Any) # TODO: numpy/numpy#30173 numpy should reject this assert_type(d / left_i, Any) # pyright: ignore[reportAssertTypeFailure] check(assert_type(left_i.truediv(b), pd.Series), pd.Series)