From fdf2d3cacec305ec31d56d82f7d3dffe72d58658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Diridollou?= Date: Fri, 27 Jun 2025 21:51:04 -0400 Subject: [PATCH 1/2] GH1264 Version 2.0 cleanup --- pandas-stubs/core/indexes/base.pyi | 12 +++++++++--- pandas-stubs/core/indexes/multi.pyi | 2 +- pandas-stubs/core/series.pyi | 7 +++++++ tests/test_indexes.py | 25 +++++++++++++++++++++++++ tests/test_series.py | 5 +++++ 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index b33240c0..b65ac0fc 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -347,11 +347,16 @@ class Index(IndexOpsMixin[S1]): def __neg__(self) -> Self: ... def __nonzero__(self) -> None: ... __bool__ = ... - def union(self, other: list[HashableT] | Index, sort=...) -> Index: ... - def intersection(self, other: list[S1] | Self, sort: bool = ...) -> Self: ... + def union( + self, other: list[HashableT] | Index, sort: bool | None = ... + ) -> Index: ... + def intersection(self, other: list[S1] | Self, sort: bool | None = ...) -> Self: ... def difference(self, other: list | Index, sort: bool | None = None) -> Self: ... def symmetric_difference( - self, other: list[S1] | Self, result_name: Hashable = ..., sort=... + self, + other: list[S1] | Self, + result_name: Hashable = ..., + sort: bool | None = ..., ) -> Self: ... def get_loc( self, @@ -472,5 +477,6 @@ class Index(IndexOpsMixin[S1]): | Sequence[float] ), ) -> Self: ... + def infer_objects(self, copy: bool = ...) -> Self: ... UnknownIndex: TypeAlias = Index[Any] diff --git a/pandas-stubs/core/indexes/multi.pyi b/pandas-stubs/core/indexes/multi.pyi index 8a017d82..69457d21 100644 --- a/pandas-stubs/core/indexes/multi.pyi +++ b/pandas-stubs/core/indexes/multi.pyi @@ -155,7 +155,7 @@ class MultiIndex(Index): def equal_levels(self, other): ... def union(self, other, sort=...): ... # pyrefly: ignore def intersection( # pyright: ignore[reportIncompatibleMethodOverride] - self, other: list | Self, sort: bool = ... + self, other: list | Self, sort: bool | None = ... ): ... def difference(self, other, sort=...): ... def astype(self, dtype: DtypeArg, copy: bool = ...) -> Self: ... diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 57fe5f04..cc102d10 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -2324,6 +2324,13 @@ class TimedeltaSeries(Series[Timedelta]): *args: Any, **kwargs: Any, ) -> TimedeltaSeries: ... + def cumprod( + self, + axis: AxisIndex | None = ..., + skipna: _bool = ..., + *args: Any, + **kwargs: Any, + ) -> Never: ... class PeriodSeries(Series[Period]): @property diff --git a/tests/test_indexes.py b/tests/test_indexes.py index 2b448075..6aa11b80 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -172,6 +172,10 @@ def test_difference_none() -> None: # GH 253 check(assert_type(ind.difference([1]), "pd.Index[int]"), pd.Index) + # check with sort parameter + check(assert_type(ind.difference([1, None], sort=False), "pd.Index[int]"), pd.Index) + check(assert_type(ind.difference([1], sort=True), "pd.Index[int]"), pd.Index) + def test_str_split() -> None: # GH 194 @@ -312,6 +316,20 @@ def test_range_index_union(): ), pd.Index, ) + check( + assert_type( + pd.RangeIndex(0, 10).union(["a", "b", "c"], sort=True), + Union[pd.Index, "pd.Index[int]", pd.RangeIndex], + ), + pd.Index, + ) + check( + assert_type( + pd.RangeIndex(0, 10).union(["a", "b", "c"], sort=False), + Union[pd.Index, "pd.Index[int]", pd.RangeIndex], + ), + pd.Index, + ) def test_range_index_start_stop_step(): @@ -1361,3 +1379,10 @@ def test_index_dict() -> None: ), pd.TimedeltaIndex, ) + + +def test_index_infer_objects() -> None: + """Test infer_objects method on Index.""" + df = pd.DataFrame({"A": ["a", 1, 2, 3]}) + idx = df.set_index("A").index[1:] + check(assert_type(idx.infer_objects(), pd.Index), pd.Index) diff --git a/tests/test_series.py b/tests/test_series.py index b71f6498..b622da02 100644 --- a/tests/test_series.py +++ b/tests/test_series.py @@ -3941,3 +3941,8 @@ def test_series_index_type() -> None: if TYPE_CHECKING_INVALID_USAGE: t = pd.Series([1, 2], index="ab") # type: ignore[call-overload] # pyright: ignore[reportCallIssue, reportArgumentType] + + +def test_timedelta_index_cumsum() -> None: + if TYPE_CHECKING_INVALID_USAGE: + assert_type(pd.Series([pd.Timedelta(0), pd.Timedelta(1)]).cumprod(), Never) From 1aa5c420b6852ce50130520bbe7c6f4d44e2a44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Diridollou?= Date: Sat, 28 Jun 2025 16:00:12 -0400 Subject: [PATCH 2/2] GH1246 Pr feedback --- pandas-stubs/core/indexes/base.pyi | 4 ++-- pandas-stubs/core/series.pyi | 34 ++++++++++++++++++++++++++++-- tests/test_indexes.py | 14 ++++++------ tests/test_series.py | 31 ++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index b65ac0fc..f34f273e 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -348,10 +348,10 @@ class Index(IndexOpsMixin[S1]): def __nonzero__(self) -> None: ... __bool__ = ... def union( - self, other: list[HashableT] | Index, sort: bool | None = ... + self, other: list[HashableT] | Self, sort: bool | None = ... ) -> Index: ... def intersection(self, other: list[S1] | Self, sort: bool | None = ...) -> Self: ... - def difference(self, other: list | Index, sort: bool | None = None) -> Self: ... + def difference(self, other: list | Self, sort: bool | None = None) -> Self: ... def symmetric_difference( self, other: list[S1] | Self, diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index cc102d10..9cdbbf91 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1739,9 +1739,18 @@ class Series(IndexOpsMixin[S1], NDFrame): *args: Any, **kwargs: Any, ) -> Series[S1]: ... + @overload + def cumprod( + self: Series[_str], + axis: AxisIndex = ..., + skipna: _bool = ..., + *args: Any, + **kwargs: Any, + ) -> Never: ... + @overload def cumprod( self, - axis: AxisIndex | None = ..., + axis: AxisIndex = ..., skipna: _bool = ..., *args: Any, **kwargs: Any, @@ -2219,6 +2228,13 @@ class TimestampSeries(Series[Timestamp]): **kwargs: Any, ) -> Timedelta: ... def diff(self, periods: int = ...) -> TimedeltaSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def cumprod( + self, + axis: AxisIndex = ..., + skipna: _bool = ..., + *args: Any, + **kwargs: Any, + ) -> Never: ... class TimedeltaSeries(Series[Timedelta]): # ignores needed because of mypy @@ -2326,7 +2342,7 @@ class TimedeltaSeries(Series[Timedelta]): ) -> TimedeltaSeries: ... def cumprod( self, - axis: AxisIndex | None = ..., + axis: AxisIndex = ..., skipna: _bool = ..., *args: Any, **kwargs: Any, @@ -2337,6 +2353,13 @@ class PeriodSeries(Series[Period]): def dt(self) -> PeriodProperties: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] def __sub__(self, other: PeriodSeries) -> OffsetSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] def diff(self, periods: int = ...) -> OffsetSeries: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + def cumprod( + self, + axis: AxisIndex = ..., + skipna: _bool = ..., + *args: Any, + **kwargs: Any, + ) -> Never: ... class OffsetSeries(Series[BaseOffset]): @overload # type: ignore[override] @@ -2345,6 +2368,13 @@ class OffsetSeries(Series[BaseOffset]): def __radd__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: BaseOffset ) -> OffsetSeries: ... + def cumprod( + self, + axis: AxisIndex = ..., + skipna: _bool = ..., + *args: Any, + **kwargs: Any, + ) -> Never: ... class IntervalSeries(Series[Interval[_OrderableT]], Generic[_OrderableT]): @property diff --git a/tests/test_indexes.py b/tests/test_indexes.py index 6aa11b80..b3f566cd 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -316,18 +316,16 @@ def test_range_index_union(): ), pd.Index, ) + + +def test_index_union_sort() -> None: + """Test sort argument in pd.Index.union GH1264.""" check( - assert_type( - pd.RangeIndex(0, 10).union(["a", "b", "c"], sort=True), - Union[pd.Index, "pd.Index[int]", pd.RangeIndex], - ), + assert_type(pd.Index(["e", "f"]).union(["a", "b", "c"], sort=True), pd.Index), pd.Index, ) check( - assert_type( - pd.RangeIndex(0, 10).union(["a", "b", "c"], sort=False), - Union[pd.Index, "pd.Index[int]", pd.RangeIndex], - ), + assert_type(pd.Index(["e", "f"]).union(["a", "b", "c"], sort=False), pd.Index), pd.Index, ) diff --git a/tests/test_series.py b/tests/test_series.py index b622da02..7f51f9ad 100644 --- a/tests/test_series.py +++ b/tests/test_series.py @@ -3943,6 +3943,35 @@ def test_series_index_type() -> None: t = pd.Series([1, 2], index="ab") # type: ignore[call-overload] # pyright: ignore[reportCallIssue, reportArgumentType] -def test_timedelta_index_cumsum() -> None: +def test_timedelta_index_cumprod() -> None: + dates = pd.Series( + [ + pd.Timestamp("2020-01-01"), + pd.Timestamp("2020-01-15"), + pd.Timestamp("2020-02-01"), + ], + dtype="datetime64[ns]", + ) + as_period_series = pd.Series(pd.PeriodIndex(dates, freq="M")) + + offset_series = as_period_series - as_period_series + + if TYPE_CHECKING_INVALID_USAGE: + assert_type(pd.Series(["a", "b"]).cumprod(), Never) + + if TYPE_CHECKING_INVALID_USAGE: + assert_type(offset_series.cumprod(), Never) + if TYPE_CHECKING_INVALID_USAGE: assert_type(pd.Series([pd.Timedelta(0), pd.Timedelta(1)]).cumprod(), Never) + + if TYPE_CHECKING_INVALID_USAGE: + assert_type( + pd.Series( + [pd.Timestamp("2024-04-29"), pd.Timestamp("2034-08-28")] + ).cumprod(), + Never, + ) + + if TYPE_CHECKING_INVALID_USAGE: + assert_type(as_period_series.cumprod(), Never)