Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 17 additions & 45 deletions pandas-stubs/core/series.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3823,6 +3823,23 @@ class Series(IndexOpsMixin[S1], NDFrame):
*args: Any,
**kwargs: Any,
) -> Series[S1]: ...
@overload
def cumprod(
self: Series[Never],
axis: AxisIndex = ...,
skipna: _bool = ...,
*args: Any,
**kwargs: Any,
) -> Series: ...
@overload
def cumprod(
self: Series[bool],
axis: AxisIndex = ...,
skipna: _bool = ...,
*args: Any,
**kwargs: Any,
) -> Series[int]: ...
@overload
def cumprod(
self: SupportsGetItem[Scalar, _SupportsMul[S1]],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that work with classes that have overloads for __mul__? My understanding from microsoft/pyright#6549 (comment) is that type checkers will then pick the first overload. It might be okay in this case (and I wish we could use this pattern!) - just something to be aware of when using this patterns in more places.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure that it would matter, because S1 are types we define in pandas as well as fundamental types (int, float, etc.), so I think we will be fine. It's a bit different than the case you wrote up, because of the use of _SupportsMul[S1] requiring the type that supports __mul__() to be in S1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I with this pattern can help us saving efforts, too.

  • Note that there are already SupportsAdd and SupportsMul in _typeshed. They are however different somehow from our _SupportsAdd and _SupportsMul. We probably need a renaming in the near future.
  • It would be great if we could work out a pattern that deal with typing changes like A.__operate__(B) ->B and A.__operate__(A) -> B, for example bool + int -> int, int / int -> float.

axis: AxisIndex = ...,
Expand Down Expand Up @@ -4240,51 +4257,6 @@ class _SeriesSubclassBase(Series[S1], Generic[S1, GenericT_co]):
**kwargs,
) -> np_1darray: ...

class TimestampSeries(_SeriesSubclassBase[Timestamp, np.datetime64]):
@property
def dt(self) -> TimestampProperties: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
def __add__(self, other: TimedeltaSeries | np.timedelta64 | timedelta | BaseOffset) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
def __radd__(self, other: TimedeltaSeries | np.timedelta64 | timedelta) -> TimestampSeries: ... # type: ignore[override]
@overload # type: ignore[override]
def __sub__(
self, other: Timestamp | datetime | TimestampSeries
) -> TimedeltaSeries: ...
@overload
def __sub__( # pyright: ignore[reportIncompatibleMethodOverride]
self,
other: (
timedelta | TimedeltaSeries | TimedeltaIndex | np.timedelta64 | BaseOffset
),
) -> TimestampSeries: ...
def __mul__(self, other: float | Series[int] | Series[float] | Sequence[float]) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
def __truediv__(self, other: float | Series[int] | Series[float] | Sequence[float]) -> TimestampSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
def unique(self) -> DatetimeArray: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
def mean( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
self,
axis: AxisIndex | None = 0,
skipna: _bool = ...,
level: None = ...,
numeric_only: _bool = ...,
**kwargs: Any,
) -> Timestamp: ...
def median( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
self,
axis: AxisIndex | None = 0,
skipna: _bool = ...,
level: None = ...,
numeric_only: _bool = ...,
**kwargs: Any,
) -> Timestamp: ...
def std( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
self,
axis: AxisIndex | None = 0,
skipna: _bool | None = ...,
ddof: int = ...,
numeric_only: _bool = ...,
**kwargs: Any,
) -> Timedelta: ...
def diff(self, periods: int = ...) -> TimedeltaSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]

class TimedeltaSeries(_SeriesSubclassBase[Timedelta, np.timedelta64]):
# ignores needed because of mypy
@overload # type: ignore[override]
Expand Down
51 changes: 51 additions & 0 deletions tests/series/test_cumul.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import numpy as np
import pandas as pd
from typing_extensions import assert_type

from tests import (
TYPE_CHECKING_INVALID_USAGE,
check,
)


def test_cumul_any_int() -> None:
series = pd.DataFrame({"A": [1.0, float("nan"), 2.0]})["A"]
check(assert_type(series.cumprod(), pd.Series), pd.Series, np.floating)


def test_cumul_bool() -> None:
series = pd.Series([True, False, True])
check(assert_type(series.cumprod(), "pd.Series[int]"), pd.Series, np.integer)


def test_cumul_int() -> None:
series = pd.Series([3, 1, 2])
check(assert_type(series.cumprod(), "pd.Series[int]"), pd.Series, np.integer)


def test_cumul_float() -> None:
series = pd.Series([3.0, float("nan"), 2.0])
check(assert_type(series.cumprod(), "pd.Series[float]"), pd.Series, np.floating)


def test_cumul_complex() -> None:
series = pd.Series([3j, 3 + 4j, 2j])
check(
assert_type(series.cumprod(), "pd.Series[complex]"),
pd.Series,
np.complexfloating,
)


def test_cumul_str() -> None:
series = pd.Series(["1", "a", "🐼"])
if TYPE_CHECKING_INVALID_USAGE:
series.cumprod() # type: ignore[misc] # pyright: ignore[reportAttributeAccessIssue]


def test_cumul_ts() -> None:
series = pd.Series(pd.to_datetime(["2025-09-18", "2025-09-18", "2025-09-18"]))
check(assert_type(series, "pd.Series[pd.Timestamp]"), pd.Series, pd.Timestamp)

if TYPE_CHECKING_INVALID_USAGE:
series.cumprod() # type: ignore[misc] # pyright: ignore[reportAttributeAccessIssue]
Empty file removed tests/series/window/__init__.py
Empty file.
11 changes: 0 additions & 11 deletions tests/series/window/test_window_any.py

This file was deleted.

15 changes: 0 additions & 15 deletions tests/series/window/test_window_complex.py

This file was deleted.

11 changes: 0 additions & 11 deletions tests/series/window/test_window_float.py

This file was deleted.

11 changes: 0 additions & 11 deletions tests/series/window/test_window_int.py

This file was deleted.

10 changes: 0 additions & 10 deletions tests/series/window/test_window_str.py

This file was deleted.

Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.