Skip to content

Commit 79a77ac

Browse files
committed
feat(array): #624 accumulate
1 parent 0a67d8b commit 79a77ac

File tree

6 files changed

+95
-22
lines changed

6 files changed

+95
-22
lines changed

pandas-stubs/core/arrays/base.pyi

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from collections.abc import Iterator
22
from typing import (
33
Any,
4+
Literal,
45
overload,
56
)
67

@@ -68,7 +69,13 @@ class ExtensionArray:
6869
def _reduce(
6970
self, name: str, *, skipna: bool = ..., keepdims: bool = ..., **kwargs
7071
) -> object: ...
71-
def _accumulate(self, name: str, *, skipna: bool = ..., **kwargs) -> Self: ...
72+
def _accumulate(
73+
self,
74+
name: Literal["cummin", "cummax", "cumsum", "cumprod"],
75+
*,
76+
skipna: bool = True,
77+
**kwargs,
78+
) -> Self: ...
7279

7380
class ExtensionOpsMixin:
7481
@classmethod

pandas-stubs/core/indexes/accessors.pyi

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ from pandas.core.accessor import PandasDelegate
1717
from pandas.core.arrays.base import ExtensionArray
1818
from pandas.core.arrays.categorical import Categorical
1919
from pandas.core.arrays.datetimes import DatetimeArray
20+
from pandas.core.arrays.integer import (
21+
Int64Dtype,
22+
IntegerArray,
23+
)
2024
from pandas.core.arrays.interval import IntervalArray
2125
from pandas.core.arrays.period import PeriodArray
2226
from pandas.core.arrays.timedeltas import TimedeltaArray
@@ -464,6 +468,10 @@ class ArrayDescriptor:
464468
self, instance: IndexOpsMixin[Never], owner: type[IndexOpsMixin]
465469
) -> ExtensionArray: ...
466470
@overload
471+
def __get__(
472+
self, instance: IndexOpsMixin[Int64Dtype], owner: type[IndexOpsMixin]
473+
) -> IntegerArray: ...
474+
@overload
467475
def __get__(
468476
self, instance: IndexOpsMixin[CategoricalDtype], owner: type[IndexOpsMixin]
469477
) -> Categorical: ...

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ mypy = "1.18.2"
4040
pandas = "2.3.2"
4141
pyarrow = ">=10.0.1"
4242
pytest = ">=8.4.2"
43-
pyright = ">=1.1.405"
43+
pyright = ">=1.1.406"
4444
ty = ">=0.0.1a21"
4545
pyrefly = ">=0.35.0"
4646
poethepoet = ">=0.16.5"

tests/arrays/__init__.py

Whitespace-only changes.

tests/arrays/test_arrays.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from typing import (
2+
assert_type,
3+
cast,
4+
)
5+
6+
from pandas.core.arrays.integer import (
7+
Int64Dtype,
8+
IntegerArray,
9+
)
10+
from pandas.core.series import Series
11+
12+
from tests import check
13+
14+
from pandas._libs.missing import NA
15+
16+
17+
def test_cumul_int():
18+
# cast will be removed if pandas-dev/pandas-stubs#1395 is resolved
19+
arr = cast("Series[Int64Dtype]", Series([1, NA, 2], dtype="Int64")).array
20+
21+
check(assert_type(arr._accumulate("cummin"), IntegerArray), IntegerArray)
22+
check(assert_type(arr._accumulate("cummax"), IntegerArray), IntegerArray)
23+
check(assert_type(arr._accumulate("cumsum"), IntegerArray), IntegerArray)
24+
check(assert_type(arr._accumulate("cumprod"), IntegerArray), IntegerArray)
25+
26+
check(
27+
assert_type(arr._accumulate("cummin", skipna=False), IntegerArray),
28+
IntegerArray,
29+
)
30+
check(
31+
assert_type(arr._accumulate("cummax", skipna=False), IntegerArray),
32+
IntegerArray,
33+
)
34+
check(
35+
assert_type(arr._accumulate("cumsum", skipna=False), IntegerArray),
36+
IntegerArray,
37+
)
38+
check(
39+
assert_type(arr._accumulate("cumprod", skipna=False), IntegerArray),
40+
IntegerArray,
41+
)

tests/series/test_properties.py

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
from typing import (
22
TYPE_CHECKING,
3+
cast,
34
)
45

56
import numpy as np
6-
import pandas as pd
77
from pandas.core.arrays import DatetimeArray
88
from pandas.core.arrays.base import ExtensionArray
9+
from pandas.core.arrays.categorical import Categorical
10+
from pandas.core.arrays.integer import (
11+
Int64Dtype,
12+
IntegerArray,
13+
)
914
from pandas.core.arrays.interval import IntervalArray
1015
from pandas.core.arrays.timedeltas import TimedeltaArray
16+
from pandas.core.frame import DataFrame
1117
from pandas.core.indexes.accessors import (
1218
DatetimeProperties,
1319
PeriodProperties,
1420
Properties,
1521
TimedeltaProperties,
1622
)
23+
from pandas.core.indexes.interval import interval_range
24+
from pandas.core.indexes.period import period_range
25+
from pandas.core.series import Series
1726
from typing_extensions import assert_type
1827

