From 044435893ac85e8b2674a487789abb83da750a12 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sat, 27 Sep 2025 19:35:13 +0200 Subject: [PATCH 01/15] feat(arithmetic): multiplication --- pandas-stubs/_libs/tslibs/period.pyi | 33 +- pandas-stubs/_libs/tslibs/timedeltas.pyi | 88 ++-- pandas-stubs/_typing.pyi | 18 +- pandas-stubs/core/indexes/base.pyi | 116 ++++- pandas-stubs/core/indexes/datetimelike.pyi | 16 +- pandas-stubs/core/indexes/datetimes.pyi | 19 +- pandas-stubs/core/indexes/timedeltas.pyi | 41 +- pandas-stubs/core/series.pyi | 467 +++++++----------- tests/indexes/arithmetic/bool/test_mul.py | 0 tests/indexes/arithmetic/complex/test_mul.py | 0 tests/indexes/arithmetic/datetime/__init__.py | 0 tests/indexes/arithmetic/float/test_mul.py | 128 +++++ tests/indexes/arithmetic/int/test_mul.py | 126 +++++ tests/indexes/arithmetic/test_mul.py | 0 .../indexes/arithmetic/timedelta/__init__.py | 0 .../indexes/arithmetic/timedelta/test_mul.py | 0 tests/scalars/test_scalars.py | 45 -- tests/series/arithmetic/float/test_mul.py | 85 +++- tests/series/arithmetic/int/test_mul.py | 85 +++- tests/series/arithmetic/test_mul.py | 4 +- tests/series/arithmetic/timedelta/test_mul.py | 4 +- tests/series/test_series.py | 24 - tests/test_timefuncs.py | 68 +-- 23 files changed, 860 insertions(+), 507 deletions(-) create mode 100644 tests/indexes/arithmetic/bool/test_mul.py create mode 100644 tests/indexes/arithmetic/complex/test_mul.py create mode 100644 tests/indexes/arithmetic/datetime/__init__.py create mode 100644 tests/indexes/arithmetic/float/test_mul.py create mode 100644 tests/indexes/arithmetic/int/test_mul.py create mode 100644 tests/indexes/arithmetic/test_mul.py create mode 100644 tests/indexes/arithmetic/timedelta/__init__.py create mode 100644 tests/indexes/arithmetic/timedelta/test_mul.py diff --git a/pandas-stubs/_libs/tslibs/period.pyi b/pandas-stubs/_libs/tslibs/period.pyi index 897153c2e..55b1a2bfb 100644 --- a/pandas-stubs/_libs/tslibs/period.pyi +++ b/pandas-stubs/_libs/tslibs/period.pyi @@ -12,7 +12,10 @@ from pandas import ( Timedelta, TimedeltaIndex, ) -from typing_extensions import TypeAlias +from typing_extensions import ( + Self, + TypeAlias, +) from pandas._libs.tslibs import NaTType from pandas._libs.tslibs.offsets import BaseOffset @@ -87,15 +90,23 @@ class Period(PeriodMixin): @overload def __sub__(self, other: TimedeltaIndex) -> PeriodIndex: ... @overload - def __add__(self, other: _PeriodAddSub) -> Period: ... + def __add__(self, other: _PeriodAddSub) -> Self: ... @overload def __add__(self, other: NaTType) -> NaTType: ... @overload def __add__(self, other: Index) -> PeriodIndex: ... + # Ignored due to indecipherable error from mypy: + # Forward operator "__add__" is not callable [misc] @overload - def __add__( - self, other: Series[BaseOffset] | Series[Timedelta] - ) -> Series[Period]: ... # pyrefly: ignore[bad-specialization] + def __radd__(self, other: _PeriodAddSub) -> Self: ... # type: ignore[misc] + @overload + def __radd__(self, other: NaTType) -> NaTType: ... + # Real signature is -> PeriodIndex, but conflicts with Index.__add__ + # Changing Index is very hard due to Index inheritance + # Signatures of "__radd__" of "Period" and "__add__" of "Index" + # are unsafely overlapping + @overload + def __radd__(self, other: Index) -> PeriodIndex: ... # ignore[misc] here because we know all other comparisons # are False, so we use Literal[False] @overload @@ -168,18 +179,6 @@ class Period(PeriodMixin): def __ne__(self, other: np_ndarray[ShapeT, np.object_]) -> np_ndarray[ShapeT, np.bool]: ... # type: ignore[overload-overlap] @overload def __ne__(self, other: object) -> Literal[True]: ... - # Ignored due to indecipherable error from mypy: - # Forward operator "__add__" is not callable [misc] - @overload - def __radd__(self, other: _PeriodAddSub) -> Period: ... # type: ignore[misc] - # Real signature is -> PeriodIndex, but conflicts with Index.__add__ - # Changing Index is very hard due to Index inheritance - # Signatures of "__radd__" of "Period" and "__add__" of "Index" - # are unsafely overlapping - @overload - def __radd__(self, other: Index) -> Index: ... - @overload - def __radd__(self, other: NaTType) -> NaTType: ... @property def day(self) -> int: ... @property diff --git a/pandas-stubs/_libs/tslibs/timedeltas.pyi b/pandas-stubs/_libs/tslibs/timedeltas.pyi index 9ad5e0e68..a8adc91f3 100644 --- a/pandas-stubs/_libs/tslibs/timedeltas.pyi +++ b/pandas-stubs/_libs/tslibs/timedeltas.pyi @@ -1,6 +1,9 @@ # pyright: strict -import datetime as dt -from datetime import timedelta +from datetime import ( + date, + datetime, + timedelta, +) from typing import ( ClassVar, Literal, @@ -135,9 +138,9 @@ class Timedelta(timedelta): def ceil(self, freq: str | BaseOffset) -> Self: ... @property def resolution_string(self) -> str: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload # type: ignore[override] - def __add__(self, other: dt.datetime | np.datetime64) -> Timestamp: ... + def __add__(self, other: datetime | np.datetime64) -> Timestamp: ... @overload def __add__(self, other: timedelta | np.timedelta64) -> Self: ... @overload @@ -145,7 +148,7 @@ class Timedelta(timedelta): @overload def __add__(self, other: Period) -> Period: ... @overload - def __add__(self, other: dt.date) -> dt.date: ... + def __add__(self, other: date) -> date: ... @overload def __add__( self, other: np_ndarray[ShapeT, np.timedelta64] @@ -155,13 +158,13 @@ class Timedelta(timedelta): self, other: np_ndarray[ShapeT, np.datetime64] ) -> np_ndarray[ShapeT, np.datetime64]: ... @overload - def __radd__(self, other: dt.datetime | np.datetime64) -> Timestamp: ... # type: ignore[misc] + def __radd__(self, other: datetime | np.datetime64) -> Timestamp: ... # type: ignore[misc] @overload def __radd__(self, other: timedelta | np.timedelta64) -> Self: ... @overload def __radd__(self, other: NaTType) -> NaTType: ... @overload - def __radd__(self, other: dt.date) -> dt.date: ... + def __radd__(self, other: date) -> date: ... @overload def __radd__( self, other: np_ndarray[ShapeT, np.timedelta64] @@ -170,9 +173,9 @@ class Timedelta(timedelta): def __radd__( self, other: np_ndarray[ShapeT, np.datetime64] ) -> np_ndarray[ShapeT, np.datetime64]: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload # type: ignore[override] - def __sub__(self, other: timedelta | Timedelta | np.timedelta64) -> Timedelta: ... + def __sub__(self, other: timedelta | Timedelta | np.timedelta64) -> Self: ... @overload def __sub__(self, other: NaTType) -> NaTType: ... @overload @@ -182,11 +185,9 @@ class Timedelta(timedelta): @overload def __sub__(self, other: pd.TimedeltaIndex) -> TimedeltaIndex: ... @overload - def __sub__(self, other: Series[pd.Timedelta]) -> Series[pd.Timedelta]: ... - @overload - def __rsub__(self, other: timedelta | Timedelta | np.timedelta64) -> Timedelta: ... + def __rsub__(self, other: timedelta | Timedelta | np.timedelta64) -> Self: ... @overload - def __rsub__(self, other: dt.datetime | Timestamp | np.datetime64) -> Timestamp: ... # type: ignore[misc] + def __rsub__(self, other: datetime | Timestamp | np.datetime64) -> Timestamp: ... # type: ignore[misc] @overload def __rsub__(self, other: NaTType) -> NaTType: ... @overload @@ -205,44 +206,31 @@ class Timedelta(timedelta): ) -> np_ndarray[ShapeT, np.timedelta64]: ... @overload def __rsub__(self, other: pd.TimedeltaIndex) -> pd.TimedeltaIndex: ... - def __neg__(self) -> Timedelta: ... - def __pos__(self) -> Timedelta: ... - def __abs__(self) -> Timedelta: ... - # Override due to more types supported than dt.timedelta + def __neg__(self) -> Self: ... + def __pos__(self) -> Self: ... + def __abs__(self) -> Self: ... + # Override due to more types supported than timedelta @overload # type: ignore[override] - def __mul__(self, other: float) -> Timedelta: ... + def __mul__(self, other: float) -> Self: ... @overload def __mul__( - self, other: np_ndarray[ShapeT, np.integer] | np_ndarray[ShapeT, np.floating] + self, other: np_ndarray[ShapeT, np.bool_ | np.integer | np.floating] ) -> np_ndarray[ShapeT, np.timedelta64]: ... @overload - def __mul__(self, other: Series[int]) -> Series[Timedelta]: ... - @overload - def __mul__(self, other: Series[float]) -> Series[Timedelta]: ... - @overload - def __mul__(self, other: Index[int] | Index[float]) -> TimedeltaIndex: ... - @overload - def __rmul__(self, other: float) -> Timedelta: ... + def __rmul__(self, other: float) -> Self: ... @overload def __rmul__( - self, other: np_ndarray[ShapeT, np.floating] | np_ndarray[ShapeT, np.integer] + self, other: np_ndarray[ShapeT, np.bool_ | np.integer | np.floating] ) -> np_ndarray[ShapeT, np.timedelta64]: ... - @overload - def __rmul__(self, other: Series[int]) -> Series[Timedelta]: ... - @overload - def __rmul__(self, other: Series[float]) -> Series[Timedelta]: ... - # maybe related to https://github.com/python/mypy/issues/10755 - @overload - def __rmul__(self, other: Index[int] | Index[float]) -> TimedeltaIndex: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta # error: Signature of "__floordiv__" incompatible with supertype "timedelta" @overload # type: ignore[override] def __floordiv__(self, other: timedelta | Timedelta | np.timedelta64) -> int: ... @overload - def __floordiv__(self, other: float) -> Timedelta: ... + def __floordiv__(self, other: float) -> Self: ... @overload def __floordiv__( - self, other: np_ndarray[ShapeT, np.integer] | np_ndarray[ShapeT, np.floating] + self, other: np_ndarray[ShapeT, np.integer | np.floating] ) -> np_ndarray[ShapeT, np.timedelta64]: ... @overload def __floordiv__( @@ -266,14 +254,14 @@ class Timedelta(timedelta): def __rfloordiv__( self, other: np_ndarray[ShapeT, np.timedelta64] ) -> np_ndarray[ShapeT, np.int_]: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload # type: ignore[override] def __truediv__(self, other: timedelta | Timedelta | NaTType) -> float: ... @overload - def __truediv__(self, other: float) -> Timedelta: ... + def __truediv__(self, other: float) -> Self: ... @overload def __truediv__( - self, other: np_ndarray[ShapeT, np.integer] | np_ndarray[ShapeT, np.floating] + self, other: np_ndarray[ShapeT, np.integer | np.floating] ) -> np_ndarray[ShapeT, np.timedelta64]: ... @overload def __truediv__(self, other: Series[Timedelta]) -> Series[float]: ... @@ -284,7 +272,7 @@ class Timedelta(timedelta): @overload def __truediv__(self, other: Index[int] | Index[float]) -> TimedeltaIndex: ... def __rtruediv__(self, other: timedelta | Timedelta | NaTType) -> float: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload def __eq__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload @@ -297,7 +285,7 @@ class Timedelta(timedelta): ) -> np_ndarray[ShapeT, np.bool_]: ... @overload def __eq__(self, other: object) -> Literal[False]: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload def __ne__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload @@ -310,18 +298,18 @@ class Timedelta(timedelta): ) -> np_ndarray[ShapeT, np.bool_]: ... @overload def __ne__(self, other: object) -> Literal[True]: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload # type: ignore[override] - def __mod__(self, other: timedelta) -> Timedelta: ... + def __mod__(self, other: timedelta) -> Self: ... @overload - def __mod__(self, other: float) -> Timedelta: ... + def __mod__(self, other: float) -> Self: ... @overload def __mod__(self, other: Series[int] | Series[float]) -> Series[Timedelta]: ... @overload def __mod__(self, other: Index[int] | Index[float]) -> TimedeltaIndex: ... @overload def __mod__( - self, other: np_ndarray[ShapeT, np.integer] | np_ndarray[ShapeT, np.floating] + self, other: np_ndarray[ShapeT, np.integer | np.floating] ) -> np_ndarray[ShapeT, np.timedelta64]: ... @overload def __mod__( @@ -330,7 +318,7 @@ class Timedelta(timedelta): def __divmod__(self, other: timedelta) -> tuple[int, Timedelta]: ... # Mypy complains Forward operator "" is not callable, so ignore misc # for le, lt ge and gt - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload # type: ignore[override] def __le__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] @overload @@ -341,7 +329,7 @@ class Timedelta(timedelta): ) -> np_ndarray[ShapeT, np.bool_]: ... @overload def __le__(self, other: Series[pd.Timedelta]) -> Series[bool]: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload # type: ignore[override] def __lt__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] @overload @@ -352,7 +340,7 @@ class Timedelta(timedelta): ) -> np_ndarray[ShapeT, np.bool_]: ... @overload def __lt__(self, other: Series[pd.Timedelta]) -> Series[bool]: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload # type: ignore[override] def __ge__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] @overload @@ -363,7 +351,7 @@ class Timedelta(timedelta): ) -> np_ndarray[ShapeT, np.bool_]: ... @overload def __ge__(self, other: Series[pd.Timedelta]) -> Series[bool]: ... - # Override due to more types supported than dt.timedelta + # Override due to more types supported than timedelta @overload # type: ignore[override] def __gt__(self, other: timedelta | Timedelta | np.timedelta64) -> bool: ... # type: ignore[misc] @overload diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index b852fcc65..9e24a97a5 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -173,7 +173,8 @@ RandomState: TypeAlias = ( ) # dtypes -NpDtype: TypeAlias = str | np.dtype[np.generic] | type[str | complex | bool | object] +NpDtypeNoStr: TypeAlias = np.dtype[np.generic] | type[complex | bool | object] +NpDtype: TypeAlias = str | NpDtypeNoStr | type[str] Dtype: TypeAlias = ExtensionDtype | NpDtype # AstypeArg is more carefully defined here as compared to pandas @@ -847,19 +848,21 @@ MaskType: TypeAlias = Series[bool] | np_ndarray_bool | list[bool] T_INT = TypeVar("T_INT", bound=int) T_COMPLEX = TypeVar("T_COMPLEX", bound=complex) -SeriesDTypeNoDateTime: TypeAlias = ( - str - | bytes +SeriesDTypeNoStrDateTime: TypeAlias = ( + bytes | bool | int | float | complex - | Dtype + | NpDtypeNoStr + | ExtensionDtype | Period | Interval | CategoricalDtype | BaseOffset - | list[str] +) +SeriesDTypeNoDateTime: TypeAlias = ( + str | SeriesDTypeNoStrDateTime | type[str] | list[str] ) SeriesDType: TypeAlias = ( SeriesDTypeNoDateTime @@ -869,6 +872,9 @@ SeriesDType: TypeAlias = ( | datetime.timedelta # includes pd.Timedelta ) S1 = TypeVar("S1", bound=SeriesDType, default=Any) +S1_CO_NSDT = TypeVar( + "S1_CO_NSDT", bound=SeriesDTypeNoStrDateTime, default=Any, covariant=True +) S1_CT_NDT = TypeVar( "S1_CT_NDT", bound=SeriesDTypeNoDateTime, default=Any, contravariant=True ) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index a66b96513..4273d66db 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -21,7 +21,9 @@ from typing import ( from _typeshed import ( SupportsAdd, + SupportsMul, SupportsRAdd, + SupportsRMul, ) import numpy as np from pandas import ( @@ -49,12 +51,15 @@ from typing_extensions import ( ) from pandas._libs.interval import _OrderableT +from pandas._libs.tslibs.timedeltas import Timedelta from pandas._typing import ( C2, S1, S1_CO, + S1_CO_NSDT, S1_CT, T_COMPLEX, + T_INT, AnyAll, ArrayLike, AxesData, @@ -84,8 +89,10 @@ from pandas._typing import ( np_ndarray_anyint, np_ndarray_bool, np_ndarray_complex, + np_ndarray_dt, np_ndarray_float, np_ndarray_str, + np_ndarray_td, type_t, ) @@ -740,16 +747,115 @@ class Index(IndexOpsMixin[S1]): ), ) -> Index[complex]: ... @overload + def __mul__(self: Index[Never], other: complex | _ListLike | Index) -> Index: ... + @overload + def __mul__(self, other: Index[Never]) -> Index: ... + @overload + def __mul__(self, other: np_ndarray_dt) -> Never: ... + # pandas-dev/pandas#62524 + @overload + def __mul__( # type: ignore[overload-overlap] + self: Index[bool] | Index[int] | Index[float], other: Sequence[timedelta] + ) -> Index[Timedelta]: ... + @overload def __mul__( - self: Index[int] | Index[float], other: timedelta + self: Index[bool] | Index[int] | Index[float], + other: timedelta | Sequence[Timedelta] | np.timedelta64 | np_ndarray_td, ) -> TimedeltaIndex: ... @overload + def __mul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... + @overload + def __mul__(self: Index[float], other: int | Sequence[int]) -> Index[float]: ... + @overload def __mul__( - self, other: float | Sequence[float] | Index[int] | Index[float] - ) -> Self: ... + self: Index[complex], other: float | Sequence[float] + ) -> Index[complex]: ... + @overload + def __mul__( + self: Index[S1_CT], + other: ( + SupportsRMul[S1_CT, S1_CO_NSDT] | Sequence[SupportsRMul[S1_CT, S1_CO_NSDT]] + ), + ) -> Index[S1_CO_NSDT]: ... + @overload + def __mul__( + self: Index[T_COMPLEX], other: np_ndarray_bool | Index[bool] + ) -> Index[T_COMPLEX]: ... + @overload + def __mul__( + self: Index[bool], other: np_ndarray_anyint | Index[int] + ) -> Index[int]: ... + @overload + def __mul__( + self: Index[T_COMPLEX], other: np_ndarray_anyint | Index[int] + ) -> Index[T_COMPLEX]: ... + @overload + def __mul__( + self: Index[bool] | Index[int], other: np_ndarray_float | Index[float] + ) -> Index[float]: ... + @overload + def __mul__( + self: Index[T_COMPLEX], other: np_ndarray_float | Index[float] + ) -> Index[T_COMPLEX]: ... + @overload + def __mul__( + self: Index[T_COMPLEX], other: np_ndarray_complex | Index[complex] + ) -> Index[complex]: ... + @overload + def __rmul__(self: Index[Never], other: complex | _ListLike | Index) -> Index: ... + @overload + def __rmul__(self, other: Index[Never]) -> Index: ... + @overload + def __rmul__(self, other: np_ndarray_dt) -> Never: ... + # pandas-dev/pandas#62524 + @overload + def __rmul__( # type: ignore[overload-overlap] + self: Index[bool] | Index[int] | Index[float], other: Sequence[timedelta] + ) -> Index[Timedelta]: ... + @overload def __rmul__( - self, other: float | Sequence[float] | Index[int] | Index[float] - ) -> Self: ... + self: Index[bool] | Index[int] | Index[float], + other: timedelta | Sequence[Timedelta] | np.timedelta64 | np_ndarray_td, + ) -> TimedeltaIndex: ... + @overload + def __rmul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... + @overload + def __rmul__(self: Index[float], other: int | Sequence[int]) -> Index[float]: ... + @overload + def __rmul__( + self: Index[complex], other: float | Sequence[float] + ) -> Index[complex]: ... + @overload + def __rmul__( + self: Index[S1_CT], + other: ( + SupportsMul[S1_CT, S1_CO_NSDT] | Sequence[SupportsMul[S1_CT, S1_CO_NSDT]] + ), + ) -> Index[S1_CO_NSDT]: ... + @overload + def __rmul__( + self: Index[T_COMPLEX], other: np_ndarray_bool | Index[bool] + ) -> Index[T_COMPLEX]: ... + @overload + def __rmul__( + self: Index[bool], other: np_ndarray_anyint | Index[int] + ) -> Index[int]: ... + @overload + def __rmul__( + self: Index[T_COMPLEX], other: np_ndarray_anyint | Index[int] + ) -> Index[T_COMPLEX]: ... + @overload + def __rmul__( + self: Index[bool] | Index[int], other: np_ndarray_float | Index[float] + ) -> Index[float]: ... + @overload + def __rmul__( + self: Index[T_COMPLEX], other: np_ndarray_float | Index[float] + ) -> Index[T_COMPLEX]: ... + @overload + def __rmul__( + self: Index[T_COMPLEX], other: np_ndarray_complex | Index[complex] + ) -> Index[complex]: ... def __floordiv__( self, other: float | Sequence[float] | Index[int] | Index[float] ) -> Self: ... diff --git a/pandas-stubs/core/indexes/datetimelike.pyi b/pandas-stubs/core/indexes/datetimelike.pyi index bf5556595..0c0087e6b 100644 --- a/pandas-stubs/core/indexes/datetimelike.pyi +++ b/pandas-stubs/core/indexes/datetimelike.pyi @@ -1,7 +1,9 @@ import numpy as np from pandas.core.indexes.extension import ExtensionIndex -from pandas.core.indexes.timedeltas import TimedeltaIndex -from typing_extensions import Self +from typing_extensions import ( + Never, + Self, +) from pandas._libs.tslibs import BaseOffset from pandas._typing import ( @@ -9,6 +11,7 @@ from pandas._typing import ( AxisIndex, GenericT_co, TimeUnit, + np_ndarray_complex, ) class DatetimeIndexOpsMixin(ExtensionIndex[S1, GenericT_co]): @@ -30,9 +33,12 @@ class DatetimeIndexOpsMixin(ExtensionIndex[S1, GenericT_co]): def argmax( self, axis: AxisIndex | None = None, skipna: bool = True, *args, **kwargs ) -> np.int64: ... - def __rsub__( # type: ignore[misc,override] # pyright: ignore[reportIncompatibleMethodOverride] - self, other: DatetimeIndexOpsMixin - ) -> TimedeltaIndex: ... + def __mul__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + self, other: np_ndarray_complex + ) -> Never: ... + def __rmul__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + self, other: np_ndarray_complex + ) -> Never: ... class DatetimeTimedeltaMixin(DatetimeIndexOpsMixin[S1, GenericT_co]): @property diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 12af992f7..16e1a8c22 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -62,20 +62,19 @@ class DatetimeIndex( # various ignores needed for mypy, as we do want to restrict what can be used in # arithmetic for these types def __add__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - self, other: timedelta | TimedeltaIndex | BaseOffset - ) -> DatetimeIndex: ... - def __radd__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - self, other: timedelta | TimedeltaIndex | BaseOffset - ) -> DatetimeIndex: ... + self, other: timedelta | BaseOffset + ) -> Self: ... + def __radd__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + self, other: timedelta | BaseOffset + ) -> Self: ... @overload # type: ignore[override] def __sub__( - self, - other: timedelta | np.timedelta64 | np_ndarray_td | TimedeltaIndex | BaseOffset, - ) -> DatetimeIndex: ... + self, other: datetime | np.datetime64 | np_ndarray_dt | Self + ) -> TimedeltaIndex: ... @overload def __sub__( # pyright: ignore[reportIncompatibleMethodOverride] - self, other: datetime | np.datetime64 | np_ndarray_dt | DatetimeIndex - ) -> TimedeltaIndex: ... + self, other: timedelta | np.timedelta64 | np_ndarray_td | BaseOffset + ) -> Self: ... @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 e87592dc8..b15b9afe1 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -27,6 +27,10 @@ from pandas._libs.tslibs import BaseOffset from pandas._typing import ( AxesData, TimedeltaConvertibleTypes, + np_ndarray_anyint, + np_ndarray_bool, + np_ndarray_dt, + np_ndarray_float, np_ndarray_td, num, ) @@ -64,9 +68,42 @@ class TimedeltaIndex( self, other: dt.timedelta | Self ) -> Self: ... def __sub__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] - self, other: dt.timedelta | np.timedelta64 | np_ndarray_td | Self + self, other: dt.timedelta | np.timedelta64 | np_ndarray_td | BaseOffset | Self + ) -> Self: ... + @overload # type: ignore[override] + def __rsub__( + self, other: dt.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 + ) -> DatetimeIndex: ... + def __mul__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + self, + other: ( # type: ignore[override] + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + ), + ) -> Self: ... + def __rmul__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + self, + other: ( # type: ignore[override] + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + ), ) -> Self: ... - def __mul__(self, other: float) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] @overload # type: ignore[override] def __truediv__(self, other: float | Sequence[float]) -> Self: ... @overload diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 123b3f286..20ebec471 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -36,7 +36,9 @@ from typing import ( from _typeshed import ( SupportsAdd, SupportsGetItem, + SupportsMul, SupportsRAdd, + SupportsRMul, ) from matplotlib.axes import ( Axes as PlotAxes, @@ -112,6 +114,7 @@ from pandas._libs.tslibs.offsets import DateOffset from pandas._typing import ( S1, S1_CO, + S1_CO_NSDT, S1_CT, S1_CT_NDT, S2, @@ -2543,85 +2546,114 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __mul__(self, other: Index[Never] | Series[Never]) -> Series: ... @overload - def __mul__( - self: Series[bool], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], - ) -> Series[T_COMPLEX]: ... + def __mul__(self, other: np_ndarray_dt) -> Never: ... @overload - def __mul__(self: Series[bool], other: np_ndarray_bool) -> Series[bool]: ... + def __mul__( + self: Series[bool] | Series[int] | Series[float], + other: ( + timedelta + | Sequence[timedelta] + | np.timedelta64 + | np_ndarray_td + | TimedeltaIndex + | Series[Timedelta] + ), + ) -> Series[Timedelta]: ... @overload - def __mul__(self: Series[bool], other: np_ndarray_anyint) -> Series[int]: ... + def __mul__(self: Series[Timestamp], other: np_ndarray) -> Never: ... @overload - def __mul__(self: Series[bool], other: np_ndarray_float) -> Series[float]: ... + def __mul__(self: Series[Timedelta], other: np_ndarray_complex) -> Never: ... @overload def __mul__( - self: Series[int], + self: Series[Timedelta], other: ( - bool - | Sequence[bool] + float + | Sequence[float] | np_ndarray_bool | np_ndarray_anyint + | np_ndarray_float | Index[bool] + | Index[int] + | Index[float] | Series[bool] + | Series[int] + | Series[float] ), - ) -> Series[int]: ... + ) -> Series[Timedelta]: ... @overload - def __mul__( - self: Series[int], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], - ) -> Series[T_COMPLEX]: ... + def __mul__(self: Series[T_INT], other: bool | Sequence[bool]) -> Series[T_INT]: ... @overload - def __mul__(self: Series[int], other: np_ndarray_float) -> Series[float]: ... + def __mul__(self: Series[float], other: int | Sequence[int]) -> Series[float]: ... @overload def __mul__( - self: Series[float], + self: Series[complex], other: float | Sequence[float] + ) -> Series[complex]: ... + @overload + def __mul__( + self: Series[S1_CT], other: ( - int - | Sequence[int] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[T_INT] - | Series[T_INT] + SupportsRMul[S1_CT, S1_CO_NSDT] | Sequence[SupportsRMul[S1_CT, S1_CO_NSDT]] ), - ) -> Series[float]: ... + ) -> Series[S1_CO_NSDT]: ... @overload def __mul__( - self: Series[float], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[T_COMPLEX], other: np_ndarray_bool | Index[bool] | Series[bool] ) -> Series[T_COMPLEX]: ... @overload def __mul__( - self: Series[complex], - other: ( - T_COMPLEX - | Sequence[T_COMPLEX] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[T_COMPLEX] - | Series[T_COMPLEX] - ), - ) -> Series[complex]: ... + self: Series[bool], other: np_ndarray_anyint | Index[int] | Series[int] + ) -> Series[int]: ... @overload def __mul__( - self: Series[T_COMPLEX], other: np_ndarray_complex - ) -> Series[complex]: ... + self: Series[T_COMPLEX], other: np_ndarray_anyint | Index[int] | Series[int] + ) -> Series[T_COMPLEX]: ... + @overload + def __mul__( + self: Series[bool] | Series[int], + other: np_ndarray_float | Index[float] | Series[float], + ) -> Series[float]: ... @overload def __mul__( + self: Series[T_COMPLEX], other: np_ndarray_float | Index[float] | Series[float] + ) -> Series[T_COMPLEX]: ... + @overload + def __mul__( + self: Series[T_COMPLEX], + other: np_ndarray_complex | Index[complex] | Series[complex], + ) -> Series[complex]: ... + @overload + def mul( + self: Series[Never], + other: complex | _ListLike | Index | Series, + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series: ... + @overload + def mul( + self, + other: Index[Never] | Series[Never], + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series: ... + @overload + def mul( self: Series[bool] | Series[int] | Series[float], other: ( timedelta + | Sequence[timedelta] | np.timedelta64 | np_ndarray_td | TimedeltaIndex | Series[Timedelta] ), + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... @overload - def __mul__(self: Series[Timedelta], other: np_ndarray_complex) -> Never: ... - @overload - def __mul__( + def mul( self: Series[Timedelta], other: ( float @@ -2636,136 +2668,102 @@ class Series(IndexOpsMixin[S1], NDFrame): | Series[int] | Series[float] ), + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... @overload def mul( - self: Series[Never], - other: complex | _ListLike | Index | Series, + self: Series[T_INT], + other: bool | Sequence[bool], level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series: ... + ) -> Series[T_INT]: ... @overload def mul( - self, - other: Index[Never] | Series[Never], + self: Series[float], + other: int | Sequence[int], level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series: ... + ) -> Series[float]: ... @overload def mul( - self: Series[bool], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[complex], + other: float | Sequence[float], level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series[T_COMPLEX]: ... + ) -> Series[complex]: ... @overload def mul( - self: Series[bool], - other: np_ndarray_bool, + self: Series[S1_CT], + other: ( + SupportsRMul[S1_CT, S1_CO_NSDT] | Sequence[SupportsRMul[S1_CT, S1_CO_NSDT]] + ), level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series[bool]: ... + ) -> Series[S1_CO_NSDT]: ... @overload def mul( - self: Series[bool], - other: np_ndarray_anyint, + self: Series[T_COMPLEX], + other: np_ndarray_bool | Index[bool] | Series[bool], level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series[int]: ... + ) -> Series[T_COMPLEX]: ... @overload def mul( self: Series[bool], - other: np_ndarray_float, - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, - ) -> Series[float]: ... - @overload - def mul( - self: Series[int], - other: ( - bool - | Sequence[bool] - | np_ndarray_bool - | np_ndarray_anyint - | Index[bool] - | Series[bool] - ), + other: np_ndarray_anyint | Index[int] | Series[int], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[int]: ... @overload def mul( - self: Series[int], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[T_COMPLEX], + other: np_ndarray_anyint | Index[int] | Series[int], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[T_COMPLEX]: ... @overload def mul( - self: Series[int], - other: np_ndarray_float, - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, - ) -> Series[float]: ... - @overload - def mul( - self: Series[float], - other: ( - int - | Sequence[int] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[T_INT] - | Series[T_INT] - ), + self: Series[bool] | Series[int], + other: np_ndarray_float | Index[float] | Series[float], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[float]: ... @overload def mul( - self: Series[float], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[T_COMPLEX], + other: np_ndarray_float | Index[float] | Series[float], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[T_COMPLEX]: ... @overload - def mul( - self: Series[complex], - other: ( - T_COMPLEX - | Sequence[T_COMPLEX] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[T_COMPLEX] - | Series[T_COMPLEX] - ), - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, - ) -> Series[complex]: ... - @overload def mul( self: Series[T_COMPLEX], - other: np_ndarray_complex, + other: np_ndarray_complex | Index[complex] | Series[complex], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[complex]: ... @overload - def mul( + def __rmul__( # type: ignore[overload-overlap] + self: Series[Never], other: complex | NumListLike | Index | Series + ) -> Series: ... + @overload + def __rmul__(self, other: Index[Never] | Series[Never]) -> Series: ... # type: ignore[misc] + @overload + def __rmul__(self, other: np_ndarray_dt) -> Never: ... + @overload + def __rmul__( self: Series[bool] | Series[int] | Series[float], other: ( timedelta @@ -2775,12 +2773,13 @@ class Series(IndexOpsMixin[S1], NDFrame): | TimedeltaIndex | Series[Timedelta] ), - level: Level | None = ..., - fill_value: float | None = None, - axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... @overload - def mul( + def __rmul__(self: Series[Timestamp], other: np_ndarray) -> Never: ... + @overload + def __rmul__(self: Series[Timedelta], other: np_ndarray_complex) -> Never: ... + @overload + def __rmul__( self: Series[Timedelta], other: ( float @@ -2795,96 +2794,83 @@ class Series(IndexOpsMixin[S1], NDFrame): | Series[int] | Series[float] ), - level: Level | None = ..., - fill_value: float | None = None, - axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... @overload - def __rmul__( # type: ignore[overload-overlap] - self: Series[Never], other: complex | NumListLike | Index | Series - ) -> Series: ... - @overload - def __rmul__(self, other: Index[Never] | Series[Never]) -> Series: ... - @overload def __rmul__( - self: Series[bool], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], - ) -> Series[T_COMPLEX]: ... - @overload - def __rmul__(self: Series[bool], other: np_ndarray_bool) -> Series[bool]: ... + self: Series[T_INT], other: bool | Sequence[bool] + ) -> Series[T_INT]: ... @overload - def __rmul__(self: Series[bool], other: np_ndarray_anyint) -> Series[int]: ... + def __rmul__(self: Series[float], other: int | Sequence[int]) -> Series[float]: ... @overload - def __rmul__(self: Series[bool], other: np_ndarray_float) -> Series[float]: ... + def __rmul__( + self: Series[complex], other: float | Sequence[float] + ) -> Series[complex]: ... @overload def __rmul__( - self: Series[int], + self: Series[S1_CT], other: ( - bool - | Sequence[bool] - | np_ndarray_bool - | np_ndarray_anyint - | Index[bool] - | Series[bool] + SupportsMul[S1_CT, S1_CO_NSDT] | Sequence[SupportsMul[S1_CT, S1_CO_NSDT]] ), - ) -> Series[int]: ... + ) -> Series[S1_CO_NSDT]: ... @overload def __rmul__( - self: Series[int], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[T_COMPLEX], other: np_ndarray_bool | Index[bool] | Series[bool] ) -> Series[T_COMPLEX]: ... @overload - def __rmul__(self: Series[int], other: np_ndarray_float) -> Series[float]: ... + def __rmul__( + self: Series[bool], other: np_ndarray_anyint | Index[int] | Series[int] + ) -> Series[int]: ... + @overload + def __rmul__( + self: Series[T_COMPLEX], other: np_ndarray_anyint | Index[int] | Series[int] + ) -> Series[T_COMPLEX]: ... @overload def __rmul__( - self: Series[float], - other: ( - int - | Sequence[int] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[T_INT] - | Series[T_INT] - ), + self: Series[bool] | Series[int], + other: np_ndarray_float | Index[float] | Series[float], ) -> Series[float]: ... @overload def __rmul__( - self: Series[float], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[T_COMPLEX], other: np_ndarray_float | Index[float] | Series[float] ) -> Series[T_COMPLEX]: ... @overload def __rmul__( - self: Series[complex], - other: ( - T_COMPLEX - | Sequence[T_COMPLEX] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[T_COMPLEX] - | Series[T_COMPLEX] - ), + self: Series[T_COMPLEX], + other: np_ndarray_complex | Index[complex] | Series[complex], ) -> Series[complex]: ... @overload - def __rmul__( - self: Series[T_COMPLEX], other: np_ndarray_complex - ) -> Series[complex]: ... + def rmul( + self: Series[Never], + other: complex | _ListLike | Index | Series, + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series: ... @overload - def __rmul__( + def rmul( + self, + other: Index[Never] | Series[Never], + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series: ... + @overload + def rmul( self: Series[bool] | Series[int] | Series[float], other: ( timedelta + | Sequence[timedelta] | np.timedelta64 | np_ndarray_td | TimedeltaIndex | Series[Timedelta] ), + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... @overload - def __rmul__(self: Series[Timedelta], other: np_ndarray_complex) -> Never: ... - @overload - def __rmul__( + def rmul( self: Series[Timedelta], other: ( float @@ -2899,169 +2885,92 @@ class Series(IndexOpsMixin[S1], NDFrame): | Series[int] | Series[float] ), + level: Level | None = ..., + fill_value: float | None = None, + axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... @overload def rmul( - self: Series[Never], - other: complex | _ListLike | Index | Series, + self: Series[T_INT], + other: bool | Sequence[bool], level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series: ... + ) -> Series[T_INT]: ... @overload def rmul( - self, - other: Index[Never] | Series[Never], + self: Series[float], + other: int | Sequence[int], level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series: ... + ) -> Series[float]: ... @overload def rmul( - self: Series[bool], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[complex], + other: float | Sequence[float], level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series[T_COMPLEX]: ... + ) -> Series[complex]: ... @overload def rmul( - self: Series[bool], - other: np_ndarray_bool, + self: Series[S1_CT], + other: ( + SupportsMul[S1_CT, S1_CO_NSDT] | Sequence[SupportsMul[S1_CT, S1_CO_NSDT]] + ), level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series[bool]: ... + ) -> Series[S1_CO_NSDT]: ... @overload def rmul( - self: Series[bool], - other: np_ndarray_anyint, + self: Series[T_COMPLEX], + other: np_ndarray_bool | Index[bool] | Series[bool], level: Level | None = None, fill_value: float | None = None, axis: int = 0, - ) -> Series[int]: ... + ) -> Series[T_COMPLEX]: ... @overload def rmul( self: Series[bool], - other: np_ndarray_float, - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, - ) -> Series[float]: ... - @overload - def rmul( - self: Series[int], - other: ( - bool - | Sequence[bool] - | np_ndarray_bool - | np_ndarray_anyint - | Index[bool] - | Series[bool] - ), + other: np_ndarray_anyint | Index[int] | Series[int], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[int]: ... @overload def rmul( - self: Series[int], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[T_COMPLEX], + other: np_ndarray_anyint | Index[int] | Series[int], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[T_COMPLEX]: ... @overload def rmul( - self: Series[int], - other: np_ndarray_float, - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, - ) -> Series[float]: ... - @overload - def rmul( - self: Series[float], - other: ( - int - | Sequence[int] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[T_INT] - | Series[T_INT] - ), + self: Series[bool] | Series[int], + other: np_ndarray_float | Index[float] | Series[float], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[float]: ... @overload def rmul( - self: Series[float], - other: T_COMPLEX | Sequence[T_COMPLEX] | Index[T_COMPLEX] | Series[T_COMPLEX], + self: Series[T_COMPLEX], + other: np_ndarray_float | Index[float] | Series[float], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[T_COMPLEX]: ... @overload - def rmul( - self: Series[complex], - other: ( - T_COMPLEX - | Sequence[T_COMPLEX] - | np_ndarray_bool - | np_ndarray_anyint - | np_ndarray_float - | Index[T_COMPLEX] - | Series[T_COMPLEX] - ), - level: Level | None = None, - fill_value: float | None = None, - axis: int = 0, - ) -> Series[complex]: ... - @overload def rmul( self: Series[T_COMPLEX], - other: np_ndarray_complex, + other: np_ndarray_complex | Index[complex] | Series[complex], level: Level | None = None, fill_value: float | None = None, axis: int = 0, ) -> Series[complex]: ... - @overload - def rmul( - self: Series[bool] | Series[int] | Series[float], - other: ( - timedelta - | Sequence[timedelta] - | np.timedelta64 - | np_ndarray_td - | TimedeltaIndex - | Series[Timedelta] - ), - level: Level | None = ..., - fill_value: float | None = None, - axis: AxisIndex | None = 0, - ) -> Series[Timedelta]: ... - @overload - def rmul( - self: Series[Timedelta], - 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[Timedelta]: ... def __mod__(self, other: num | _ListLike | Series[S1]) -> Series[S1]: ... def __ne__(self, other: object) -> Series[_bool]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] def __pow__(self, other: num | _ListLike | Series[S1]) -> Series[S1]: ... diff --git a/tests/indexes/arithmetic/bool/test_mul.py b/tests/indexes/arithmetic/bool/test_mul.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/indexes/arithmetic/complex/test_mul.py b/tests/indexes/arithmetic/complex/test_mul.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/indexes/arithmetic/datetime/__init__.py b/tests/indexes/arithmetic/datetime/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/indexes/arithmetic/float/test_mul.py b/tests/indexes/arithmetic/float/test_mul.py new file mode 100644 index 000000000..e3b4fa4e0 --- /dev/null +++ b/tests/indexes/arithmetic/float/test_mul.py @@ -0,0 +1,128 @@ +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 +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) + +left = pd.Index([1.0, 2.0, 3.0]) # left operand + + +def test_mul_py_scalar() -> None: + """Test pd.Index[float] * Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.TimedeltaIndex"), pd.TimedeltaIndex, timedelta) + + 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.TimedeltaIndex"), pd.TimedeltaIndex, timedelta) + + +def test_mul_py_sequence() -> 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, 9, d) for d in (27, 28, 29)] + d = [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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + + 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + + +def test_mul_numpy_array() -> 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-09-{d}") for d in (27, 28, 29)], 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) + check(assert_type(left * d, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rmul__` cannot override. At runtime, they return + # `Series` with the correct element type. + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, np.floating) + check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, np.floating) + check(assert_type(f * left, "npt.NDArray[np.float64]"), pd.Index, np.floating) + check( + assert_type(c * left, "npt.NDArray[np.complex128]"), + pd.Index, + np.complexfloating, + ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s * left, Any) + check( + assert_type(d * left, "npt.NDArray[np.timedelta64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) + + +def test_mul_pd_index() -> 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, 9, 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) + check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + 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: + _15 = 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_mul.py b/tests/indexes/arithmetic/int/test_mul.py new file mode 100644 index 000000000..1f0a395c7 --- /dev/null +++ b/tests/indexes/arithmetic/int/test_mul.py @@ -0,0 +1,126 @@ +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 +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) + +left = pd.Index([1, 2, 3]) # left operand + + +def test_mul_py_scalar() -> 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) + check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, pd.TimedeltaIndex), pd.Index, pd.Timedelta) + + 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) + check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, pd.TimedeltaIndex), pd.Index, pd.Timedelta) + + +def test_mul_py_sequence() -> 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, 9, d) for d in (27, 28, 29)] + d = [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) + check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # pandas-dev/pandas#62524 + check(assert_type(left * d, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + + 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) + check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # pandas-dev/pandas#62524 + check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + + +def test_mul_numpy_array() -> None: + """Test pd.Index[int] * 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-09-{d}") for d in (27, 28, 29)], 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) + check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left * s, Never) + check(assert_type(left * d, pd.TimedeltaIndex), pd.Index, pd.Timedelta) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rmul__` cannot override. At runtime, they return + # `Series` with the correct element type. + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, np.integer) + check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, np.integer) + check(assert_type(f * left, "npt.NDArray[np.float64]"), pd.Index, np.floating) + check( + assert_type(c * left, "npt.NDArray[np.complex128]"), + pd.Index, + np.complexfloating, + ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s * left, Any) + check(assert_type(d * left, "npt.NDArray[np.timedelta64]"), pd.Index, pd.Timedelta) + + +def test_mul_pd_index() -> None: + """Test pd.Index[int] * 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, 9, 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) + check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, pd.TimedeltaIndex), pd.Index, pd.Timedelta) + + 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) + check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, pd.TimedeltaIndex), pd.Index, pd.Timedelta) diff --git a/tests/indexes/arithmetic/test_mul.py b/tests/indexes/arithmetic/test_mul.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/indexes/arithmetic/timedelta/__init__.py b/tests/indexes/arithmetic/timedelta/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/indexes/arithmetic/timedelta/test_mul.py b/tests/indexes/arithmetic/timedelta/test_mul.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/scalars/test_scalars.py b/tests/scalars/test_scalars.py index 54fcb08c5..75332fdb0 100644 --- a/tests/scalars/test_scalars.py +++ b/tests/scalars/test_scalars.py @@ -519,7 +519,6 @@ def test_timedelta_add_sub() -> None: as_dt_timedelta = dt.timedelta(days=1) as_timedelta64 = np.timedelta64(1, "D") as_timedelta_index = pd.TimedeltaIndex([td]) - as_timedelta_series = pd.Series(as_timedelta_index) as_period_index = pd.period_range("2012-01-01", periods=3, freq="D") as_datetime_index = pd.date_range("2012-01-01", periods=3) as_ndarray_td64 = ndarray_td64 @@ -535,11 +534,6 @@ def test_timedelta_add_sub() -> None: check(assert_type(td + as_dt_timedelta, pd.Timedelta), pd.Timedelta) check(assert_type(td + as_timedelta64, pd.Timedelta), pd.Timedelta) check(assert_type(td + as_timedelta_index, pd.TimedeltaIndex), pd.TimedeltaIndex) - check( - assert_type(td + as_timedelta_series, "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) check(assert_type(td + as_period_index, pd.PeriodIndex), pd.PeriodIndex) check(assert_type(td + as_datetime_index, pd.DatetimeIndex), pd.DatetimeIndex) check( @@ -577,11 +571,6 @@ def test_timedelta_add_sub() -> None: pd.Timedelta, ) check(assert_type(as_timedelta_index + td, pd.TimedeltaIndex), pd.TimedeltaIndex) - check( - assert_type(as_timedelta_series + td, "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) check(assert_type(as_period_index + td, pd.PeriodIndex), pd.PeriodIndex) check(assert_type(as_datetime_index + td, pd.DatetimeIndex), pd.DatetimeIndex) check( @@ -612,11 +601,6 @@ def test_timedelta_add_sub() -> None: check(assert_type(td - as_dt_timedelta, pd.Timedelta), pd.Timedelta) check(assert_type(td - as_timedelta64, pd.Timedelta), pd.Timedelta) check(assert_type(td - as_timedelta_index, pd.TimedeltaIndex), pd.TimedeltaIndex) - check( - assert_type(td - as_timedelta_series, "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) check( assert_type(td - as_ndarray_td64, npt.NDArray[np.timedelta64]), np.ndarray, @@ -646,11 +630,6 @@ def test_timedelta_add_sub() -> None: pd.Timedelta, ) check(assert_type(as_timedelta_index - td, pd.TimedeltaIndex), pd.TimedeltaIndex) - check( - assert_type(as_timedelta_series - td, "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) check(assert_type(as_period_index - td, pd.PeriodIndex), pd.PeriodIndex) check(assert_type(as_datetime_index - td, pd.DatetimeIndex), pd.DatetimeIndex) check( @@ -703,18 +682,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(md_int * td, pd.Timedelta), pd.Timedelta) check(assert_type(md_float * td, pd.Timedelta), pd.Timedelta) @@ -728,18 +695,6 @@ def test_timedelta_mul_div() -> None: np.ndarray, np.timedelta64, ) - check( - assert_type(mp_series_int * td, "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) - check( - assert_type(md_series_float * td, "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) - check(assert_type(md_int64_index * td, pd.TimedeltaIndex), pd.TimedeltaIndex) - check(assert_type(md_float_index * td, pd.TimedeltaIndex), pd.TimedeltaIndex) check(assert_type(td // td, int), int) check(assert_type(td // pd.NaT, float), float) diff --git a/tests/series/arithmetic/float/test_mul.py b/tests/series/arithmetic/float/test_mul.py index f4afe08d2..d9d3c71f4 100644 --- a/tests/series/arithmetic/float/test_mul.py +++ b/tests/series/arithmetic/float/test_mul.py @@ -1,9 +1,21 @@ +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 -from typing_extensions import assert_type +from typing_extensions import ( + Never, + assert_type, +) -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) left = pd.Series([1.0, 2.0, 3.0]) # left operand @@ -11,21 +23,31 @@ def test_mul_py_scalar() -> None: """Test pd.Series[float] * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 30), 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rmul(i), "pd.Series[float]"), pd.Series, np.floating) @@ -33,26 +55,40 @@ def test_mul_py_scalar() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) def test_mul_py_sequence() -> 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, 9, d) for d in (27, 28, 29)] + d = [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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rmul(i), "pd.Series[float]"), pd.Series, np.floating) @@ -60,6 +96,9 @@ def test_mul_py_sequence() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) def test_mul_numpy_array() -> None: @@ -68,11 +107,16 @@ def test_mul_numpy_array() -> 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-09-{d}") for d in (27, 28, 29)], 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) + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return @@ -85,11 +129,17 @@ def test_mul_numpy_array() -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s * left, Any) + check(assert_type(d * left, "npt.NDArray[np.timedelta64]"), pd.Series, pd.Timedelta) check(assert_type(left.mul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rmul(i), "pd.Series[float]"), pd.Series, np.floating) @@ -97,6 +147,9 @@ def test_mul_numpy_array() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_mul_pd_index() -> None: @@ -105,21 +158,32 @@ def test_mul_pd_index() -> 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, 9, 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.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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) 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: + _15 = 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.mul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rmul(i), "pd.Series[float]"), pd.Series, np.floating) @@ -127,6 +191,9 @@ def test_mul_pd_index() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_mul_pd_series() -> None: @@ -135,21 +202,32 @@ def test_mul_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, 9, d) for d in (27, 28, 29)]) + 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) 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: + _15 = 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.mul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(i), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.rmul(i), "pd.Series[float]"), pd.Series, np.floating) @@ -157,3 +235,6 @@ def test_mul_pd_series() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) diff --git a/tests/series/arithmetic/int/test_mul.py b/tests/series/arithmetic/int/test_mul.py index b15d91256..548b9ade1 100644 --- a/tests/series/arithmetic/int/test_mul.py +++ b/tests/series/arithmetic/int/test_mul.py @@ -1,9 +1,21 @@ +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 -from typing_extensions import assert_type +from typing_extensions import ( + Never, + assert_type, +) -from tests import check +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) left = pd.Series([1, 2, 3]) # left operand @@ -11,21 +23,31 @@ def test_mul_py_scalar() -> 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[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) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) 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) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = 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.mul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -33,26 +55,40 @@ def test_mul_py_scalar() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_mul_py_sequence() -> 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, 9, d) for d in (27, 28, 29)] + d = [timedelta(seconds=s + 1) for s in range(3)] 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) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) 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) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -60,6 +96,9 @@ def test_mul_py_sequence() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) def test_mul_numpy_array() -> None: @@ -68,11 +107,16 @@ def test_mul_numpy_array() -> 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-09-{d}") for d in (27, 28, 29)], np.datetime64) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) 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) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left * s, Never) + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return @@ -85,11 +129,17 @@ def test_mul_numpy_array() -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s * left, Any) + check(assert_type(d * left, "npt.NDArray[np.timedelta64]"), pd.Series, pd.Timedelta) check(assert_type(left.mul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -97,6 +147,9 @@ def test_mul_numpy_array() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_mul_pd_index() -> None: @@ -105,21 +158,32 @@ def test_mul_pd_index() -> 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, 9, 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.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) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) 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) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = 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.mul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -127,6 +191,9 @@ def test_mul_pd_index() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_mul_pd_series() -> None: @@ -135,21 +202,32 @@ def test_mul_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, 9, d) for d in (27, 28, 29)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) 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) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) 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) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = 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.mul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -157,3 +235,6 @@ def test_mul_pd_series() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) diff --git a/tests/series/arithmetic/test_mul.py b/tests/series/arithmetic/test_mul.py index f89633416..e95b4e02b 100644 --- a/tests/series/arithmetic/test_mul.py +++ b/tests/series/arithmetic/test_mul.py @@ -179,5 +179,5 @@ def test_mul_str_py_str() -> None: if TYPE_CHECKING_INVALID_USAGE: left_i * s # type: ignore[operator] # pyright:ignore[reportOperatorIssue] s * left_i # type: ignore[operator] # pyright:ignore[reportOperatorIssue] - left_i.mul(s) # type: ignore[type-var] # pyright: ignore[reportArgumentType,reportCallIssue] - left_i.rmul(s) # type: ignore[type-var] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left_i.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] diff --git a/tests/series/arithmetic/timedelta/test_mul.py b/tests/series/arithmetic/timedelta/test_mul.py index 8f83ca19e..107886c86 100644 --- a/tests/series/arithmetic/timedelta/test_mul.py +++ b/tests/series/arithmetic/timedelta/test_mul.py @@ -41,7 +41,7 @@ def test_mul_py_scalar() -> None: check(assert_type(left.mul(i), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.mul(f), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - left.mul(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] if PD_LTE_23: check( @@ -52,7 +52,7 @@ def test_mul_py_scalar() -> None: check(assert_type(left.rmul(i), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(f), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - left.rmul(c) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] def test_mul_py_sequence() -> None: diff --git a/tests/series/test_series.py b/tests/series/test_series.py index 9079708c1..f473abfe4 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -3282,30 +3282,6 @@ def test_series_mapping() -> None: ) -def test_timedeltaseries_operators() -> None: - series = pd.Series([pd.Timedelta(days=1)]) - check( - assert_type(series + datetime.datetime.now(), "pd.Series[pd.Timestamp]"), - pd.Series, - pd.Timestamp, - ) - check( - assert_type(series + datetime.timedelta(1), "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) - check( - assert_type(datetime.datetime.now() + series, "pd.Series[pd.Timestamp]"), - pd.Series, - pd.Timestamp, - ) - check( - assert_type(series - datetime.timedelta(1), "pd.Series[pd.Timedelta]"), - pd.Series, - pd.Timedelta, - ) - - def test_timestamp_series() -> None: series = pd.Series([pd.Timestamp(2024, 4, 4)]) check( diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 2fdf6a138..8e7395e6d 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -1,9 +1,6 @@ from __future__ import annotations import datetime as dt -from typing import ( - Optional, -) from dateutil.relativedelta import ( FR, @@ -154,7 +151,7 @@ def test_timedelta_arithmetic() -> None: check(assert_type(td3 / 10.2, pd.Timedelta), pd.Timedelta) -def test_timedelta_series_arithmetic() -> None: +def test_timedelta_index_arithmetic() -> None: tds1 = pd.to_timedelta([2, 3], "minutes") td1 = pd.Timedelta("2 days") check(assert_type(tds1, pd.TimedeltaIndex), pd.TimedeltaIndex) @@ -170,7 +167,7 @@ def test_timedelta_float_value() -> None: check(assert_type(pd.Timedelta(1.5, "h"), pd.Timedelta), pd.Timedelta) -def test_timedelta_series_string() -> None: +def test_timedelta_index_string() -> None: seq_list = ["1 day"] check(assert_type(pd.to_timedelta(seq_list), pd.TimedeltaIndex), pd.TimedeltaIndex) @@ -198,19 +195,6 @@ def test_datetimeindex_plus_timedelta() -> None: pd.Timestamp, ) dti = pd.to_datetime(["2022-03-08", "2022-03-15"]) - td_s = pd.to_timedelta(pd.Series([10, 20]), "minutes") - dti_td_s = dti + td_s - check( - assert_type(dti_td_s, "pd.Series[pd.Timestamp]"), - pd.Series, - pd.Timestamp, - ) - td_dti_s = td_s + dti - check( - assert_type(td_dti_s, "pd.Series[pd.Timestamp]"), - pd.Series, - pd.Timestamp, - ) tdi = pd.to_timedelta([10, 20], "minutes") dti_tdi_dti = dti + tdi check(assert_type(dti_tdi_dti, "pd.DatetimeIndex"), pd.DatetimeIndex) @@ -233,13 +217,6 @@ def test_datetimeindex_minus_timedelta() -> None: pd.Timestamp, ) dti = pd.to_datetime(["2022-03-08", "2022-03-15"]) - td_s = pd.to_timedelta(pd.Series([10, 20]), "minutes") - dti_td_s = dti - td_s - check( - assert_type(dti_td_s, "pd.Series[pd.Timestamp]"), - pd.Series, - pd.Timestamp, - ) tdi = pd.to_timedelta([10, 20], "minutes") dti_tdi_dti = dti - tdi check(assert_type(dti_tdi_dti, "pd.DatetimeIndex"), pd.DatetimeIndex) @@ -249,7 +226,7 @@ def test_datetimeindex_minus_timedelta() -> None: check(assert_type(dti_ts_tdi, pd.TimedeltaIndex), pd.TimedeltaIndex) -def test_timestamp_plus_timedelta_series() -> None: +def test_timestamp_series_construction() -> None: check( assert_type( pd.Series([pd.Timestamp("2022-03-05"), pd.Timestamp("2022-03-06")]), @@ -258,18 +235,6 @@ def test_timestamp_plus_timedelta_series() -> None: pd.Series, pd.Timestamp, ) - ts = pd.Timestamp("2022-03-05") - td = pd.to_timedelta(pd.Series([10, 20]), "minutes") - r3 = td + ts - check(assert_type(r3, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) - r4 = ts + td - check(assert_type(r4, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp) - - -def test_timedelta_series_mult() -> None: - df = pd.DataFrame({"x": [1, 3, 5], "y": [2, 2, 6]}) - std = (df["x"] < df["y"]) * pd.Timedelta(10, "minutes") - check(assert_type(std, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) def test_timedelta_series_sum() -> None: @@ -289,19 +254,10 @@ def test_iso_calendar() -> None: check(assert_type(dates.isocalendar(), pd.DataFrame), pd.DataFrame) -def test_fail_on_adding_two_timestamps() -> None: - s1 = pd.Series(pd.to_datetime(["2022-05-01", "2022-06-01"])) - s2 = pd.Series(pd.to_datetime(["2022-05-15", "2022-06-15"])) - if TYPE_CHECKING_INVALID_USAGE: - ssum = s1 + s2 # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - ts = pd.Timestamp("2022-06-30") - tsum = s1 + ts # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - - def test_dtindex_tzinfo() -> None: # GH 71 dti = pd.date_range("2000-1-1", periods=10) - check(assert_type(dti.tzinfo, Optional[dt.tzinfo]), type(None)) + check(assert_type(dti.tzinfo, dt.tzinfo | None), type(None)) def test_todatetime_fromnumpy() -> None: @@ -376,8 +332,8 @@ def test_series_dt_accessors() -> None: check(assert_type(s0.dt.is_leap_year, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(s0.dt.daysinmonth, "pd.Series[int]"), pd.Series, np.integer) check(assert_type(s0.dt.days_in_month, "pd.Series[int]"), pd.Series, np.integer) - check(assert_type(s0.dt.tz, Optional[dt.tzinfo]), type(None)) - check(assert_type(s0.dt.freq, Optional[str]), str) + check(assert_type(s0.dt.tz, dt.tzinfo | None), type(None)) + check(assert_type(s0.dt.freq, str | None), str) check(assert_type(s0.dt.isocalendar(), pd.DataFrame), pd.DataFrame) check( assert_type(s0.dt.to_period("D"), "pd.Series[pd.Period]"), pd.Series, pd.Period @@ -448,8 +404,8 @@ def test_series_dt_accessors() -> None: pd.Series, pd.Timestamp, ) - check(assert_type(s0.dt.tz, Optional[dt.tzinfo]), type(None)) - check(assert_type(s0_local.dt.tz, Optional[dt.tzinfo]), dt.tzinfo) + check(assert_type(s0.dt.tz, dt.tzinfo | None), type(None)) + check(assert_type(s0_local.dt.tz, dt.tzinfo | None), dt.tzinfo) check( assert_type(s0.dt.normalize(), "pd.Series[pd.Timestamp]"), pd.Series, @@ -676,8 +632,8 @@ def test_datetimeindex_accessors() -> None: check(assert_type(i0.is_leap_year, np_1darray[np.bool]), np_1darray[np.bool]) check(assert_type(i0.daysinmonth, "pd.Index[int]"), pd.Index, np.int32) check(assert_type(i0.days_in_month, "pd.Index[int]"), pd.Index, np.int32) - check(assert_type(i0.tz, Optional[dt.tzinfo]), type(None)) - check(assert_type(i0.freq, Optional[BaseOffset]), BaseOffset) + check(assert_type(i0.tz, dt.tzinfo | None), type(None)) + check(assert_type(i0.freq, BaseOffset | None), BaseOffset) check(assert_type(i0.isocalendar(), pd.DataFrame), pd.DataFrame) check(assert_type(i0.to_period("D"), pd.PeriodIndex), pd.PeriodIndex, pd.Period) check( @@ -698,7 +654,7 @@ def test_datetimeindex_accessors() -> None: assert_type(ilocal.tz_convert(pytz.timezone("US/Pacific")), pd.DatetimeIndex), pd.DatetimeIndex, ) - check(assert_type(ilocal.tz, Optional[dt.tzinfo]), dt.tzinfo) + check(assert_type(ilocal.tz, dt.tzinfo | None), dt.tzinfo) check(assert_type(i0.normalize(), pd.DatetimeIndex), pd.DatetimeIndex, pd.Timestamp) check(assert_type(i0.strftime("%Y"), pd.Index), pd.Index, str) check(assert_type(i0.round("D"), pd.DatetimeIndex), pd.DatetimeIndex, pd.Timestamp) @@ -763,7 +719,7 @@ def test_periodindex_accessors() -> None: check(assert_type(i0.quarter, "pd.Index[int]"), pd.Index, np.integer) check(assert_type(i0.daysinmonth, "pd.Index[int]"), pd.Index, np.integer) check(assert_type(i0.days_in_month, "pd.Index[int]"), pd.Index, np.integer) - check(assert_type(i0.freq, Optional[BaseOffset]), BaseOffset) + check(assert_type(i0.freq, BaseOffset | None), BaseOffset) check(assert_type(i0.strftime("%Y"), pd.Index), pd.Index, str) check(assert_type(i0.asfreq("D"), pd.PeriodIndex), pd.PeriodIndex, pd.Period) check(assert_type(i0.end_time, pd.DatetimeIndex), pd.DatetimeIndex, pd.Timestamp) From 8d2a17f93b911370bede7533f3a2a9b7457b6365 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 1 Oct 2025 22:16:01 +0200 Subject: [PATCH 02/15] feat: mul for timedelta indexes --- pandas-stubs/core/indexes/base.pyi | 32 +++++ pandas-stubs/core/indexes/timedeltas.pyi | 20 ++- tests/indexes/arithmetic/float/test_mul.py | 16 ++- tests/indexes/arithmetic/int/test_mul.py | 16 ++- .../indexes/arithmetic/timedelta/test_mul.py | 114 +++++++++++++++++ tests/indexes/timedeltaindex/__init__.py | 0 tests/indexes/timedeltaindex/test_mul.py | 121 ++++++++++++++++++ tests/series/arithmetic/float/test_mul.py | 18 ++- tests/series/arithmetic/int/test_mul.py | 18 ++- tests/series/arithmetic/timedelta/test_mul.py | 18 ++- 10 files changed, 340 insertions(+), 33 deletions(-) create mode 100644 tests/indexes/timedeltaindex/__init__.py create mode 100644 tests/indexes/timedeltaindex/test_mul.py diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 4273d66db..c8fc72b1f 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -763,6 +763,22 @@ class Index(IndexOpsMixin[S1]): other: timedelta | Sequence[Timedelta] | np.timedelta64 | np_ndarray_td, ) -> TimedeltaIndex: ... @overload + def __mul__(self: Index[Timedelta], other: np_ndarray_complex) -> Never: ... + @overload + def __mul__( + self: Index[Timedelta], + other: ( + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + ), + ) -> Index[Timedelta]: ... + @overload def __mul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... @overload def __mul__(self: Index[float], other: int | Sequence[int]) -> Index[float]: ... @@ -818,6 +834,22 @@ class Index(IndexOpsMixin[S1]): other: timedelta | Sequence[Timedelta] | np.timedelta64 | np_ndarray_td, ) -> TimedeltaIndex: ... @overload + def __rmul__(self: Index[Timedelta], other: np_ndarray_complex) -> Never: ... + @overload + def __rmul__( + self: Index[Timedelta], + other: ( + float + | Sequence[float] + | np_ndarray_bool + | np_ndarray_anyint + | np_ndarray_float + | Index[bool] + | Index[int] + | Index[float] + ), + ) -> Index[Timedelta]: ... + @overload def __rmul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... @overload def __rmul__(self: Index[float], other: int | Sequence[int]) -> Index[float]: ... diff --git a/pandas-stubs/core/indexes/timedeltas.pyi b/pandas-stubs/core/indexes/timedeltas.pyi index b15b9afe1..5b0915c6b 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -20,7 +20,10 @@ from pandas.core.indexes.datetimelike import DatetimeTimedeltaMixin from pandas.core.indexes.datetimes import DatetimeIndex from pandas.core.indexes.period import PeriodIndex from pandas.core.series import Series -from typing_extensions import Self +from typing_extensions import ( + Never, + Self, +) from pandas._libs import Timedelta from pandas._libs.tslibs import BaseOffset @@ -29,6 +32,7 @@ from pandas._typing import ( TimedeltaConvertibleTypes, np_ndarray_anyint, np_ndarray_bool, + np_ndarray_complex, np_ndarray_dt, np_ndarray_float, np_ndarray_td, @@ -78,9 +82,12 @@ class TimedeltaIndex( def __rsub__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: dt.datetime | np.datetime64 | np_ndarray_dt | DatetimeIndex ) -> DatetimeIndex: ... - def __mul__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @overload # type: ignore[override] + def __mul__(self, other: np_ndarray_complex) -> Never: ... + @overload + def __mul__( self, - other: ( # type: ignore[override] + other: ( float | Sequence[float] | np_ndarray_bool @@ -91,9 +98,12 @@ class TimedeltaIndex( | Index[float] ), ) -> Self: ... - def __rmul__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + @overload # type: ignore[override] + def __rmul__(self, other: np_ndarray_complex) -> Never: ... + @overload + def __rmul__( self, - other: ( # type: ignore[override] + other: ( float | Sequence[float] | np_ndarray_bool diff --git a/tests/indexes/arithmetic/float/test_mul.py b/tests/indexes/arithmetic/float/test_mul.py index e3b4fa4e0..8d1e383c4 100644 --- a/tests/indexes/arithmetic/float/test_mul.py +++ b/tests/indexes/arithmetic/float/test_mul.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.Index([1.0, 2.0, 3.0]) # left operand +@pytest.fixture +def left() -> "pd.Index[float]": + """left operand""" + lo = pd.Index([1.0, 2.0, 3.0]) + return check(assert_type(lo, "pd.Index[float]"), pd.Index, np.floating) -def test_mul_py_scalar() -> None: + +def test_mul_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, 30), timedelta(seconds=1) @@ -42,7 +48,7 @@ def test_mul_py_scalar() -> None: check(assert_type(d * left, "pd.TimedeltaIndex"), pd.TimedeltaIndex, timedelta) -def test_mul_py_sequence() -> None: +def test_mul_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, 9, d) for d in (27, 28, 29)] @@ -65,7 +71,7 @@ def test_mul_py_sequence() -> None: check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) -def test_mul_numpy_array() -> None: +def test_mul_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) @@ -102,7 +108,7 @@ def test_mul_numpy_array() -> None: ) -def test_mul_pd_index() -> None: +def test_mul_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]) diff --git a/tests/indexes/arithmetic/int/test_mul.py b/tests/indexes/arithmetic/int/test_mul.py index 1f0a395c7..021fd4ca4 100644 --- a/tests/indexes/arithmetic/int/test_mul.py +++ b/tests/indexes/arithmetic/int/test_mul.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.Index([1, 2, 3]) # left operand +@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_mul_py_scalar() -> None: + +def test_mul_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) @@ -42,7 +48,7 @@ def test_mul_py_scalar() -> None: check(assert_type(d * left, pd.TimedeltaIndex), pd.Index, pd.Timedelta) -def test_mul_py_sequence() -> None: +def test_mul_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, 9, d) for d in (27, 28, 29)] @@ -67,7 +73,7 @@ def test_mul_py_sequence() -> None: check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) -def test_mul_numpy_array() -> None: +def test_mul_numpy_array(left: "pd.Index[int]") -> None: """Test pd.Index[int] * numpy arrays""" b = np.array([True, False, True], np.bool_) i = np.array([2, 3, 5], np.int64) @@ -100,7 +106,7 @@ def test_mul_numpy_array() -> None: check(assert_type(d * left, "npt.NDArray[np.timedelta64]"), pd.Index, pd.Timedelta) -def test_mul_pd_index() -> None: +def test_mul_pd_index(left: "pd.Index[int]") -> None: """Test pd.Index[int] * pandas Indexes""" b = pd.Index([True, False, True]) i = pd.Index([2, 3, 5]) diff --git a/tests/indexes/arithmetic/timedelta/test_mul.py b/tests/indexes/arithmetic/timedelta/test_mul.py index e69de29bb..9d912f4e2 100644 --- a/tests/indexes/arithmetic/timedelta/test_mul.py +++ b/tests/indexes/arithmetic/timedelta/test_mul.py @@ -0,0 +1,114 @@ +from datetime import timedelta + +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 ( + PD_LTE_23, + TYPE_CHECKING_INVALID_USAGE, + check, +) + + +@pytest.fixture +def left() -> "pd.Index[pd.Timedelta]": + """left operand""" + # pandas-dev/pandas#62524 + lo = pd.Index([1]) * [timedelta(seconds=1)] # left operand + return check(assert_type(lo, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + + +def test_mul_py_scalar(left: "pd.Index[pd.Timedelta]") -> None: + """Test pd.Series[pd.Timedelta] * Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + + # pandas-dev/pandas#62316 + if PD_LTE_23: + check(assert_type(left * b, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(left * i, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(left * f, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _0 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + if PD_LTE_23: + check(assert_type(b * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(i * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(f * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _1 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_mul_py_sequence(left: "pd.Index[pd.Timedelta]") -> None: + """Test pd.Series[pd.Timedelta] * Python native sequences""" + b, i, f, c = [True], [2], [1.5], [1.7j] + + # pandas-dev/pandas#62316 + if PD_LTE_23: + check(assert_type(left * b, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(left * i, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(left * f, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _0 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + if PD_LTE_23: + check(assert_type(b * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(i * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(f * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _1 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_mul_numpy_array(left: "pd.Index[pd.Timedelta]") -> None: + """Test pd.Series[pd.Timedelta] * 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) + + # pandas-dev/pandas#62316 + if PD_LTE_23: + check(assert_type(left * b, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(left * i, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(left * f, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left * c, Never) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rmul__` cannot override. At runtime, they return + # `Series` with the correct element type. + if PD_LTE_23: + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, timedelta) + check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, timedelta) + check(assert_type(f * left, "npt.NDArray[np.float64]"), pd.Index, timedelta) + if TYPE_CHECKING_INVALID_USAGE: + # We made it Never, but numpy takes over + assert_type(c * left, "npt.NDArray[np.complex128]") + + +def test_mul_pd_index(left: "pd.Index[pd.Timedelta]") -> None: + """Test pd.Series[pd.Timedelta] * pandas Indexes""" + b = pd.Index([True]) + i = pd.Index([2]) + f = pd.Index([1.5]) + c = pd.Index([1.7j]) + + # pandas-dev/pandas#62316 + if PD_LTE_23: + check(assert_type(left * b, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(left * i, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(left * f, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _0 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + if PD_LTE_23: + check(assert_type(b * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(i * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + check(assert_type(f * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _1 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] diff --git a/tests/indexes/timedeltaindex/__init__.py b/tests/indexes/timedeltaindex/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/indexes/timedeltaindex/test_mul.py b/tests/indexes/timedeltaindex/test_mul.py new file mode 100644 index 000000000..fec362fc2 --- /dev/null +++ b/tests/indexes/timedeltaindex/test_mul.py @@ -0,0 +1,121 @@ +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 ( + PD_LTE_23, + TYPE_CHECKING_INVALID_USAGE, + check, +) + + +@pytest.fixture +def left() -> pd.TimedeltaIndex: + """left operand""" + lo = pd.Index([pd.Timedelta(1, "s")]) # left operand + return check(assert_type(lo, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + +def test_mul_py_scalar(left: pd.TimedeltaIndex) -> None: + """Test pd.Series[pd.Timedelta] * Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + + # pandas-dev/pandas#62316 + if PD_LTE_23: + check(assert_type(left * b, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + 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: + _0 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + if PD_LTE_23: + check(assert_type(b * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(i * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(f * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _1 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_mul_py_sequence(left: pd.TimedeltaIndex) -> None: + """Test pd.Series[pd.Timedelta] * Python native sequences""" + b, i, f, c = [True], [2], [1.5], [1.7j] + + # pandas-dev/pandas#62316 + if PD_LTE_23: + check(assert_type(left * b, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + 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: + _0 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + if PD_LTE_23: + check(assert_type(b * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(i * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(f * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _1 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_mul_numpy_array(left: pd.TimedeltaIndex) -> None: + """Test pd.Series[pd.Timedelta] * 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) + + # pandas-dev/pandas#62316 + if PD_LTE_23: + check(assert_type(left * b, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + 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) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rmul__` cannot override. At runtime, they return + # `Series` with the correct element type. + if PD_LTE_23: + check( + assert_type(b * left, "npt.NDArray[np.bool_]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) + check( + assert_type(i * left, "npt.NDArray[np.int64]"), pd.TimedeltaIndex, pd.Timedelta + ) + check( + assert_type(f * left, "npt.NDArray[np.float64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) + if TYPE_CHECKING_INVALID_USAGE: + # We made it Never, but numpy takes over + assert_type(c * left, "npt.NDArray[np.complex128]") + + +def test_mul_pd_index(left: pd.TimedeltaIndex) -> None: + """Test pd.Series[pd.Timedelta] * pandas Indexes""" + b = pd.Index([True]) + i = pd.Index([2]) + f = pd.Index([1.5]) + c = pd.Index([1.7j]) + + # pandas-dev/pandas#62316 + if PD_LTE_23: + check(assert_type(left * b, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + 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: + _0 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + if PD_LTE_23: + check(assert_type(b * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(i * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + check(assert_type(f * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + _1 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] diff --git a/tests/series/arithmetic/float/test_mul.py b/tests/series/arithmetic/float/test_mul.py index d9d3c71f4..ae6ceb1bb 100644 --- a/tests/series/arithmetic/float/test_mul.py +++ b/tests/series/arithmetic/float/test_mul.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([1.0, 2.0, 3.0]) # left operand +@pytest.fixture +def left() -> "pd.Series[float]": + """left operand""" + lo = pd.Series([1.0, 2.0, 3.0]) + return check(assert_type(lo, "pd.Series[float]"), pd.Series, np.floating) -def test_mul_py_scalar() -> None: + +def test_mul_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, 30), timedelta(seconds=1) @@ -60,7 +66,7 @@ def test_mul_py_scalar() -> None: check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) -def test_mul_py_sequence() -> None: +def test_mul_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, 9, d) for d in (27, 28, 29)] @@ -101,7 +107,7 @@ def test_mul_py_sequence() -> None: check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) -def test_mul_numpy_array() -> None: +def test_mul_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) @@ -152,7 +158,7 @@ def test_mul_numpy_array() -> None: check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_mul_pd_index() -> None: +def test_mul_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]) @@ -196,7 +202,7 @@ def test_mul_pd_index() -> None: check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_mul_pd_series() -> None: +def test_mul_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]) diff --git a/tests/series/arithmetic/int/test_mul.py b/tests/series/arithmetic/int/test_mul.py index 548b9ade1..a2b48d8f4 100644 --- a/tests/series/arithmetic/int/test_mul.py +++ b/tests/series/arithmetic/int/test_mul.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([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_mul_py_scalar() -> None: + +def test_mul_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) @@ -60,7 +66,7 @@ def test_mul_py_scalar() -> None: check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_mul_py_sequence() -> None: +def test_mul_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, 9, d) for d in (27, 28, 29)] @@ -101,7 +107,7 @@ def test_mul_py_sequence() -> None: check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) -def test_mul_numpy_array() -> None: +def test_mul_numpy_array(left: "pd.Series[int]") -> None: """Test pd.Series[int] * numpy arrays""" b = np.array([True, False, True], np.bool_) i = np.array([2, 3, 5], np.int64) @@ -152,7 +158,7 @@ def test_mul_numpy_array() -> None: check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_mul_pd_index() -> None: +def test_mul_pd_index(left: "pd.Series[int]") -> None: """Test pd.Series[int] * pandas Indexes""" b = pd.Index([True, False, True]) i = pd.Index([2, 3, 5]) @@ -196,7 +202,7 @@ def test_mul_pd_index() -> None: check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_mul_pd_series() -> None: +def test_mul_pd_series(left: "pd.Series[int]") -> None: """Test pd.Series[int] * pandas Series""" b = pd.Series([True, False, True]) i = pd.Series([2, 3, 5]) diff --git a/tests/series/arithmetic/timedelta/test_mul.py b/tests/series/arithmetic/timedelta/test_mul.py index 107886c86..5eaf68ffd 100644 --- a/tests/series/arithmetic/timedelta/test_mul.py +++ b/tests/series/arithmetic/timedelta/test_mul.py @@ -1,6 +1,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, @@ -12,10 +13,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")]) # left operand + return check(assert_type(lo, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_mul_py_scalar() -> None: + +def test_mul_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 @@ -55,7 +61,7 @@ def test_mul_py_scalar() -> None: left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] -def test_mul_py_sequence() -> None: +def test_mul_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] @@ -95,7 +101,7 @@ def test_mul_py_sequence() -> None: left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] -def test_mul_numpy_array() -> None: +def test_mul_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) @@ -142,7 +148,7 @@ def test_mul_numpy_array() -> None: left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] -def test_mul_pd_index() -> None: +def test_mul_pd_index(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] * pandas Indexes""" b = pd.Index([True]) i = pd.Index([2]) @@ -185,7 +191,7 @@ def test_mul_pd_index() -> None: left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] -def test_mul_pd_series() -> None: +def test_mul_pd_series(left: "pd.Series[pd.Timedelta]") -> None: """Test pd.Series[pd.Timedelta] * pandas Series""" b = pd.Series([True]) i = pd.Series([2]) From b9c57d23cad066f8683cf0a36eb087f5c4c1fdc1 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 1 Oct 2025 22:21:41 +0200 Subject: [PATCH 03/15] doc and refactor --- tests/indexes/arithmetic/timedelta/test_mul.py | 8 ++++---- tests/indexes/{ => arithmetic}/timedeltaindex/__init__.py | 0 tests/indexes/{ => arithmetic}/timedeltaindex/test_mul.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) rename tests/indexes/{ => arithmetic}/timedeltaindex/__init__.py (100%) rename tests/indexes/{ => arithmetic}/timedeltaindex/test_mul.py (95%) diff --git a/tests/indexes/arithmetic/timedelta/test_mul.py b/tests/indexes/arithmetic/timedelta/test_mul.py index 9d912f4e2..8d351960d 100644 --- a/tests/indexes/arithmetic/timedelta/test_mul.py +++ b/tests/indexes/arithmetic/timedelta/test_mul.py @@ -25,7 +25,7 @@ def left() -> "pd.Index[pd.Timedelta]": def test_mul_py_scalar(left: "pd.Index[pd.Timedelta]") -> None: - """Test pd.Series[pd.Timedelta] * Python native scalars""" + """Test pd.Index[pd.Timedelta] * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j # pandas-dev/pandas#62316 @@ -45,7 +45,7 @@ def test_mul_py_scalar(left: "pd.Index[pd.Timedelta]") -> None: def test_mul_py_sequence(left: "pd.Index[pd.Timedelta]") -> None: - """Test pd.Series[pd.Timedelta] * Python native sequences""" + """Test pd.Index[pd.Timedelta] * Python native sequences""" b, i, f, c = [True], [2], [1.5], [1.7j] # pandas-dev/pandas#62316 @@ -65,7 +65,7 @@ def test_mul_py_sequence(left: "pd.Index[pd.Timedelta]") -> None: def test_mul_numpy_array(left: "pd.Index[pd.Timedelta]") -> None: - """Test pd.Series[pd.Timedelta] * numpy arrays""" + """Test pd.Index[pd.Timedelta] * numpy arrays""" b = np.array([True], np.bool_) i = np.array([2], np.int64) f = np.array([1.5], np.float64) @@ -92,7 +92,7 @@ def test_mul_numpy_array(left: "pd.Index[pd.Timedelta]") -> None: def test_mul_pd_index(left: "pd.Index[pd.Timedelta]") -> None: - """Test pd.Series[pd.Timedelta] * pandas Indexes""" + """Test pd.Index[pd.Timedelta] * pandas Indexes""" b = pd.Index([True]) i = pd.Index([2]) f = pd.Index([1.5]) diff --git a/tests/indexes/timedeltaindex/__init__.py b/tests/indexes/arithmetic/timedeltaindex/__init__.py similarity index 100% rename from tests/indexes/timedeltaindex/__init__.py rename to tests/indexes/arithmetic/timedeltaindex/__init__.py diff --git a/tests/indexes/timedeltaindex/test_mul.py b/tests/indexes/arithmetic/timedeltaindex/test_mul.py similarity index 95% rename from tests/indexes/timedeltaindex/test_mul.py rename to tests/indexes/arithmetic/timedeltaindex/test_mul.py index fec362fc2..3bc6577c3 100644 --- a/tests/indexes/timedeltaindex/test_mul.py +++ b/tests/indexes/arithmetic/timedeltaindex/test_mul.py @@ -22,7 +22,7 @@ def left() -> pd.TimedeltaIndex: def test_mul_py_scalar(left: pd.TimedeltaIndex) -> None: - """Test pd.Series[pd.Timedelta] * Python native scalars""" + """Test pd.TimedeltaIndex * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j # pandas-dev/pandas#62316 @@ -42,7 +42,7 @@ def test_mul_py_scalar(left: pd.TimedeltaIndex) -> None: def test_mul_py_sequence(left: pd.TimedeltaIndex) -> None: - """Test pd.Series[pd.Timedelta] * Python native sequences""" + """Test pd.TimedeltaIndex * Python native sequences""" b, i, f, c = [True], [2], [1.5], [1.7j] # pandas-dev/pandas#62316 @@ -62,7 +62,7 @@ def test_mul_py_sequence(left: pd.TimedeltaIndex) -> None: def test_mul_numpy_array(left: pd.TimedeltaIndex) -> None: - """Test pd.Series[pd.Timedelta] * numpy arrays""" + """Test pd.TimedeltaIndex * numpy arrays""" b = np.array([True], np.bool_) i = np.array([2], np.int64) f = np.array([1.5], np.float64) @@ -99,7 +99,7 @@ def test_mul_numpy_array(left: pd.TimedeltaIndex) -> None: def test_mul_pd_index(left: pd.TimedeltaIndex) -> None: - """Test pd.Series[pd.Timedelta] * pandas Indexes""" + """Test pd.TimedeltaIndex * pandas Indexes""" b = pd.Index([True]) i = pd.Index([2]) f = pd.Index([1.5]) From d2d11d1355c2fb7b742f4e562d00d80b0384887e Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 1 Oct 2025 23:06:23 +0200 Subject: [PATCH 04/15] complex --- pandas-stubs/core/indexes/base.pyi | 4 + pandas-stubs/core/series.pyi | 4 + tests/indexes/arithmetic/complex/test_mul.py | 132 ++++++++++++++++++ .../{datetime => datetimeindex}/__init__.py | 0 tests/indexes/arithmetic/float/test_mul.py | 2 +- tests/indexes/arithmetic/int/test_mul.py | 2 +- tests/series/arithmetic/complex/test_mul.py | 103 ++++++++++++-- tests/series/arithmetic/float/test_mul.py | 20 +-- tests/series/arithmetic/int/test_mul.py | 20 +-- tests/series/test_properties.py | 4 +- 10 files changed, 258 insertions(+), 33 deletions(-) rename tests/indexes/arithmetic/{datetime => datetimeindex}/__init__.py (100%) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index c8fc72b1f..81bc4ce84 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -752,6 +752,8 @@ class Index(IndexOpsMixin[S1]): def __mul__(self, other: Index[Never]) -> Index: ... @overload def __mul__(self, other: np_ndarray_dt) -> Never: ... + @overload + def __mul__(self: Index[complex], other: np_ndarray_td) -> Never: ... # pandas-dev/pandas#62524 @overload def __mul__( # type: ignore[overload-overlap] @@ -823,6 +825,8 @@ class Index(IndexOpsMixin[S1]): def __rmul__(self, other: Index[Never]) -> Index: ... @overload def __rmul__(self, other: np_ndarray_dt) -> Never: ... + @overload + def __rmul__(self: Index[complex], other: np_ndarray_td) -> Never: ... # pandas-dev/pandas#62524 @overload def __rmul__( # type: ignore[overload-overlap] diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 20ebec471..802948ab2 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2548,6 +2548,8 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __mul__(self, other: np_ndarray_dt) -> Never: ... @overload + def __mul__(self: Series[complex], other: np_ndarray_td) -> Never: ... + @overload def __mul__( self: Series[bool] | Series[int] | Series[float], other: ( @@ -2777,6 +2779,8 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __rmul__(self: Series[Timestamp], other: np_ndarray) -> Never: ... @overload + def __rmul__(self: Series[complex], other: np_ndarray_td) -> Never: ... + @overload def __rmul__(self: Series[Timedelta], other: np_ndarray_complex) -> Never: ... @overload def __rmul__( diff --git a/tests/indexes/arithmetic/complex/test_mul.py b/tests/indexes/arithmetic/complex/test_mul.py index e69de29bb..7d5fe84a5 100644 --- a/tests/indexes/arithmetic/complex/test_mul.py +++ b/tests/indexes/arithmetic/complex/test_mul.py @@ -0,0 +1,132 @@ +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.Index[complex]": + """left operand""" + lo = pd.Index([1j, 2j, 3j]) + return check(assert_type(lo, "pd.Index[complex]"), pd.Index, np.complexfloating) + + +def test_mul_py_scalar(left: "pd.Index[complex]") -> None: + """Test pd.Index[complex] * Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 30), timedelta(seconds=1) + + check(assert_type(left * b, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * i, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * f, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(i * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(f * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_mul_py_sequence(left: "pd.Index[complex]") -> None: + """Test pd.Index[complex] * 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, 9, d) for d in (27, 28, 29)] + d = [timedelta(seconds=s + 1) for s in range(3)] + + check(assert_type(left * b, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * i, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * f, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(i * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(f * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_mul_numpy_array(left: "pd.Index[complex]") -> None: + """Test pd.Index[complex] * 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-09-{d}") for d in (27, 28, 29)], np.datetime64) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) + + check(assert_type(left * b, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * i, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * f, "pd.Index[complex]"), pd.Index, np.complexfloating) + 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 `__rmul__` cannot override. At runtime, they return + # `Index` with the correct element type. + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, np.complexfloating) + check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, np.complexfloating) + check( + assert_type(f * left, "npt.NDArray[np.float64]"), pd.Index, np.complexfloating + ) + check( + assert_type(c * left, "npt.NDArray[np.complex128]"), + pd.Index, + np.complexfloating, + ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s * left, Any) + assert_type(d * left, "npt.NDArray[np.timedelta64]") + + +def test_mul_pd_index(left: "pd.Index[complex]") -> None: + """Test pd.Index[complex] * 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, 9, 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[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * i, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * f, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(i * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(f * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] diff --git a/tests/indexes/arithmetic/datetime/__init__.py b/tests/indexes/arithmetic/datetimeindex/__init__.py similarity index 100% rename from tests/indexes/arithmetic/datetime/__init__.py rename to tests/indexes/arithmetic/datetimeindex/__init__.py diff --git a/tests/indexes/arithmetic/float/test_mul.py b/tests/indexes/arithmetic/float/test_mul.py index 8d1e383c4..db4a24608 100644 --- a/tests/indexes/arithmetic/float/test_mul.py +++ b/tests/indexes/arithmetic/float/test_mul.py @@ -90,7 +90,7 @@ def test_mul_numpy_array(left: "pd.Index[float]") -> None: # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return - # `Series` with the correct element type. + # `Index` with the correct element type. check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, np.floating) check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, np.floating) check(assert_type(f * left, "npt.NDArray[np.float64]"), pd.Index, np.floating) diff --git a/tests/indexes/arithmetic/int/test_mul.py b/tests/indexes/arithmetic/int/test_mul.py index 021fd4ca4..43992eee5 100644 --- a/tests/indexes/arithmetic/int/test_mul.py +++ b/tests/indexes/arithmetic/int/test_mul.py @@ -92,7 +92,7 @@ def test_mul_numpy_array(left: "pd.Index[int]") -> None: # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return - # `Series` with the correct element type. + # `Index` with the correct element type. check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, np.integer) check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, np.integer) check(assert_type(f * left, "npt.NDArray[np.float64]"), pd.Index, np.floating) diff --git a/tests/series/arithmetic/complex/test_mul.py b/tests/series/arithmetic/complex/test_mul.py index e36a822c6..72402c91b 100644 --- a/tests/series/arithmetic/complex/test_mul.py +++ b/tests/series/arithmetic/complex/test_mul.py @@ -1,31 +1,59 @@ +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 -from typing_extensions import assert_type +import pytest +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) -from tests import check -left = pd.Series([1j, 2j, 3j]) # left operand +@pytest.fixture +def left() -> "pd.Series[complex]": + """left operand""" + lo = pd.Series([1j, 2j, 3j]) + return check(assert_type(lo, "pd.Series[complex]"), pd.Series, np.complexfloating) -def test_mul_py_scalar() -> None: +def test_mul_py_scalar(left: "pd.Series[complex]") -> None: """Test pd.Series[complex] * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 9, 30), timedelta(seconds=1) check(assert_type(left * b, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * i, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(i * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(f * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(f), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check( assert_type(left.rmul(b), "pd.Series[complex]"), pd.Series, np.complexfloating @@ -39,26 +67,40 @@ def test_mul_py_scalar() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] -def test_mul_py_sequence() -> None: +def test_mul_py_sequence(left: "pd.Series[complex]") -> None: """Test pd.Series[complex] * 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, 9, d) for d in (27, 28, 29)] + d = [timedelta(seconds=s + 1) for s in range(3)] check(assert_type(left * b, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * i, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(i * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(f * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(f), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check( assert_type(left.rmul(b), "pd.Series[complex]"), pd.Series, np.complexfloating @@ -72,19 +114,27 @@ def test_mul_py_sequence() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] -def test_mul_numpy_array() -> None: +def test_mul_numpy_array(left: "pd.Series[complex]") -> None: """Test pd.Series[complex] * 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-09-{d}") for d in (27, 28, 29)], np.datetime64) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) check(assert_type(left * b, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * i, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) 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 `__rmul__` cannot override. At runtime, they return @@ -99,11 +149,17 @@ def test_mul_numpy_array() -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s * left, Any) + assert_type(d * left, "npt.NDArray[np.timedelta64]") check(assert_type(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(f), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check( assert_type(left.rmul(b), "pd.Series[complex]"), pd.Series, np.complexfloating @@ -117,29 +173,43 @@ def test_mul_numpy_array() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] -def test_mul_pd_index() -> None: +def test_mul_pd_index(left: "pd.Series[complex]") -> None: """Test pd.Series[complex] * 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, 9, 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.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * i, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(i * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(f * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(f), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check( assert_type(left.rmul(b), "pd.Series[complex]"), pd.Series, np.complexfloating @@ -153,29 +223,43 @@ def test_mul_pd_index() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] -def test_mul_pd_series() -> None: +def test_mul_pd_series(left: "pd.Series[complex]") -> None: """Test pd.Series[complex] * 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, 9, d) for d in (27, 28, 29)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left * b, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * i, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(b * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(i * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(f * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(f), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check( assert_type(left.rmul(b), "pd.Series[complex]"), pd.Series, np.complexfloating @@ -189,3 +273,6 @@ def test_mul_pd_series() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] diff --git a/tests/series/arithmetic/float/test_mul.py b/tests/series/arithmetic/float/test_mul.py index ae6ceb1bb..ac7d8e2e9 100644 --- a/tests/series/arithmetic/float/test_mul.py +++ b/tests/series/arithmetic/float/test_mul.py @@ -52,7 +52,7 @@ def test_mul_py_scalar(left: "pd.Series[float]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) @@ -62,7 +62,7 @@ def test_mul_py_scalar(left: "pd.Series[float]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) @@ -93,7 +93,7 @@ def test_mul_py_sequence(left: "pd.Series[float]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) @@ -103,7 +103,7 @@ def test_mul_py_sequence(left: "pd.Series[float]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) @@ -144,7 +144,7 @@ def test_mul_numpy_array(left: "pd.Series[float]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) @@ -154,7 +154,7 @@ def test_mul_numpy_array(left: "pd.Series[float]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) @@ -188,7 +188,7 @@ def test_mul_pd_index(left: "pd.Series[float]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) @@ -198,7 +198,7 @@ def test_mul_pd_index(left: "pd.Series[float]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) @@ -232,7 +232,7 @@ def test_mul_pd_series(left: "pd.Series[float]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[float]"), pd.Series, np.floating) @@ -242,5 +242,5 @@ def test_mul_pd_series(left: "pd.Series[float]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) diff --git a/tests/series/arithmetic/int/test_mul.py b/tests/series/arithmetic/int/test_mul.py index a2b48d8f4..f5a75db46 100644 --- a/tests/series/arithmetic/int/test_mul.py +++ b/tests/series/arithmetic/int/test_mul.py @@ -52,7 +52,7 @@ def test_mul_py_scalar(left: "pd.Series[int]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) @@ -62,7 +62,7 @@ def test_mul_py_scalar(left: "pd.Series[int]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) @@ -93,7 +93,7 @@ def test_mul_py_sequence(left: "pd.Series[int]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) @@ -103,7 +103,7 @@ def test_mul_py_sequence(left: "pd.Series[int]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) @@ -144,7 +144,7 @@ def test_mul_numpy_array(left: "pd.Series[int]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) @@ -154,7 +154,7 @@ def test_mul_numpy_array(left: "pd.Series[int]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) @@ -188,7 +188,7 @@ def test_mul_pd_index(left: "pd.Series[int]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) @@ -198,7 +198,7 @@ def test_mul_pd_index(left: "pd.Series[int]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) @@ -232,7 +232,7 @@ def test_mul_pd_series(left: "pd.Series[int]") -> None: check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _25 = left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[int]"), pd.Series, np.integer) @@ -242,5 +242,5 @@ def test_mul_pd_series(left: "pd.Series[int]") -> None: assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) if TYPE_CHECKING_INVALID_USAGE: - _35 = left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) diff --git a/tests/series/test_properties.py b/tests/series/test_properties.py index 2b76e50db..ac286069e 100644 --- a/tests/series/test_properties.py +++ b/tests/series/test_properties.py @@ -1,6 +1,4 @@ -from typing import ( - TYPE_CHECKING, -) +from typing import TYPE_CHECKING import numpy as np import pandas as pd From 9c802b48af36ca1aca372afcf14b393af6d8df8a Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Wed, 1 Oct 2025 23:21:19 +0200 Subject: [PATCH 05/15] bool --- tests/indexes/arithmetic/bool/test_mul.py | 134 ++++++++++++++++++++++ tests/series/arithmetic/bool/test_mul.py | 103 +++++++++++++++-- 2 files changed, 229 insertions(+), 8 deletions(-) diff --git a/tests/indexes/arithmetic/bool/test_mul.py b/tests/indexes/arithmetic/bool/test_mul.py index e69de29bb..520813303 100644 --- a/tests/indexes/arithmetic/bool/test_mul.py +++ b/tests/indexes/arithmetic/bool/test_mul.py @@ -0,0 +1,134 @@ +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.Index[bool]": + """left operand""" + lo = pd.Index([True, True, False]) + return check(assert_type(lo, "pd.Index[bool]"), pd.Index, np.bool_) + + +def test_mul_py_scalar(left: "pd.Index[bool]") -> None: + """Test pd.Index[bool] * Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 10, 1), timedelta(seconds=1) + + check(assert_type(left * b, "pd.Index[bool]"), pd.Index, np.bool_) + check(assert_type(left * i, "pd.Index[int]"), pd.Index, np.integer) + 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + check(assert_type(b * left, "pd.Index[bool]"), pd.Index, np.bool_) + check(assert_type(i * left, "pd.Index[int]"), pd.Index, np.integer) + 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + +def test_mul_py_sequence(left: "pd.Index[bool]") -> None: + """Test pd.Index[bool] * 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 (1, 2, 3)] + d = [timedelta(seconds=s + 1) for s in range(3)] + + check(assert_type(left * b, "pd.Index[bool]"), pd.Index, np.bool_) + check(assert_type(left * i, "pd.Index[int]"), pd.Index, np.integer) + 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + + check(assert_type(b * left, "pd.Index[bool]"), pd.Index, np.bool_) + check(assert_type(i * left, "pd.Index[int]"), pd.Index, np.integer) + 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) + + +def test_mul_numpy_array(left: "pd.Index[bool]") -> None: + """Test pd.Index[bool] * 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 (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[bool]"), pd.Index, np.bool_) + check(assert_type(left * i, "pd.Index[int]"), pd.Index, np.integer) + 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) + check(assert_type(left * d, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rmul__` cannot override. At runtime, they return + # `Index` with the correct element type. + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, np.bool_) + check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, np.integer) + check(assert_type(f * left, "npt.NDArray[np.float64]"), pd.Index, np.floating) + check( + assert_type(c * left, "npt.NDArray[np.complex128]"), + pd.Index, + np.complexfloating, + ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s * left, Any) + check( + assert_type(d * left, "npt.NDArray[np.timedelta64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) + + +def test_mul_pd_index(left: "pd.Index[bool]") -> None: + """Test pd.Index[bool] * 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 (1, 2, 3)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) + + check(assert_type(left * b, "pd.Index[bool]"), pd.Index, np.bool_) + check(assert_type(left * i, "pd.Index[int]"), pd.Index, np.integer) + 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, pd.TimedeltaIndex), pd.Index, timedelta) + + check(assert_type(b * left, "pd.Index[bool]"), pd.Index, np.bool_) + check(assert_type(i * left, "pd.Index[int]"), pd.Index, np.integer) + 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, pd.TimedeltaIndex), pd.Index, timedelta) diff --git a/tests/series/arithmetic/bool/test_mul.py b/tests/series/arithmetic/bool/test_mul.py index c7e76e917..202b8b04f 100644 --- a/tests/series/arithmetic/bool/test_mul.py +++ b/tests/series/arithmetic/bool/test_mul.py @@ -1,31 +1,59 @@ +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 -from typing_extensions import assert_type +import pytest +from typing_extensions import ( + Never, + assert_type, +) + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) -from tests import check -left = pd.Series([True, True, False]) # left operand +@pytest.fixture +def left() -> "pd.Series[bool]": + """left operand""" + lo = pd.Series([True, True, False]) + return check(assert_type(lo, "pd.Series[bool]"), pd.Series, np.bool_) -def test_mul_py_scalar() -> None: +def test_mul_py_scalar(left: "pd.Series[bool]") -> None: """Test pd.Series[bool] * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j + s, d = datetime(2025, 10, 1), timedelta(seconds=1) check(assert_type(left * b, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left * i, "pd.Series[int]"), pd.Series, np.integer) 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(b * left, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(i * left, "pd.Series[int]"), pd.Series, np.integer) 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: + _15 = 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.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -33,26 +61,40 @@ def test_mul_py_scalar() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_mul_py_sequence() -> None: +def test_mul_py_sequence(left: "pd.Series[bool]") -> None: """Test pd.Series[bool] * 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 (1, 2, 3)] + d = [timedelta(seconds=s + 1) for s in range(3)] check(assert_type(left * b, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left * i, "pd.Series[int]"), pd.Series, np.integer) 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(i * left, "pd.Series[int]"), pd.Series, np.integer) 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -60,19 +102,27 @@ def test_mul_py_sequence() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) -def test_mul_numpy_array() -> None: +def test_mul_numpy_array(left: "pd.Series[bool]") -> None: """Test pd.Series[bool] * 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 (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.Series[bool]"), pd.Series, np.bool_) check(assert_type(left * i, "pd.Series[int]"), pd.Series, np.integer) 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) + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return @@ -85,11 +135,17 @@ def test_mul_numpy_array() -> None: pd.Series, np.complexfloating, ) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(s * left, Any) + check(assert_type(d * left, "npt.NDArray[np.timedelta64]"), pd.Series, pd.Timedelta) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -97,29 +153,43 @@ def test_mul_numpy_array() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) -def test_mul_pd_index() -> None: +def test_mul_pd_index(left: "pd.Series[bool]") -> None: """Test pd.Series[bool] * 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 (1, 2, 3)]) + d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left * b, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left * i, "pd.Series[int]"), pd.Series, np.integer) 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(i * left, "pd.Series[int]"), pd.Series, np.integer) 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -127,29 +197,43 @@ def test_mul_pd_index() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) -def test_mul_pd_series() -> None: +def test_mul_pd_series(left: "pd.Series[bool]") -> None: """Test pd.Series[bool] * 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 (1, 2, 3)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) check(assert_type(left * b, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left * i, "pd.Series[int]"), pd.Series, np.integer) 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: + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(i * left, "pd.Series[int]"), pd.Series, np.integer) 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: + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) check(assert_type(left.mul(f), "pd.Series[float]"), pd.Series, np.floating) check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -157,3 +241,6 @@ def test_mul_pd_series() -> None: check( assert_type(left.rmul(c), "pd.Series[complex]"), pd.Series, np.complexfloating ) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) From 8b987d4cff3fae56e1ecc1fb8de781546b0dfb1b Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 2 Oct 2025 09:53:40 +0200 Subject: [PATCH 06/15] chore(poetry): update pyright --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a4b6430a1..f98dd1195 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ mypy = "1.18.2" pandas = "2.3.2" pyarrow = ">=10.0.1" pytest = ">=8.4.2" -pyright = ">=1.1.405" +pyright = ">=1.1.406" ty = ">=0.0.1a21" pyrefly = ">=0.35.0" poethepoet = ">=0.16.5" From c8e0105221a84d9790136530ef0e7db0fbbab0c7 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sat, 4 Oct 2025 20:31:22 +0200 Subject: [PATCH 07/15] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1397#discussion_r2404101854 --- tests/indexes/arithmetic/test_mul.py | 112 +++++++++++++++++++++++++++ tests/series/arithmetic/test_mul.py | 20 +++-- 2 files changed, 125 insertions(+), 7 deletions(-) diff --git a/tests/indexes/arithmetic/test_mul.py b/tests/indexes/arithmetic/test_mul.py index e69de29bb..eb901c177 100644 --- a/tests/indexes/arithmetic/test_mul.py +++ b/tests/indexes/arithmetic/test_mul.py @@ -0,0 +1,112 @@ +from typing import Any + +import numpy as np +import pandas as pd +import pytest +from typing_extensions import assert_type + +from tests import ( + TYPE_CHECKING_INVALID_USAGE, + check, +) + + +@pytest.fixture +def left_i() -> "pd.Index[Any]": + """left operand""" + lo = pd.MultiIndex.from_tuples([(1,), (2,), (3,)]).levels[0] + return check(assert_type(lo, pd.Index), pd.Index) + + +def test_mul_py_scalar(left_i: "pd.Index[Any]") -> None: + """Test pd.Index[Any] (int) * Python native scalars""" + b, i, f, c = True, 1, 1.0, 1j + + check(assert_type(left_i * b, pd.Index), pd.Index) + check(assert_type(left_i * i, pd.Index), pd.Index) + check(assert_type(left_i * f, pd.Index), pd.Index) + check(assert_type(left_i * c, pd.Index), pd.Index) + + check(assert_type(b * left_i, pd.Index), pd.Index) + check(assert_type(i * left_i, pd.Index), pd.Index) + check(assert_type(f * left_i, pd.Index), pd.Index) + check(assert_type(c * left_i, pd.Index), pd.Index) + + +def test_mul_py_sequence(left_i: "pd.Index[Any]") -> None: + """Test pd.Index[Any] (int) * Python native sequences""" + b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] + + check(assert_type(left_i * b, pd.Index), pd.Index) + check(assert_type(left_i * i, pd.Index), pd.Index) + check(assert_type(left_i * f, pd.Index), pd.Index) + check(assert_type(left_i * c, pd.Index), pd.Index) + + check(assert_type(b * left_i, pd.Index), pd.Index) + check(assert_type(i * left_i, pd.Index), pd.Index) + check(assert_type(f * left_i, pd.Index), pd.Index) + check(assert_type(c * left_i, pd.Index), pd.Index) + + +def test_mul_numpy_array(left_i: "pd.Index[Any]") -> None: + """Test pd.Index[Any] (int) * 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) + + check(assert_type(left_i * b, pd.Index), pd.Index) + check(assert_type(left_i * i, pd.Index), pd.Index) + check(assert_type(left_i * f, pd.Index), pd.Index) + check(assert_type(left_i * c, pd.Index), pd.Index) + + # `numpy` typing gives the corresponding `ndarray`s in the static type + # checking, where our `__rmul__` cannot override. At runtime, they return + # `Index`. + # microsoft/pyright#10924 + check( + assert_type(b * left_i, Any), # pyright: ignore[reportAssertTypeFailure] + pd.Index, + ) + check( + assert_type(i * left_i, Any), # pyright: ignore[reportAssertTypeFailure] + pd.Index, + ) + check( + assert_type(f * left_i, Any), # pyright: ignore[reportAssertTypeFailure] + pd.Index, + ) + check( + assert_type(c * left_i, Any), # pyright: ignore[reportAssertTypeFailure] + pd.Index, + ) + + +def test_mul_pd_index(left_i: "pd.Index[Any]") -> None: + """Test pd.Index[Any] (int) * pandas Indexes""" + a = pd.MultiIndex.from_tuples([(1,), (2,), (3,)]).levels[0] + 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]) + + check(assert_type(left_i * a, pd.Index), pd.Index) + check(assert_type(left_i * b, pd.Index), pd.Index) + check(assert_type(left_i * i, pd.Index), pd.Index) + check(assert_type(left_i * f, pd.Index), pd.Index) + check(assert_type(left_i * c, pd.Index), pd.Index) + + check(assert_type(a * left_i, pd.Index), pd.Index) + check(assert_type(b * left_i, pd.Index), pd.Index) + check(assert_type(i * left_i, pd.Index), pd.Index) + check(assert_type(f * left_i, pd.Index), pd.Index) + check(assert_type(c * left_i, pd.Index), pd.Index) + + +def test_mul_str_py_str(left_i: "pd.Index[Any]") -> None: + """Test pd.Index[Any] (int) * Python str""" + 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] diff --git a/tests/series/arithmetic/test_mul.py b/tests/series/arithmetic/test_mul.py index 8fb674717..d5d1e6091 100644 --- a/tests/series/arithmetic/test_mul.py +++ b/tests/series/arithmetic/test_mul.py @@ -2,6 +2,7 @@ import numpy as np import pandas as pd +import pytest from typing_extensions import assert_type from tests import ( @@ -9,10 +10,15 @@ check, ) -left_i = pd.DataFrame({"a": [1, 2, 3]})["a"] # left operand +@pytest.fixture +def left_i() -> "pd.Series[Any]": + """left operand""" + lo = pd.DataFrame({"a": [1, 2, 3]})["a"] + return check(assert_type(lo, pd.Series), pd.Series) -def test_mul_py_scalar() -> None: + +def test_mul_py_scalar(left_i: "pd.Series[Any]") -> None: """Test pd.Series[Any] (int) * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j @@ -37,7 +43,7 @@ def test_mul_py_scalar() -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_py_sequence() -> None: +def test_mul_py_sequence(left_i: "pd.Series[Any]") -> 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] @@ -62,7 +68,7 @@ def test_mul_py_sequence() -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_numpy_array() -> None: +def test_mul_numpy_array(left_i: "pd.Series[Any]") -> None: """Test pd.Series[Any] (int) * numpy arrays""" b = np.array([True, False, True], np.bool_) i = np.array([2, 3, 5], np.int64) @@ -106,7 +112,7 @@ def test_mul_numpy_array() -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_pd_index() -> None: +def test_mul_pd_index(left_i: "pd.Series[Any]") -> None: """Test pd.Series[Any] (int) * pandas Indexes""" a = pd.MultiIndex.from_tuples([(1,), (2,), (3,)]).levels[0] b = pd.Index([True, False, True]) @@ -139,7 +145,7 @@ def test_mul_pd_index() -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_pd_series() -> None: +def test_mul_pd_series(left_i: "pd.Series[Any]") -> None: """Test pd.Series[Any] (int) * pandas Series""" a = pd.DataFrame({"a": [1, 2, 3]})["a"] b = pd.Series([True, False, True]) @@ -172,7 +178,7 @@ def test_mul_pd_series() -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_str_py_str() -> None: +def test_mul_str_py_str(left_i: "pd.Series[Any]") -> None: """Test pd.Series[Any] (int) * Python str""" s = "abc" From 6cf48fc7432bcfc4808a5ab9d6451c9f9519fc54 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sat, 4 Oct 2025 21:18:35 +0200 Subject: [PATCH 08/15] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1397#pullrequestreview-3302019493 --- pandas-stubs/core/indexes/base.pyi | 20 ++ pandas-stubs/core/series.pyi | 64 +++++++ tests/indexes/arithmetic/str/test_mul.py | 126 ++++++++++++ tests/series/arithmetic/str/test_mul.py | 232 +++++++++++++++++++++++ 4 files changed, 442 insertions(+) create mode 100644 tests/indexes/arithmetic/str/test_mul.py create mode 100644 tests/series/arithmetic/str/test_mul.py diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index b1c21b7ef..ea70379b2 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -781,6 +781,16 @@ class Index(IndexOpsMixin[S1]): ), ) -> Index[Timedelta]: ... @overload + def __mul__( + self: Index[_str], + other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + ) -> Never: ... + @overload + def __mul__( + self: Index[_str], + other: int | Sequence[int] | np_ndarray_bool | np_ndarray_anyint | Index[T_INT], + ) -> Index[_str]: ... + @overload def __mul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... @overload def __mul__(self: Index[float], other: int | Sequence[int]) -> Index[float]: ... @@ -854,6 +864,16 @@ class Index(IndexOpsMixin[S1]): ), ) -> Index[Timedelta]: ... @overload + def __rmul__( + self: Index[_str], + other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + ) -> Never: ... + @overload + def __rmul__( + self: Index[_str], + other: int | Sequence[int] | np_ndarray_bool | np_ndarray_anyint | Index[T_INT], + ) -> Index[_str]: ... + @overload def __rmul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... @overload def __rmul__(self: Index[float], other: int | Sequence[int]) -> Index[float]: ... diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 8c26edff3..92d109e6f 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2583,6 +2583,23 @@ class Series(IndexOpsMixin[S1], NDFrame): ), ) -> Series[Timedelta]: ... @overload + def __mul__( + self: Series[_str], + other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + ) -> Never: ... + @overload + def __mul__( + self: Series[_str], + other: ( + int + | Sequence[int] + | np_ndarray_bool + | np_ndarray_anyint + | Index[T_INT] + | Series[T_INT] + ), + ) -> Series[_str]: ... + @overload def __mul__(self: Series[T_INT], other: bool | Sequence[bool]) -> Series[T_INT]: ... @overload def __mul__(self: Series[float], other: int | Sequence[int]) -> Series[float]: ... @@ -2675,6 +2692,21 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... @overload + def mul( + self: Series[_str], + other: ( + int + | Sequence[int] + | np_ndarray_bool + | np_ndarray_anyint + | Index[T_INT] + | Series[T_INT] + ), + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series[_str]: ... + @overload def mul( self: Series[T_INT], other: bool | Sequence[bool], @@ -2800,6 +2832,23 @@ class Series(IndexOpsMixin[S1], NDFrame): ), ) -> Series[Timedelta]: ... @overload + def __rmul__( + self: Series[_str], + other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + ) -> Never: ... + @overload + def __rmul__( + self: Series[_str], + other: ( + int + | Sequence[int] + | np_ndarray_bool + | np_ndarray_anyint + | Index[T_INT] + | Series[T_INT] + ), + ) -> Series[_str]: ... + @overload def __rmul__( self: Series[T_INT], other: bool | Sequence[bool] ) -> Series[T_INT]: ... @@ -2894,6 +2943,21 @@ class Series(IndexOpsMixin[S1], NDFrame): axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... @overload + def rmul( + self: Series[_str], + other: ( + int + | Sequence[int] + | np_ndarray_bool + | np_ndarray_anyint + | Index[T_INT] + | Series[T_INT] + ), + level: Level | None = None, + fill_value: float | None = None, + axis: int = 0, + ) -> Series[_str]: ... + @overload def rmul( self: Series[T_INT], other: bool | Sequence[bool], diff --git a/tests/indexes/arithmetic/str/test_mul.py b/tests/indexes/arithmetic/str/test_mul.py new file mode 100644 index 000000000..c75c07031 --- /dev/null +++ b/tests/indexes/arithmetic/str/test_mul.py @@ -0,0 +1,126 @@ +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.Index[str]": + """left operand""" + lo = pd.Index(["1", "2", "3"]) + return check(assert_type(lo, "pd.Index[str]"), pd.Index, str) + + +def test_mul_py_scalar(left: "pd.Index[str]") -> None: + """Test pd.Index[str] * 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[str]"), pd.Index, str) + check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) + check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_mul_py_sequence(left: "pd.Index[str]") -> None: + """Test pd.Index[str] * 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, 9, d) for d in (27, 28, 29)] + d = [timedelta(seconds=s + 1) for s in range(3)] + + check(assert_type(left * b, "pd.Index[str]"), pd.Index, str) + check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) + check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + +def test_mul_numpy_array(left: "pd.Index[str]") -> None: + """Test pd.Index[str] * 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-09-{d}") for d in (27, 28, 29)], np.datetime64) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) + + check(assert_type(left * b, "pd.Index[str]"), pd.Index, str) + check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left * f, Never) + 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 `__rmul__` cannot override. At runtime, they return + # `Index` with the correct element type. + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, str) + check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(f * left, "npt.NDArray[np.float64]") + assert_type(c * left, "npt.NDArray[np.complex128]") + assert_type(s * left, Any) + assert_type(d * left, "npt.NDArray[np.timedelta64]") + + +def test_mul_pd_index(left: "pd.Index[str]") -> None: + """Test pd.Index[str] * 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, 9, 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[str]"), pd.Index, str) + check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) + check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] diff --git a/tests/series/arithmetic/str/test_mul.py b/tests/series/arithmetic/str/test_mul.py new file mode 100644 index 000000000..722fa5dda --- /dev/null +++ b/tests/series/arithmetic/str/test_mul.py @@ -0,0 +1,232 @@ +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.Series[str]": + """left operand""" + lo = pd.Series(["1", "2", "3"]) + return check(assert_type(lo, "pd.Series[str]"), pd.Series, str) + + +def test_mul_py_scalar(left: "pd.Series[str]") -> None: + """Test pd.Series[str] * 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[str]"), pd.Series, str) + check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) + check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + +def test_mul_py_sequence(left: "pd.Series[str]") -> None: + """Test pd.Series[str] * 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, 9, d) for d in (27, 28, 29)] + d = [timedelta(seconds=s + 1) for s in range(3)] + + check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) + check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) + check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + +def test_mul_numpy_array(left: "pd.Series[str]") -> None: + """Test pd.Series[str] * 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-09-{d}") for d in (27, 28, 29)], np.datetime64) + d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) + + check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) + check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left * f, Never) + 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 `__rmul__` cannot override. At runtime, they return + # `Series` with the correct element type. + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Series, str) + check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(f * left, "npt.NDArray[np.float64]") + assert_type(c * left, "npt.NDArray[np.complex128]") + assert_type(s * left, Any) + assert_type(d * left, "npt.NDArray[np.timedelta64]") + + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + +def test_mul_pd_index(left: "pd.Series[str]") -> None: + """Test pd.Series[str] * 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, 9, 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.Series[str]"), pd.Series, str) + check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) + check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + +def test_mul_pd_series(left: "pd.Series[str]") -> None: + """Test pd.Series[str] * 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, 9, d) for d in (27, 28, 29)]) + d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) + + check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) + check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) + check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] From 560695e62c1324b3075f3343f6f140e0252c62ed Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sat, 4 Oct 2025 21:19:56 +0200 Subject: [PATCH 09/15] chore(pyrefly): remove-unused-ignores --- pandas-stubs/core/arrays/datetimelike.pyi | 4 ++-- pandas-stubs/core/groupby/generic.pyi | 2 +- pandas-stubs/core/indexes/base.pyi | 2 +- pandas-stubs/core/indexes/multi.pyi | 4 ++-- pandas-stubs/core/indexes/range.pyi | 2 +- pandas-stubs/core/series.pyi | 4 ++-- pandas-stubs/core/window/ewm.pyi | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pandas-stubs/core/arrays/datetimelike.pyi b/pandas-stubs/core/arrays/datetimelike.pyi index 59841aa0f..74f62e405 100644 --- a/pandas-stubs/core/arrays/datetimelike.pyi +++ b/pandas-stubs/core/arrays/datetimelike.pyi @@ -60,7 +60,7 @@ class DatetimeLikeArrayMixin(ExtensionOpsMixin, ExtensionArray): @property def shape(self): ... def reshape(self, *args: Any, **kwargs: Any): ... - def ravel(self, *args: Any, **kwargs: Any): ... # pyrefly: ignore + def ravel(self, *args: Any, **kwargs: Any): ... def __iter__(self): ... @property def asi8(self) -> np.ndarray: ... @@ -85,7 +85,7 @@ class DatetimeLikeArrayMixin(ExtensionOpsMixin, ExtensionArray): def unique(self): ... def copy(self): ... def shift(self, periods: int = 1, fill_value=..., axis: int = ...): ... - def repeat(self, repeats, *args: Any, **kwargs: Any): ... # pyrefly: ignore + def repeat(self, repeats, *args: Any, **kwargs: Any): ... def value_counts(self, dropna: bool = True): ... def map(self, mapper): ... def isna(self): ... diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 2fba6ce66..40670c59d 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -57,7 +57,7 @@ class NamedAgg(NamedTuple): class SeriesGroupBy(GroupBy[Series[S2]], Generic[S2, ByT]): @overload - def aggregate( # pyrefly: ignore + def aggregate( self, func: Callable[Concatenate[Series[S2], P], S3], /, diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index ea70379b2..a553ff2c8 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -929,7 +929,7 @@ class Index(IndexOpsMixin[S1]): @type_check_only class _IndexSubclassBase(Index[S1], Generic[S1, GenericT_co]): @overload - def to_numpy( # pyrefly: ignore + def to_numpy( self, dtype: None = None, copy: bool = False, diff --git a/pandas-stubs/core/indexes/multi.pyi b/pandas-stubs/core/indexes/multi.pyi index a4301ad29..b64cd1f2d 100644 --- a/pandas-stubs/core/indexes/multi.pyi +++ b/pandas-stubs/core/indexes/multi.pyi @@ -109,7 +109,7 @@ class MultiIndex(Index): def dropna(self, how: AnyAll = "any") -> Self: ... def get_level_values(self, level: str | int) -> Index: ... def unique(self, level=...): ... - def to_frame( # pyrefly: ignore + def to_frame( self, index: bool = True, name: list[HashableT] = ..., @@ -131,7 +131,7 @@ class MultiIndex(Index): def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] self, key: int ) -> tuple: ... - def append(self, other): ... # pyrefly: ignore + def append(self, other): ... def repeat(self, repeats, axis=...): ... def drop(self, codes, level: Level | None = None, errors: str = "raise") -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] def swaplevel(self, i: int = -2, j: int = -1): ... diff --git a/pandas-stubs/core/indexes/range.pyi b/pandas-stubs/core/indexes/range.pyi index e2fe1c8c0..5e4055fb8 100644 --- a/pandas-stubs/core/indexes/range.pyi +++ b/pandas-stubs/core/indexes/range.pyi @@ -81,7 +81,7 @@ class RangeIndex(_IndexSubclassBase[int, np.int64]): def all(self, *args: Any, **kwargs: Any) -> bool: ... def any(self, *args: Any, **kwargs: Any) -> bool: ... @final - def union( # pyrefly: ignore + def union( self, other: list[HashableT] | Index, sort: bool | None = None ) -> Index | Index[int] | RangeIndex: ... @overload # type: ignore[override] diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 92d109e6f..5dfb5c907 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -4620,7 +4620,7 @@ class Series(IndexOpsMixin[S1], NDFrame): **kwargs: Any, ) -> np_1darray: ... @overload - def to_numpy( # pyrefly: ignore[bad-override] + def to_numpy( self: Series[Timestamp], dtype: type[np.datetime64] | None = None, copy: bool = False, @@ -4636,7 +4636,7 @@ class Series(IndexOpsMixin[S1], NDFrame): **kwargs: Any, ) -> np_1darray[GenericT]: ... @overload - def to_numpy( # pyrefly: ignore[bad-override] + def to_numpy( self: Series[Timedelta], dtype: type[np.timedelta64] | None = None, copy: bool = False, diff --git a/pandas-stubs/core/window/ewm.pyi b/pandas-stubs/core/window/ewm.pyi index eb3c6ed33..ea7e3b0ce 100644 --- a/pandas-stubs/core/window/ewm.pyi +++ b/pandas-stubs/core/window/ewm.pyi @@ -51,7 +51,7 @@ class ExponentialMovingWindowGroupby( class OnlineExponentialMovingWindow(ExponentialMovingWindow[NDFrameT]): def reset(self) -> None: ... def aggregate(self, func, *args: Any, **kwargs: Any): ... - def std(self, bias: bool = False, *args: Any, **kwargs: Any): ... # pyrefly: ignore + def std(self, bias: bool = False, *args: Any, **kwargs: Any): ... def corr( self, other: DataFrame | Series | None = None, @@ -66,7 +66,7 @@ class OnlineExponentialMovingWindow(ExponentialMovingWindow[NDFrameT]): numeric_only: bool = False, ): ... def var(self, bias: bool = False, numeric_only: bool = False): ... - def mean( # pyrefly: ignore + def mean( self, *args: Any, update: NDFrameT | None = ..., From 23dd2021d7633e5ac6896761482733600974c199 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 5 Oct 2025 17:00:16 +0200 Subject: [PATCH 10/15] chore(comment): https://github.com/pandas-dev/pandas-stubs/pull/1397#discussion_r2404508429 --- pandas-stubs/core/indexes/base.pyi | 6 ++++-- tests/indexes/arithmetic/int/test_mul.py | 6 ++++-- tests/indexes/arithmetic/timedelta/test_mul.py | 3 ++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index a553ff2c8..1c21dcee8 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -754,7 +754,8 @@ class Index(IndexOpsMixin[S1]): def __mul__(self, other: np_ndarray_dt) -> Never: ... @overload def __mul__(self: Index[complex], other: np_ndarray_td) -> Never: ... - # pandas-dev/pandas#62524 + # pandas-dev/pandas#62524: An index of Python native timedeltas can be + # produced, instead of a TimedeltaIndex, hence the overload @overload def __mul__( # type: ignore[overload-overlap] self: Index[bool] | Index[int] | Index[float], other: Sequence[timedelta] @@ -837,7 +838,8 @@ class Index(IndexOpsMixin[S1]): def __rmul__(self, other: np_ndarray_dt) -> Never: ... @overload def __rmul__(self: Index[complex], other: np_ndarray_td) -> Never: ... - # pandas-dev/pandas#62524 + # pandas-dev/pandas#62524: An index of Python native timedeltas can be + # produced, instead of a TimedeltaIndex, hence the overload @overload def __rmul__( # type: ignore[overload-overlap] self: Index[bool] | Index[int] | Index[float], other: Sequence[timedelta] diff --git a/tests/indexes/arithmetic/int/test_mul.py b/tests/indexes/arithmetic/int/test_mul.py index 43992eee5..68a722678 100644 --- a/tests/indexes/arithmetic/int/test_mul.py +++ b/tests/indexes/arithmetic/int/test_mul.py @@ -60,7 +60,8 @@ def test_mul_py_sequence(left: "pd.Index[int]") -> None: check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - # pandas-dev/pandas#62524 + # pandas-dev/pandas#62524: An index of Python native timedeltas can be + # produced, instead of a TimedeltaIndex, hence the test check(assert_type(left * d, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) check(assert_type(b * left, "pd.Index[int]"), pd.Index, np.integer) @@ -69,7 +70,8 @@ def test_mul_py_sequence(left: "pd.Index[int]") -> None: check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - # pandas-dev/pandas#62524 + # pandas-dev/pandas#62524: An index of Python native timedeltas can be + # produced, instead of a TimedeltaIndex, hence the test check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) diff --git a/tests/indexes/arithmetic/timedelta/test_mul.py b/tests/indexes/arithmetic/timedelta/test_mul.py index 8d351960d..590dc57d6 100644 --- a/tests/indexes/arithmetic/timedelta/test_mul.py +++ b/tests/indexes/arithmetic/timedelta/test_mul.py @@ -19,7 +19,8 @@ @pytest.fixture def left() -> "pd.Index[pd.Timedelta]": """left operand""" - # pandas-dev/pandas#62524 + # pandas-dev/pandas#62524: An index of Python native timedeltas can be + # produced, instead of a TimedeltaIndex, hence this test file lo = pd.Index([1]) * [timedelta(seconds=1)] # left operand return check(assert_type(lo, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) From 6443fbf17edb591adc3bdbedfd66ee0a716e0efc Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 5 Oct 2025 17:18:25 +0200 Subject: [PATCH 11/15] fix(comment): https://github.com/pandas-dev/pandas-stubs/pull/1397#discussion_r2404506170 --- tests/indexes/arithmetic/test_mul.py | 12 ++++++------ tests/series/arithmetic/test_mul.py | 14 +++++++------- tests/series/test_series.py | 6 ++---- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/tests/indexes/arithmetic/test_mul.py b/tests/indexes/arithmetic/test_mul.py index eb901c177..5239e44dc 100644 --- a/tests/indexes/arithmetic/test_mul.py +++ b/tests/indexes/arithmetic/test_mul.py @@ -12,13 +12,13 @@ @pytest.fixture -def left_i() -> "pd.Index[Any]": +def left_i() -> pd.Index: """left operand""" lo = pd.MultiIndex.from_tuples([(1,), (2,), (3,)]).levels[0] return check(assert_type(lo, pd.Index), pd.Index) -def test_mul_py_scalar(left_i: "pd.Index[Any]") -> None: +def test_mul_py_scalar(left_i: pd.Index) -> None: """Test pd.Index[Any] (int) * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j @@ -33,7 +33,7 @@ def test_mul_py_scalar(left_i: "pd.Index[Any]") -> None: check(assert_type(c * left_i, pd.Index), pd.Index) -def test_mul_py_sequence(left_i: "pd.Index[Any]") -> None: +def test_mul_py_sequence(left_i: pd.Index) -> None: """Test pd.Index[Any] (int) * Python native sequences""" b, i, f, c = [True, False, True], [2, 3, 5], [1.0, 2.0, 3.0], [1j, 1j, 4j] @@ -48,7 +48,7 @@ def test_mul_py_sequence(left_i: "pd.Index[Any]") -> None: check(assert_type(c * left_i, pd.Index), pd.Index) -def test_mul_numpy_array(left_i: "pd.Index[Any]") -> None: +def test_mul_numpy_array(left_i: pd.Index) -> None: """Test pd.Index[Any] (int) * numpy arrays""" b = np.array([True, False, True], np.bool_) i = np.array([2, 3, 5], np.int64) @@ -82,7 +82,7 @@ def test_mul_numpy_array(left_i: "pd.Index[Any]") -> None: ) -def test_mul_pd_index(left_i: "pd.Index[Any]") -> None: +def test_mul_pd_index(left_i: pd.Index) -> None: """Test pd.Index[Any] (int) * pandas Indexes""" a = pd.MultiIndex.from_tuples([(1,), (2,), (3,)]).levels[0] b = pd.Index([True, False, True]) @@ -103,7 +103,7 @@ def test_mul_pd_index(left_i: "pd.Index[Any]") -> None: check(assert_type(c * left_i, pd.Index), pd.Index) -def test_mul_str_py_str(left_i: "pd.Index[Any]") -> None: +def test_mul_str_py_str(left_i: pd.Index) -> None: """Test pd.Index[Any] (int) * Python str""" s = "abc" diff --git a/tests/series/arithmetic/test_mul.py b/tests/series/arithmetic/test_mul.py index d5d1e6091..4d1b3aaa3 100644 --- a/tests/series/arithmetic/test_mul.py +++ b/tests/series/arithmetic/test_mul.py @@ -12,13 +12,13 @@ @pytest.fixture -def left_i() -> "pd.Series[Any]": +def left_i() -> pd.Series: """left operand""" lo = pd.DataFrame({"a": [1, 2, 3]})["a"] return check(assert_type(lo, pd.Series), pd.Series) -def test_mul_py_scalar(left_i: "pd.Series[Any]") -> None: +def test_mul_py_scalar(left_i: pd.Series) -> None: """Test pd.Series[Any] (int) * Python native scalars""" b, i, f, c = True, 1, 1.0, 1j @@ -43,7 +43,7 @@ def test_mul_py_scalar(left_i: "pd.Series[Any]") -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_py_sequence(left_i: "pd.Series[Any]") -> None: +def test_mul_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] @@ -68,7 +68,7 @@ def test_mul_py_sequence(left_i: "pd.Series[Any]") -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_numpy_array(left_i: "pd.Series[Any]") -> None: +def test_mul_numpy_array(left_i: pd.Series) -> None: """Test pd.Series[Any] (int) * numpy arrays""" b = np.array([True, False, True], np.bool_) i = np.array([2, 3, 5], np.int64) @@ -112,7 +112,7 @@ def test_mul_numpy_array(left_i: "pd.Series[Any]") -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_pd_index(left_i: "pd.Series[Any]") -> None: +def test_mul_pd_index(left_i: pd.Series) -> None: """Test pd.Series[Any] (int) * pandas Indexes""" a = pd.MultiIndex.from_tuples([(1,), (2,), (3,)]).levels[0] b = pd.Index([True, False, True]) @@ -145,7 +145,7 @@ def test_mul_pd_index(left_i: "pd.Series[Any]") -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_pd_series(left_i: "pd.Series[Any]") -> None: +def test_mul_pd_series(left_i: pd.Series) -> None: """Test pd.Series[Any] (int) * pandas Series""" a = pd.DataFrame({"a": [1, 2, 3]})["a"] b = pd.Series([True, False, True]) @@ -178,7 +178,7 @@ def test_mul_pd_series(left_i: "pd.Series[Any]") -> None: check(assert_type(left_i.rmul(c), pd.Series), pd.Series) -def test_mul_str_py_str(left_i: "pd.Series[Any]") -> None: +def test_mul_str_py_str(left_i: pd.Series) -> None: """Test pd.Series[Any] (int) * Python str""" s = "abc" diff --git a/tests/series/test_series.py b/tests/series/test_series.py index 1e65de04a..464390d10 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -3485,9 +3485,7 @@ def test_diff() -> None: ) # bool -> Any check( - assert_type( - pd.Series([True, True, False, False, True]).diff(), "pd.Series[Any]" - ), + assert_type(pd.Series([True, True, False, False, True]).diff(), pd.Series), pd.Series, bool, index_to_check_for_type=-1, @@ -3508,7 +3506,7 @@ def test_diff() -> None: ) # Any -> float s_o = s.astype(object) - assert_type(s_o, "pd.Series[Any]") + assert_type(s_o, pd.Series) check(assert_type(s_o.diff(), "pd.Series[float]"), pd.Series, float) # complex -> complex check( From fb97790e84fde2aa66722d392327d682e975fe2c Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 5 Oct 2025 19:13:16 +0200 Subject: [PATCH 12/15] fix(nightly): pytest --- pandas-stubs/core/indexes/base.pyi | 20 ++++- pandas-stubs/core/series.pyi | 52 +++++++----- tests/indexes/arithmetic/bool/test_mul.py | 29 +++++-- tests/indexes/arithmetic/str/test_mul.py | 24 ++++-- tests/series/arithmetic/bool/test_mul.py | 97 +++++++++++++++++++---- tests/series/arithmetic/str/test_mul.py | 64 ++++++++++----- tests/series/test_series.py | 3 +- 7 files changed, 208 insertions(+), 81 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 1c21dcee8..7b94a5090 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -784,12 +784,18 @@ class Index(IndexOpsMixin[S1]): @overload def __mul__( self: Index[_str], - other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + other: ( + np_ndarray_bool + | np_ndarray_float + | np_ndarray_complex + | np_ndarray_dt + | np_ndarray_td + ), ) -> Never: ... @overload def __mul__( self: Index[_str], - other: int | Sequence[int] | np_ndarray_bool | np_ndarray_anyint | Index[T_INT], + other: Just[int] | Sequence[Just[int]] | np_ndarray_anyint | Index[int], ) -> Index[_str]: ... @overload def __mul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... @@ -868,12 +874,18 @@ class Index(IndexOpsMixin[S1]): @overload def __rmul__( self: Index[_str], - other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + other: ( + np_ndarray_bool + | np_ndarray_float + | np_ndarray_complex + | np_ndarray_dt + | np_ndarray_td + ), ) -> Never: ... @overload def __rmul__( self: Index[_str], - other: int | Sequence[int] | np_ndarray_bool | np_ndarray_anyint | Index[T_INT], + other: Just[int] | Sequence[Just[int]] | np_ndarray_anyint | Index[int], ) -> Index[_str]: ... @overload def __rmul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 5dfb5c907..db3469508 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2585,18 +2585,23 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __mul__( self: Series[_str], - other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + other: ( + np_ndarray_bool + | np_ndarray_float + | np_ndarray_complex + | np_ndarray_dt + | np_ndarray_td + ), ) -> Never: ... @overload def __mul__( self: Series[_str], other: ( - int - | Sequence[int] - | np_ndarray_bool + Just[int] + | Sequence[Just[int]] | np_ndarray_anyint - | Index[T_INT] - | Series[T_INT] + | Index[int] + | Series[int] ), ) -> Series[_str]: ... @overload @@ -2695,12 +2700,11 @@ class Series(IndexOpsMixin[S1], NDFrame): def mul( self: Series[_str], other: ( - int - | Sequence[int] - | np_ndarray_bool + Just[int] + | Sequence[Just[int]] | np_ndarray_anyint - | Index[T_INT] - | Series[T_INT] + | Index[int] + | Series[int] ), level: Level | None = None, fill_value: float | None = None, @@ -2834,18 +2838,23 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __rmul__( self: Series[_str], - other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, + other: ( + np_ndarray_bool + | np_ndarray_float + | np_ndarray_complex + | np_ndarray_dt + | np_ndarray_td + ), ) -> Never: ... @overload def __rmul__( self: Series[_str], other: ( - int - | Sequence[int] - | np_ndarray_bool + Just[int] + | Sequence[Just[int]] | np_ndarray_anyint - | Index[T_INT] - | Series[T_INT] + | Index[int] + | Series[int] ), ) -> Series[_str]: ... @overload @@ -2946,12 +2955,11 @@ class Series(IndexOpsMixin[S1], NDFrame): def rmul( self: Series[_str], other: ( - int - | Sequence[int] - | np_ndarray_bool + Just[int] + | Sequence[Just[int]] | np_ndarray_anyint - | Index[T_INT] - | Series[T_INT] + | Index[int] + | Series[int] ), level: Level | None = None, fill_value: float | None = None, diff --git a/tests/indexes/arithmetic/bool/test_mul.py b/tests/indexes/arithmetic/bool/test_mul.py index 520813303..cd9cfd5a1 100644 --- a/tests/indexes/arithmetic/bool/test_mul.py +++ b/tests/indexes/arithmetic/bool/test_mul.py @@ -14,6 +14,7 @@ ) from tests import ( + PD_LTE_23, TYPE_CHECKING_INVALID_USAGE, check, ) @@ -86,7 +87,10 @@ def test_mul_numpy_array(left: "pd.Index[bool]") -> None: check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: assert_type(left * s, Never) - check(assert_type(left * d, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left * d, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return @@ -101,11 +105,14 @@ def test_mul_numpy_array(left: "pd.Index[bool]") -> None: ) if TYPE_CHECKING_INVALID_USAGE: assert_type(s * left, Any) - check( - assert_type(d * left, "npt.NDArray[np.timedelta64]"), - pd.TimedeltaIndex, - pd.Timedelta, - ) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check( + assert_type(d * left, "npt.NDArray[np.timedelta64]"), + pd.TimedeltaIndex, + pd.Timedelta, + ) def test_mul_pd_index(left: "pd.Index[bool]") -> None: @@ -123,7 +130,10 @@ def test_mul_pd_index(left: "pd.Index[bool]") -> None: check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left * d, pd.TimedeltaIndex), pd.Index, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left * d, pd.TimedeltaIndex), pd.Index, timedelta) check(assert_type(b * left, "pd.Index[bool]"), pd.Index, np.bool_) check(assert_type(i * left, "pd.Index[int]"), pd.Index, np.integer) @@ -131,4 +141,7 @@ def test_mul_pd_index(left: "pd.Index[bool]") -> None: check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(d * left, pd.TimedeltaIndex), pd.Index, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(d * left, pd.TimedeltaIndex), pd.Index, timedelta) diff --git a/tests/indexes/arithmetic/str/test_mul.py b/tests/indexes/arithmetic/str/test_mul.py index c75c07031..795946fe5 100644 --- a/tests/indexes/arithmetic/str/test_mul.py +++ b/tests/indexes/arithmetic/str/test_mul.py @@ -31,7 +31,8 @@ def test_mul_py_scalar(left: "pd.Index[str]") -> None: 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[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -39,7 +40,8 @@ def test_mul_py_scalar(left: "pd.Index[str]") -> None: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -54,7 +56,8 @@ def test_mul_py_sequence(left: "pd.Index[str]") -> None: s = [datetime(2025, 9, d) for d in (27, 28, 29)] d = [timedelta(seconds=s + 1) for s in range(3)] - check(assert_type(left * b, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -62,7 +65,8 @@ def test_mul_py_sequence(left: "pd.Index[str]") -> None: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -80,7 +84,8 @@ def test_mul_numpy_array(left: "pd.Index[str]") -> None: s = np.array([np.datetime64(f"2025-09-{d}") for d in (27, 28, 29)], np.datetime64) d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) - check(assert_type(left * b, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left * b, Never) check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: assert_type(left * f, Never) @@ -91,7 +96,8 @@ def test_mul_numpy_array(left: "pd.Index[str]") -> None: # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return # `Index` with the correct element type. - check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(b * left, "npt.NDArray[np.bool_]") check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: assert_type(f * left, "npt.NDArray[np.float64]") @@ -109,7 +115,8 @@ def test_mul_pd_index(left: "pd.Index[str]") -> None: s = pd.Index([datetime(2025, 9, 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[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -117,7 +124,8 @@ def test_mul_pd_index(left: "pd.Index[str]") -> None: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) + if TYPE_CHECKING_INVALID_USAGE: + _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] diff --git a/tests/series/arithmetic/bool/test_mul.py b/tests/series/arithmetic/bool/test_mul.py index 202b8b04f..023ab5637 100644 --- a/tests/series/arithmetic/bool/test_mul.py +++ b/tests/series/arithmetic/bool/test_mul.py @@ -14,6 +14,7 @@ ) from tests import ( + PD_LTE_23, TYPE_CHECKING_INVALID_USAGE, check, ) @@ -78,7 +79,10 @@ def test_mul_py_sequence(left: "pd.Series[bool]") -> None: check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(i * left, "pd.Series[int]"), pd.Series, np.integer) @@ -86,7 +90,10 @@ def test_mul_py_sequence(left: "pd.Series[bool]") -> None: check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -94,7 +101,10 @@ def test_mul_py_sequence(left: "pd.Series[bool]") -> None: check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -104,7 +114,12 @@ def test_mul_py_sequence(left: "pd.Series[bool]") -> None: ) if TYPE_CHECKING_INVALID_USAGE: left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check( + assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta + ) def test_mul_numpy_array(left: "pd.Series[bool]") -> None: @@ -122,7 +137,10 @@ def test_mul_numpy_array(left: "pd.Series[bool]") -> None: check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: assert_type(left * s, Never) - check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return @@ -137,7 +155,14 @@ def test_mul_numpy_array(left: "pd.Series[bool]") -> None: ) if TYPE_CHECKING_INVALID_USAGE: assert_type(s * left, Any) - check(assert_type(d * left, "npt.NDArray[np.timedelta64]"), pd.Series, pd.Timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check( + assert_type(d * left, "npt.NDArray[np.timedelta64]"), + pd.Series, + pd.Timedelta, + ) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -145,7 +170,12 @@ def test_mul_numpy_array(left: "pd.Series[bool]") -> None: check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check( + assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta + ) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -155,7 +185,14 @@ def test_mul_numpy_array(left: "pd.Series[bool]") -> None: ) if TYPE_CHECKING_INVALID_USAGE: left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check( + assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), + pd.Series, + pd.Timedelta, + ) def test_mul_pd_index(left: "pd.Series[bool]") -> None: @@ -173,7 +210,10 @@ def test_mul_pd_index(left: "pd.Series[bool]") -> None: check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(i * left, "pd.Series[int]"), pd.Series, np.integer) @@ -181,7 +221,10 @@ def test_mul_pd_index(left: "pd.Series[bool]") -> None: check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -189,7 +232,10 @@ def test_mul_pd_index(left: "pd.Series[bool]") -> None: check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -199,7 +245,12 @@ def test_mul_pd_index(left: "pd.Series[bool]") -> None: ) if TYPE_CHECKING_INVALID_USAGE: left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check( + assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta + ) def test_mul_pd_series(left: "pd.Series[bool]") -> None: @@ -217,7 +268,10 @@ def test_mul_pd_series(left: "pd.Series[bool]") -> None: check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(i * left, "pd.Series[int]"), pd.Series, np.integer) @@ -225,7 +279,10 @@ def test_mul_pd_series(left: "pd.Series[bool]") -> None: check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(d * left, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.mul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -233,7 +290,10 @@ def test_mul_pd_series(left: "pd.Series[bool]") -> None: check(assert_type(left.mul(c), "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check(assert_type(left.mul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(left.rmul(b), "pd.Series[bool]"), pd.Series, np.bool_) check(assert_type(left.rmul(i), "pd.Series[int]"), pd.Series, np.integer) @@ -243,4 +303,9 @@ def test_mul_pd_series(left: "pd.Series[bool]") -> None: ) if TYPE_CHECKING_INVALID_USAGE: left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta) + if PD_LTE_23: + # pandas-dev/pandas#62316: both timedelta * bool + # and np.timedelta64 * bool works, so pandas probably also should work + check( + assert_type(left.rmul(d), "pd.Series[pd.Timedelta]"), pd.Series, timedelta + ) diff --git a/tests/series/arithmetic/str/test_mul.py b/tests/series/arithmetic/str/test_mul.py index 722fa5dda..ce90cd40f 100644 --- a/tests/series/arithmetic/str/test_mul.py +++ b/tests/series/arithmetic/str/test_mul.py @@ -31,7 +31,8 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: 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[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -39,7 +40,8 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -47,20 +49,22 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -70,7 +74,8 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: s = [datetime(2025, 9, d) for d in (27, 28, 29)] d = [timedelta(seconds=s + 1) for s in range(3)] - check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -78,7 +83,8 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -86,7 +92,8 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -94,7 +101,8 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -112,7 +120,8 @@ def test_mul_numpy_array(left: "pd.Series[str]") -> None: s = np.array([np.datetime64(f"2025-09-{d}") for d in (27, 28, 29)], np.datetime64) d = np.array([np.timedelta64(s + 1, "s") for s in range(3)], np.timedelta64) - check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(left * b, Never) check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: assert_type(left * f, Never) @@ -123,7 +132,8 @@ def test_mul_numpy_array(left: "pd.Series[str]") -> None: # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return # `Series` with the correct element type. - check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + assert_type(b * left, "npt.NDArray[np.bool_]") check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: assert_type(f * left, "npt.NDArray[np.float64]") @@ -131,7 +141,8 @@ def test_mul_numpy_array(left: "pd.Series[str]") -> None: assert_type(s * left, Any) assert_type(d * left, "npt.NDArray[np.timedelta64]") - check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -139,7 +150,8 @@ def test_mul_numpy_array(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -157,7 +169,8 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: s = pd.Index([datetime(2025, 9, 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.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -165,7 +178,8 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -173,7 +187,8 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -181,7 +196,8 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -199,7 +215,8 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: s = pd.Series([datetime(2025, 9, d) for d in (27, 28, 29)]) d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) - check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -207,7 +224,8 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -215,7 +233,8 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _16 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -223,7 +242,8 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) + if TYPE_CHECKING_INVALID_USAGE: + left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] diff --git a/tests/series/test_series.py b/tests/series/test_series.py index 464390d10..0a9aa85ba 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -3804,7 +3804,8 @@ def test_info() -> None: check(assert_type(s.info(memory_usage="deep"), None), type(None)) check(assert_type(s.info(memory_usage=None), None), type(None)) check(assert_type(s.info(show_counts=True), None), type(None)) - check(assert_type(s.info(show_counts=False), None), type(None)) + if PD_LTE_23: # pandas-dev/pandas#62590 + check(assert_type(s.info(show_counts=False), None), type(None)) check(assert_type(s.info(show_counts=None), None), type(None)) From eba4608a2d3ff939eebd083b79bdd6de149c93cf Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Sun, 5 Oct 2025 19:21:27 +0200 Subject: [PATCH 13/15] chore: naming --- tests/indexes/arithmetic/bool/test_mul.py | 12 ++-- tests/indexes/arithmetic/complex/test_mul.py | 24 ++++---- tests/indexes/arithmetic/float/test_mul.py | 12 ++-- tests/indexes/arithmetic/int/test_mul.py | 12 ++-- tests/indexes/arithmetic/str/test_mul.py | 48 +++++++-------- tests/series/arithmetic/bool/test_mul.py | 16 ++--- tests/series/arithmetic/complex/test_mul.py | 32 +++++----- tests/series/arithmetic/float/test_mul.py | 16 ++--- tests/series/arithmetic/int/test_mul.py | 16 ++--- tests/series/arithmetic/str/test_mul.py | 64 ++++++++++---------- 10 files changed, 126 insertions(+), 126 deletions(-) diff --git a/tests/indexes/arithmetic/bool/test_mul.py b/tests/indexes/arithmetic/bool/test_mul.py index cd9cfd5a1..a68a63ce2 100644 --- a/tests/indexes/arithmetic/bool/test_mul.py +++ b/tests/indexes/arithmetic/bool/test_mul.py @@ -37,7 +37,7 @@ def test_mul_py_scalar(left: "pd.Index[bool]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) check(assert_type(b * left, "pd.Index[bool]"), pd.Index, np.bool_) @@ -45,7 +45,7 @@ def test_mul_py_scalar(left: "pd.Index[bool]") -> None: 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: - _15 = s * 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) @@ -60,7 +60,7 @@ def test_mul_py_sequence(left: "pd.Index[bool]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) check(assert_type(b * left, "pd.Index[bool]"), pd.Index, np.bool_) @@ -68,7 +68,7 @@ def test_mul_py_sequence(left: "pd.Index[bool]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) @@ -129,7 +129,7 @@ def test_mul_pd_index(left: "pd.Index[bool]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if PD_LTE_23: # pandas-dev/pandas#62316: both timedelta * bool # and np.timedelta64 * bool works, so pandas probably also should work @@ -140,7 +140,7 @@ def test_mul_pd_index(left: "pd.Index[bool]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if PD_LTE_23: # pandas-dev/pandas#62316: both timedelta * bool # and np.timedelta64 * bool works, so pandas probably also should work diff --git a/tests/indexes/arithmetic/complex/test_mul.py b/tests/indexes/arithmetic/complex/test_mul.py index 7d5fe84a5..136d4824b 100644 --- a/tests/indexes/arithmetic/complex/test_mul.py +++ b/tests/indexes/arithmetic/complex/test_mul.py @@ -36,16 +36,16 @@ def test_mul_py_scalar(left: "pd.Index[complex]") -> None: check(assert_type(left * f, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # 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[complex]"), pd.Index, np.complexfloating) check(assert_type(i * left, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(f * left, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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_mul_py_sequence(left: "pd.Index[complex]") -> None: @@ -59,16 +59,16 @@ def test_mul_py_sequence(left: "pd.Index[complex]") -> None: check(assert_type(left * f, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # 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[complex]"), pd.Index, np.complexfloating) check(assert_type(i * left, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(f * left, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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_mul_numpy_array(left: "pd.Index[complex]") -> None: @@ -120,13 +120,13 @@ def test_mul_pd_index(left: "pd.Index[complex]") -> None: check(assert_type(left * f, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(left * c, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # 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[complex]"), pd.Index, np.complexfloating) check(assert_type(i * left, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(f * left, "pd.Index[complex]"), pd.Index, np.complexfloating) check(assert_type(c * left, "pd.Index[complex]"), pd.Index, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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] diff --git a/tests/indexes/arithmetic/float/test_mul.py b/tests/indexes/arithmetic/float/test_mul.py index db4a24608..45a1587e9 100644 --- a/tests/indexes/arithmetic/float/test_mul.py +++ b/tests/indexes/arithmetic/float/test_mul.py @@ -36,7 +36,7 @@ def test_mul_py_scalar(left: "pd.Index[float]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.TimedeltaIndex"), pd.TimedeltaIndex, timedelta) check(assert_type(b * left, "pd.Index[float]"), pd.Index, np.floating) @@ -44,7 +44,7 @@ def test_mul_py_scalar(left: "pd.Index[float]") -> None: 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: - _15 = s * 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, timedelta) @@ -59,7 +59,7 @@ def test_mul_py_sequence(left: "pd.Index[float]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) check(assert_type(b * left, "pd.Index[float]"), pd.Index, np.floating) @@ -67,7 +67,7 @@ def test_mul_py_sequence(left: "pd.Index[float]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) @@ -122,7 +122,7 @@ def test_mul_pd_index(left: "pd.Index[float]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, pd.TimedeltaIndex), pd.TimedeltaIndex, pd.Timedelta) check(assert_type(b * left, "pd.Index[float]"), pd.Index, np.floating) @@ -130,5 +130,5 @@ def test_mul_pd_index(left: "pd.Index[float]") -> None: 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: - _15 = s * 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_mul.py b/tests/indexes/arithmetic/int/test_mul.py index 68a722678..69c49cad9 100644 --- a/tests/indexes/arithmetic/int/test_mul.py +++ b/tests/indexes/arithmetic/int/test_mul.py @@ -36,7 +36,7 @@ def test_mul_py_scalar(left: "pd.Index[int]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, pd.TimedeltaIndex), pd.Index, pd.Timedelta) check(assert_type(b * left, "pd.Index[int]"), pd.Index, np.integer) @@ -44,7 +44,7 @@ def test_mul_py_scalar(left: "pd.Index[int]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d * left, pd.TimedeltaIndex), pd.Index, pd.Timedelta) @@ -59,7 +59,7 @@ def test_mul_py_sequence(left: "pd.Index[int]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] # pandas-dev/pandas#62524: An index of Python native timedeltas can be # produced, instead of a TimedeltaIndex, hence the test check(assert_type(left * d, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) @@ -69,7 +69,7 @@ def test_mul_py_sequence(left: "pd.Index[int]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] # pandas-dev/pandas#62524: An index of Python native timedeltas can be # produced, instead of a TimedeltaIndex, hence the test check(assert_type(d * left, "pd.Index[pd.Timedelta]"), pd.Index, timedelta) @@ -122,7 +122,7 @@ def test_mul_pd_index(left: "pd.Index[int]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, pd.TimedeltaIndex), pd.Index, pd.Timedelta) check(assert_type(b * left, "pd.Index[int]"), pd.Index, np.integer) @@ -130,5 +130,5 @@ def test_mul_pd_index(left: "pd.Index[int]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(d * left, pd.TimedeltaIndex), pd.Index, pd.Timedelta) diff --git a/tests/indexes/arithmetic/str/test_mul.py b/tests/indexes/arithmetic/str/test_mul.py index 795946fe5..bc3aade00 100644 --- a/tests/indexes/arithmetic/str/test_mul.py +++ b/tests/indexes/arithmetic/str/test_mul.py @@ -35,19 +35,19 @@ def test_mul_py_scalar(left: "pd.Index[str]") -> None: _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: - _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _02 = left * f # 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] if TYPE_CHECKING_INVALID_USAGE: _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: - _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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] + _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] def test_mul_py_sequence(left: "pd.Index[str]") -> None: @@ -60,19 +60,19 @@ def test_mul_py_sequence(left: "pd.Index[str]") -> None: _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: - _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _02 = left * f # 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] if TYPE_CHECKING_INVALID_USAGE: _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: - _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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] + _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] def test_mul_numpy_array(left: "pd.Index[str]") -> None: @@ -119,16 +119,16 @@ def test_mul_pd_index(left: "pd.Index[str]") -> None: _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: - _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _02 = left * f # 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] if TYPE_CHECKING_INVALID_USAGE: _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: - _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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] + _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] diff --git a/tests/series/arithmetic/bool/test_mul.py b/tests/series/arithmetic/bool/test_mul.py index 023ab5637..d781e0d8d 100644 --- a/tests/series/arithmetic/bool/test_mul.py +++ b/tests/series/arithmetic/bool/test_mul.py @@ -37,7 +37,7 @@ def test_mul_py_scalar(left: "pd.Series[bool]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(b * left, "pd.Series[bool]"), pd.Series, np.bool_) @@ -45,7 +45,7 @@ def test_mul_py_scalar(left: "pd.Series[bool]") -> None: 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: - _15 = s * 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) check(assert_type(left.mul(b), "pd.Series[bool]"), pd.Series, np.bool_) @@ -78,7 +78,7 @@ def test_mul_py_sequence(left: "pd.Series[bool]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if PD_LTE_23: # pandas-dev/pandas#62316: both timedelta * bool # and np.timedelta64 * bool works, so pandas probably also should work @@ -89,7 +89,7 @@ def test_mul_py_sequence(left: "pd.Series[bool]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if PD_LTE_23: # pandas-dev/pandas#62316: both timedelta * bool # and np.timedelta64 * bool works, so pandas probably also should work @@ -209,7 +209,7 @@ def test_mul_pd_index(left: "pd.Series[bool]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if PD_LTE_23: # pandas-dev/pandas#62316: both timedelta * bool # and np.timedelta64 * bool works, so pandas probably also should work @@ -220,7 +220,7 @@ def test_mul_pd_index(left: "pd.Series[bool]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if PD_LTE_23: # pandas-dev/pandas#62316: both timedelta * bool # and np.timedelta64 * bool works, so pandas probably also should work @@ -267,7 +267,7 @@ def test_mul_pd_series(left: "pd.Series[bool]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if PD_LTE_23: # pandas-dev/pandas#62316: both timedelta * bool # and np.timedelta64 * bool works, so pandas probably also should work @@ -278,7 +278,7 @@ def test_mul_pd_series(left: "pd.Series[bool]") -> None: 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: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if PD_LTE_23: # pandas-dev/pandas#62316: both timedelta * bool # and np.timedelta64 * bool works, so pandas probably also should work diff --git a/tests/series/arithmetic/complex/test_mul.py b/tests/series/arithmetic/complex/test_mul.py index 72402c91b..b997b4d3b 100644 --- a/tests/series/arithmetic/complex/test_mul.py +++ b/tests/series/arithmetic/complex/test_mul.py @@ -36,16 +36,16 @@ def test_mul_py_scalar(left: "pd.Series[complex]") -> None: check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # 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.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(i * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(f * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) @@ -83,16 +83,16 @@ def test_mul_py_sequence(left: "pd.Series[complex]") -> None: check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # 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.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(i * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(f * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) @@ -192,16 +192,16 @@ def test_mul_pd_index(left: "pd.Series[complex]") -> None: check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # 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.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(i * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(f * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) @@ -242,16 +242,16 @@ def test_mul_pd_series(left: "pd.Series[complex]") -> None: check(assert_type(left * f, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left * c, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # 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.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(i * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(f * left, "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(c * left, "pd.Series[complex]"), pd.Series, np.complexfloating) if TYPE_CHECKING_INVALID_USAGE: - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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(left.mul(b), "pd.Series[complex]"), pd.Series, np.complexfloating) check(assert_type(left.mul(i), "pd.Series[complex]"), pd.Series, np.complexfloating) diff --git a/tests/series/arithmetic/float/test_mul.py b/tests/series/arithmetic/float/test_mul.py index ac7d8e2e9..ae320658b 100644 --- a/tests/series/arithmetic/float/test_mul.py +++ b/tests/series/arithmetic/float/test_mul.py @@ -36,7 +36,7 @@ def test_mul_py_scalar(left: "pd.Series[float]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[float]"), pd.Series, np.floating) @@ -44,7 +44,7 @@ def test_mul_py_scalar(left: "pd.Series[float]") -> None: 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: - _15 = s * 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, timedelta) check(assert_type(left.mul(b), "pd.Series[float]"), pd.Series, np.floating) @@ -77,7 +77,7 @@ def test_mul_py_sequence(left: "pd.Series[float]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[float]"), pd.Series, np.floating) @@ -85,7 +85,7 @@ def test_mul_py_sequence(left: "pd.Series[float]") -> None: 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: - _15 = s * 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, timedelta) check(assert_type(left.mul(b), "pd.Series[float]"), pd.Series, np.floating) @@ -172,7 +172,7 @@ def test_mul_pd_index(left: "pd.Series[float]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(b * left, "pd.Series[float]"), pd.Series, np.floating) @@ -180,7 +180,7 @@ def test_mul_pd_index(left: "pd.Series[float]") -> None: 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: - _15 = s * 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) check(assert_type(left.mul(b), "pd.Series[float]"), pd.Series, np.floating) @@ -216,7 +216,7 @@ def test_mul_pd_series(left: "pd.Series[float]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(b * left, "pd.Series[float]"), pd.Series, np.floating) @@ -224,7 +224,7 @@ def test_mul_pd_series(left: "pd.Series[float]") -> None: 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: - _15 = s * 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) check(assert_type(left.mul(b), "pd.Series[float]"), pd.Series, np.floating) diff --git a/tests/series/arithmetic/int/test_mul.py b/tests/series/arithmetic/int/test_mul.py index f5a75db46..030adfc98 100644 --- a/tests/series/arithmetic/int/test_mul.py +++ b/tests/series/arithmetic/int/test_mul.py @@ -36,7 +36,7 @@ def test_mul_py_scalar(left: "pd.Series[int]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(b * left, "pd.Series[int]"), pd.Series, np.integer) @@ -44,7 +44,7 @@ def test_mul_py_scalar(left: "pd.Series[int]") -> None: 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: - _15 = s * 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) check(assert_type(left.mul(b), "pd.Series[int]"), pd.Series, np.integer) @@ -77,7 +77,7 @@ def test_mul_py_sequence(left: "pd.Series[int]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, timedelta) check(assert_type(b * left, "pd.Series[int]"), pd.Series, np.integer) @@ -85,7 +85,7 @@ def test_mul_py_sequence(left: "pd.Series[int]") -> None: 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: - _15 = s * 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, timedelta) check(assert_type(left.mul(b), "pd.Series[int]"), pd.Series, np.integer) @@ -172,7 +172,7 @@ def test_mul_pd_index(left: "pd.Series[int]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(b * left, "pd.Series[int]"), pd.Series, np.integer) @@ -180,7 +180,7 @@ def test_mul_pd_index(left: "pd.Series[int]") -> None: 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: - _15 = s * 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) check(assert_type(left.mul(b), "pd.Series[int]"), pd.Series, np.integer) @@ -216,7 +216,7 @@ def test_mul_pd_series(left: "pd.Series[int]") -> None: 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: - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * d, "pd.Series[pd.Timedelta]"), pd.Series, pd.Timedelta) check(assert_type(b * left, "pd.Series[int]"), pd.Series, np.integer) @@ -224,7 +224,7 @@ def test_mul_pd_series(left: "pd.Series[int]") -> None: 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: - _15 = s * 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) check(assert_type(left.mul(b), "pd.Series[int]"), pd.Series, np.integer) diff --git a/tests/series/arithmetic/str/test_mul.py b/tests/series/arithmetic/str/test_mul.py index ce90cd40f..1d562db75 100644 --- a/tests/series/arithmetic/str/test_mul.py +++ b/tests/series/arithmetic/str/test_mul.py @@ -35,19 +35,19 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _02 = left * f # 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] if TYPE_CHECKING_INVALID_USAGE: _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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] + _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if TYPE_CHECKING_INVALID_USAGE: left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -78,19 +78,19 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _02 = left * f # 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] if TYPE_CHECKING_INVALID_USAGE: _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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] + _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if TYPE_CHECKING_INVALID_USAGE: left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -173,19 +173,19 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _02 = left * f # 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] if TYPE_CHECKING_INVALID_USAGE: _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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] + _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if TYPE_CHECKING_INVALID_USAGE: left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -219,19 +219,19 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - _03 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _04 = left * c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _05 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _06 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + _02 = left * f # 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] if TYPE_CHECKING_INVALID_USAGE: _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: - _13 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _14 = c * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _15 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - _16 = d * 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] + _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if TYPE_CHECKING_INVALID_USAGE: left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] From 5da6b1cd9b17b7fb84c836bda9096e101c8ce8db Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 6 Oct 2025 22:03:50 +0200 Subject: [PATCH 14/15] fix(comment): pandas-dev/pandas#62595 https://github.com/pandas-dev/pandas-stubs/pull/1397#discussion_r2404737078 --- pandas-stubs/core/indexes/base.pyi | 38 ++++++----- pandas-stubs/core/series.pyi | 52 +++++++++------ tests/indexes/arithmetic/str/test_mul.py | 41 +++++++----- tests/series/arithmetic/str/test_mul.py | 85 +++++++++++++----------- 4 files changed, 125 insertions(+), 91 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 7b94a5090..b41353ef4 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -784,18 +784,21 @@ class Index(IndexOpsMixin[S1]): @overload def __mul__( self: Index[_str], - other: ( - np_ndarray_bool - | np_ndarray_float - | np_ndarray_complex - | np_ndarray_dt - | np_ndarray_td - ), + other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, ) -> Never: ... + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x @overload def __mul__( self: Index[_str], - other: Just[int] | Sequence[Just[int]] | np_ndarray_anyint | Index[int], + other: ( + int + | Sequence[int] + | np_ndarray_bool + | np_ndarray_anyint + | Index[bool] + | Index[int] + ), ) -> Index[_str]: ... @overload def __mul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... @@ -874,18 +877,21 @@ class Index(IndexOpsMixin[S1]): @overload def __rmul__( self: Index[_str], - other: ( - np_ndarray_bool - | np_ndarray_float - | np_ndarray_complex - | np_ndarray_dt - | np_ndarray_td - ), + other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, ) -> Never: ... + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x @overload def __rmul__( self: Index[_str], - other: Just[int] | Sequence[Just[int]] | np_ndarray_anyint | Index[int], + other: ( + int + | Sequence[int] + | np_ndarray_bool + | np_ndarray_anyint + | Index[bool] + | Index[int] + ), ) -> Index[_str]: ... @overload def __rmul__(self: Index[T_INT], other: bool | Sequence[bool]) -> Index[T_INT]: ... diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index db3469508..a0513eaf4 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2585,22 +2585,21 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __mul__( self: Series[_str], - other: ( - np_ndarray_bool - | np_ndarray_float - | np_ndarray_complex - | np_ndarray_dt - | np_ndarray_td - ), + other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, ) -> Never: ... + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x @overload def __mul__( self: Series[_str], other: ( - Just[int] - | Sequence[Just[int]] + int + | Sequence[int] + | np_ndarray_bool | np_ndarray_anyint + | Index[bool] | Index[int] + | Series[bool] | Series[int] ), ) -> Series[_str]: ... @@ -2696,14 +2695,19 @@ class Series(IndexOpsMixin[S1], NDFrame): fill_value: float | None = None, axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x @overload def mul( self: Series[_str], other: ( - Just[int] - | Sequence[Just[int]] + int + | Sequence[int] + | np_ndarray_bool | np_ndarray_anyint + | Index[bool] | Index[int] + | Series[bool] | Series[int] ), level: Level | None = None, @@ -2838,22 +2842,21 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __rmul__( self: Series[_str], - other: ( - np_ndarray_bool - | np_ndarray_float - | np_ndarray_complex - | np_ndarray_dt - | np_ndarray_td - ), + other: np_ndarray_float | np_ndarray_complex | np_ndarray_dt | np_ndarray_td, ) -> Never: ... + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x @overload def __rmul__( self: Series[_str], other: ( - Just[int] - | Sequence[Just[int]] + int + | Sequence[int] + | np_ndarray_bool | np_ndarray_anyint + | Index[bool] | Index[int] + | Series[bool] | Series[int] ), ) -> Series[_str]: ... @@ -2951,14 +2954,19 @@ class Series(IndexOpsMixin[S1], NDFrame): fill_value: float | None = None, axis: AxisIndex | None = 0, ) -> Series[Timedelta]: ... + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x @overload def rmul( self: Series[_str], other: ( - Just[int] - | Sequence[Just[int]] + int + | Sequence[int] + | np_ndarray_bool | np_ndarray_anyint + | Index[bool] | Index[int] + | Series[bool] | Series[int] ), level: Level | None = None, diff --git a/tests/indexes/arithmetic/str/test_mul.py b/tests/indexes/arithmetic/str/test_mul.py index bc3aade00..2f1b45bfd 100644 --- a/tests/indexes/arithmetic/str/test_mul.py +++ b/tests/indexes/arithmetic/str/test_mul.py @@ -14,6 +14,7 @@ ) from tests import ( + PD_LTE_23, TYPE_CHECKING_INVALID_USAGE, check, ) @@ -31,8 +32,10 @@ def test_mul_py_scalar(left: "pd.Index[str]") -> None: b, i, f, c = True, 1, 1.0, 1j s, d = datetime(2025, 9, 27), timedelta(seconds=1) - if TYPE_CHECKING_INVALID_USAGE: - _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x + if PD_LTE_23: + check(assert_type(left * b, "pd.Index[str]"), pd.Index, str) check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -40,8 +43,8 @@ def test_mul_py_scalar(left: "pd.Index[str]") -> None: _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + if PD_LTE_23: + check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -56,8 +59,10 @@ def test_mul_py_sequence(left: "pd.Index[str]") -> None: s = [datetime(2025, 9, d) for d in (27, 28, 29)] d = [timedelta(seconds=s + 1) for s in range(3)] - if TYPE_CHECKING_INVALID_USAGE: - _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x + if PD_LTE_23: + check(assert_type(left * b, "pd.Index[str]"), pd.Index, str) check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -65,8 +70,8 @@ def test_mul_py_sequence(left: "pd.Index[str]") -> None: _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + if PD_LTE_23: + check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -84,8 +89,10 @@ def test_mul_numpy_array(left: "pd.Index[str]") -> None: s = np.array([np.datetime64(f"2025-09-{d}") for d in (27, 28, 29)], 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) + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x + if PD_LTE_23: + check(assert_type(left * b, "pd.Index[str]"), pd.Index, str) check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: assert_type(left * f, Never) @@ -96,8 +103,8 @@ def test_mul_numpy_array(left: "pd.Index[str]") -> None: # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return # `Index` with the correct element type. - if TYPE_CHECKING_INVALID_USAGE: - assert_type(b * left, "npt.NDArray[np.bool_]") + if PD_LTE_23: + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Index, str) check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: assert_type(f * left, "npt.NDArray[np.float64]") @@ -115,8 +122,10 @@ def test_mul_pd_index(left: "pd.Index[str]") -> None: s = pd.Index([datetime(2025, 9, d) for d in (27, 28, 29)]) d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) - if TYPE_CHECKING_INVALID_USAGE: - _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x + if PD_LTE_23: + check(assert_type(left * b, "pd.Index[str]"), pd.Index, str) check(assert_type(left * i, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -124,8 +133,8 @@ def test_mul_pd_index(left: "pd.Index[str]") -> None: _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + if PD_LTE_23: + check(assert_type(b * left, "pd.Index[str]"), pd.Index, str) check(assert_type(i * left, "pd.Index[str]"), pd.Index, str) if TYPE_CHECKING_INVALID_USAGE: _12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] diff --git a/tests/series/arithmetic/str/test_mul.py b/tests/series/arithmetic/str/test_mul.py index 1d562db75..e07836e8a 100644 --- a/tests/series/arithmetic/str/test_mul.py +++ b/tests/series/arithmetic/str/test_mul.py @@ -14,6 +14,7 @@ ) from tests import ( + PD_LTE_23, TYPE_CHECKING_INVALID_USAGE, check, ) @@ -31,8 +32,10 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: b, i, f, c = True, 1, 1.0, 1j s, d = datetime(2025, 9, 27), timedelta(seconds=1) - if TYPE_CHECKING_INVALID_USAGE: - _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x + if PD_LTE_23: + check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -40,8 +43,8 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + if PD_LTE_23: + check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -49,8 +52,8 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -58,8 +61,8 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - if TYPE_CHECKING_INVALID_USAGE: - left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -74,8 +77,10 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: s = [datetime(2025, 9, d) for d in (27, 28, 29)] d = [timedelta(seconds=s + 1) for s in range(3)] - if TYPE_CHECKING_INVALID_USAGE: - _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x + if PD_LTE_23: + check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -83,8 +88,8 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + if PD_LTE_23: + check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -92,8 +97,8 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -101,8 +106,8 @@ def test_mul_py_sequence(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - if TYPE_CHECKING_INVALID_USAGE: - left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -120,8 +125,10 @@ def test_mul_numpy_array(left: "pd.Series[str]") -> None: s = np.array([np.datetime64(f"2025-09-{d}") for d in (27, 28, 29)], 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) + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x + if PD_LTE_23: + check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: assert_type(left * f, Never) @@ -132,8 +139,8 @@ def test_mul_numpy_array(left: "pd.Series[str]") -> None: # `numpy` typing gives the corresponding `ndarray`s in the static type # checking, where our `__rmul__` cannot override. At runtime, they return # `Series` with the correct element type. - if TYPE_CHECKING_INVALID_USAGE: - assert_type(b * left, "npt.NDArray[np.bool_]") + if PD_LTE_23: + check(assert_type(b * left, "npt.NDArray[np.bool_]"), pd.Series, str) check(assert_type(i * left, "npt.NDArray[np.int64]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: assert_type(f * left, "npt.NDArray[np.float64]") @@ -141,8 +148,8 @@ def test_mul_numpy_array(left: "pd.Series[str]") -> None: assert_type(s * left, Any) assert_type(d * left, "npt.NDArray[np.timedelta64]") - if TYPE_CHECKING_INVALID_USAGE: - left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -150,8 +157,8 @@ def test_mul_numpy_array(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - if TYPE_CHECKING_INVALID_USAGE: - left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -169,8 +176,10 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: s = pd.Index([datetime(2025, 9, d) for d in (27, 28, 29)]) d = pd.Index([timedelta(seconds=s + 1) for s in range(3)]) + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x if TYPE_CHECKING_INVALID_USAGE: - _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -179,7 +188,7 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: _05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if TYPE_CHECKING_INVALID_USAGE: - _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -188,7 +197,7 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] if TYPE_CHECKING_INVALID_USAGE: - left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -196,8 +205,8 @@ def test_mul_pd_index(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - if TYPE_CHECKING_INVALID_USAGE: - left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -215,8 +224,10 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: s = pd.Series([datetime(2025, 9, d) for d in (27, 28, 29)]) d = pd.Series([timedelta(seconds=s + 1) for s in range(3)]) - if TYPE_CHECKING_INVALID_USAGE: - _00 = left * b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + # pandas-dev/pandas#62595: we may want to support Series[str] * bool + # also in 3.x + if PD_LTE_23: + check(assert_type(left * b, "pd.Series[str]"), pd.Series, str) check(assert_type(left * i, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _02 = left * f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -224,8 +235,8 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: _04 = left * s # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _05 = left * d # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - _10 = b * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] + if PD_LTE_23: + check(assert_type(b * left, "pd.Series[str]"), pd.Series, str) check(assert_type(i * left, "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: _12 = f * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -233,8 +244,8 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: _14 = s * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] _15 = d * left # type: ignore[operator] # pyright: ignore[reportOperatorIssue] - if TYPE_CHECKING_INVALID_USAGE: - left.mul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.mul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.mul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] @@ -242,8 +253,8 @@ def test_mul_pd_series(left: "pd.Series[str]") -> None: left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - if TYPE_CHECKING_INVALID_USAGE: - left.rmul(b) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + if PD_LTE_23: + check(assert_type(left.rmul(b), "pd.Series[str]"), pd.Series, str) check(assert_type(left.rmul(i), "pd.Series[str]"), pd.Series, str) if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] From 7d7e4019b13b7eb44baf334c0ce2171f90d57f3a Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 6 Oct 2025 22:10:01 +0200 Subject: [PATCH 15/15] fix: mypy --- tests/series/arithmetic/str/test_mul.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/series/arithmetic/str/test_mul.py b/tests/series/arithmetic/str/test_mul.py index e07836e8a..2d7d60efc 100644 --- a/tests/series/arithmetic/str/test_mul.py +++ b/tests/series/arithmetic/str/test_mul.py @@ -58,7 +58,7 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: if TYPE_CHECKING_INVALID_USAGE: left.mul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.mul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.mul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] left.mul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] if PD_LTE_23: @@ -67,7 +67,7 @@ def test_mul_py_scalar(left: "pd.Series[str]") -> None: if TYPE_CHECKING_INVALID_USAGE: left.rmul(f) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] left.rmul(c) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] - left.rmul(s) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue] + left.rmul(s) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] left.rmul(d) # type: ignore[arg-type] # pyright: ignore[reportArgumentType,reportCallIssue]