28+
from pandas._libs.interval import Interval
29+
from pandas._libs.missing import NA
30+
from pandas._libs.tslibs.timedeltas import Timedelta
31+
from pandas._libs.tslibs.timestamps import Timestamp
32+
1933
from tests import (
2034
TYPE_CHECKING_INVALID_USAGE,
2135
check,
@@ -25,58 +39,61 @@
2539
from pandas.core.indexes.accessors import TimestampProperties # noqa: F401
2640

2741

28-
def test_dt_property() -> None:
42+
def test_property_dt() -> None:
2943
"""Test the Series.dt property"""
3044
check(
31-
assert_type(pd.Series([pd.Timestamp(2025, 9, 28)]).dt, "TimestampProperties"),
45+
assert_type(Series([Timestamp(2025, 9, 28)]).dt, "TimestampProperties"),
3246
DatetimeProperties,
3347
)
3448
check(
35-
assert_type(pd.Series([pd.Timedelta(1, "s")]).dt, TimedeltaProperties),
49+
assert_type(Series([Timedelta(1, "s")]).dt, TimedeltaProperties),
3650
TimedeltaProperties,
3751
)
3852
check(
3953
assert_type(
40-
pd.period_range(start="2022-06-01", periods=10).to_series().dt,
54+
period_range(start="2022-06-01", periods=10).to_series().dt,
4155
PeriodProperties,
4256
),
4357
PeriodProperties,
4458
)
4559

4660
if TYPE_CHECKING_INVALID_USAGE:
47-
s = pd.DataFrame({"a": [1]})["a"]
61+
s = DataFrame({"a": [1]})["a"]
4862
# python/mypy#19952: mypy believes Properties and its subclasses have a
4963
# conflict and gives Any for s.dt
5064
assert_type(s.dt, Properties) # type: ignore[assert-type]
51-
_1 = pd.Series([1]).dt # type: ignore[arg-type] # pyright: ignore[reportAttributeAccessIssue]
65+
_1 = Series([1]).dt # type: ignore[arg-type] # pyright: ignore[reportAttributeAccessIssue]
5266

5367

54-
def test_array_property() -> None:
68+
def test_property_array() -> None:
5569
"""Test that Series.array returns ExtensionArray and its subclasses"""
70+
check(
71+
assert_type(Series([1], dtype="category").array, Categorical), Categorical, int
72+
)
73+
# cast will be removed if pandas-dev/pandas-stubs#1395 is resolved
5674
check(
5775
assert_type(
58-
pd.Series([1], dtype="category").array,
59-
pd.Categorical,
76+
cast("Series[Int64Dtype]", Series([1, NA], dtype="Int64")).array,
77+
IntegerArray,
6078
),
61-
pd.Categorical,
62-
int,
79+
IntegerArray,
6380
)
6481
check(
65-
assert_type(pd.Series(pd.interval_range(0, 1)).array, IntervalArray),
82+
assert_type(Series(interval_range(0, 1)).array, IntervalArray),
6683
IntervalArray,
67-
pd.Interval,
84+
Interval,
6885
)
6986
check(
70-
assert_type(pd.Series([pd.Timestamp(2025, 9, 28)]).array, DatetimeArray),
87+
assert_type(Series([Timestamp(2025, 9, 28)]).array, DatetimeArray),
7188
DatetimeArray,
72-
pd.Timestamp,
89+
Timestamp,
7390
)
7491
check(
75-
assert_type(pd.Series([pd.Timedelta(1, "s")]).array, TimedeltaArray),
92+
assert_type(Series([Timedelta(1, "s")]).array, TimedeltaArray),
7693
TimedeltaArray,
77-
pd.Timedelta,
94+
Timedelta,
7895
)
79-
check(assert_type(pd.Series([1]).array, ExtensionArray), ExtensionArray, np.integer)
96+
check(assert_type(Series([1]).array, ExtensionArray), ExtensionArray, np.integer)
8097
# python/mypy#19952: mypy believes ExtensionArray and its subclasses have a
8198
# conflict and gives Any for s.array
82-
check(assert_type(pd.Series([1, "s"]).array, ExtensionArray), ExtensionArray) # type: ignore[assert-type]
99+
check(assert_type(Series([1, "s"]).array, ExtensionArray), ExtensionArray) # type: ignore[assert-type]

0 commit comments

Comments
 (0)