Skip to content

Commit 76f7bc4

Browse files
authored
Support an ExtensionDtype and ExtensionArray (#554)
* Support an ExtensionDtype and ExtensionArray * update TypeGuard usage. Test astype for Decimal * use ClassVar. Change is_float to accept numpy. Remove self: Self * remove declarations of private funcs. make na_value a property
1 parent c6815aa commit 76f7bc4

20 files changed

+436
-60
lines changed

pandas-stubs/_libs/lib.pyi

+24-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,28 @@
1+
from enum import Enum
2+
from typing import (
3+
Final,
4+
Literal,
5+
)
6+
7+
import numpy as np
8+
from pandas import Interval
9+
from typing_extensions import (
10+
TypeAlias,
11+
TypeGuard,
12+
)
13+
14+
class _NoDefault(Enum):
15+
no_default = ...
16+
17+
no_default: Final = _NoDefault.no_default
18+
NoDefault: TypeAlias = Literal[_NoDefault.no_default]
19+
120
def infer_dtype(value: object, skipna: bool = ...) -> str: ...
221
def is_iterator(obj: object) -> bool: ...
322
def is_scalar(val: object) -> bool: ...
423
def is_list_like(obj: object, allow_sets: bool = ...) -> bool: ...
5-
def is_interval(val: object) -> bool: ...
6-
def is_complex(val: object) -> bool: ...
7-
def is_bool(val: object) -> bool: ...
8-
def is_integer(val: object) -> bool: ...
9-
def is_float(val: object) -> bool: ...
24+
def is_interval(val: object) -> TypeGuard[Interval]: ...
25+
def is_complex(val: object) -> TypeGuard[complex]: ...
26+
def is_bool(val: object) -> TypeGuard[bool | np.bool_]: ...
27+
def is_integer(val: object) -> TypeGuard[int | np.integer]: ...
28+
def is_float(val: object) -> TypeGuard[float | np.floating]: ...

pandas-stubs/_typing.pyi

+4-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ class WriteExcelBuffer(WriteBuffer[bytes], Protocol):
166166

167167
FilePath: TypeAlias = str | PathLike[str]
168168

169-
Axis: TypeAlias = str | int
169+
AxisInt: TypeAlias = Literal[0, 1]
170+
Axis: TypeAlias = AxisInt | Literal["index", "columns", "rows"]
170171
IndexLabel: TypeAlias = Hashable | Sequence[Hashable]
171172
Label: TypeAlias = Hashable | None
172173
Level: TypeAlias = Hashable | int
@@ -293,6 +294,8 @@ IntervalT = TypeVar(
293294
)
294295
IntervalClosedType: TypeAlias = Literal["left", "right", "both", "neither"]
295296

297+
TakeIndexer: TypeAlias = Sequence[int] | Sequence[np.integer] | npt.NDArray[np.integer]
298+
296299
IgnoreRaiseCoerce: TypeAlias = Literal["ignore", "raise", "coerce"]
297300

298301
# Shared by functions such as drop and astype

pandas-stubs/api/extensions/__init__.pyi

+3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ from pandas.core.accessor import (
33
register_index_accessor as register_index_accessor,
44
register_series_accessor as register_series_accessor,
55
)
6+
from pandas.core.algorithms import take as take
67
from pandas.core.arrays import (
78
ExtensionArray as ExtensionArray,
89
ExtensionScalarOpsMixin as ExtensionScalarOpsMixin,
910
)
1011

12+
from pandas._libs.lib import no_default as no_default
13+
1114
from pandas.core.dtypes.dtypes import (
1215
ExtensionDtype as ExtensionDtype,
1316
register_extension_dtype as register_extension_dtype,

pandas-stubs/core/algorithms.pyi

+9
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ from pandas.api.extensions import ExtensionArray
1414

1515
from pandas._typing import (
1616
AnyArrayLike,
17+
AxisInt,
1718
IntervalT,
19+
TakeIndexer,
1820
)
1921

2022
# These are type: ignored because the Index types overlap due to inheritance but indices
@@ -69,3 +71,10 @@ def value_counts(
6971
bins: int | None = ...,
7072
dropna: bool = ...,
7173
) -> Series: ...
74+
def take(
75+
arr,
76+
indices: TakeIndexer,
77+
axis: AxisInt = 0,
78+
allow_fill: bool = False,
79+
fill_value=None,
80+
): ...

pandas-stubs/core/arraylike.pyi

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ from typing import Any
22

33
from typing_extensions import Self
44

5+
from pandas._libs.ops_dispatch import (
6+
maybe_dispatch_ufunc_to_dunder_op as maybe_dispatch_ufunc_to_dunder_op,
7+
)
8+
59
class OpsMixin:
610
def __eq__(self, other: object) -> Self: ... # type: ignore[override]
711
def __ne__(self, other: object) -> Self: ... # type: ignore[override]

pandas-stubs/core/arrays/base.pyi

+24-15
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
from collections.abc import Sequence
1+
from typing import Any
22

33
import numpy as np
4+
from typing_extensions import Self
45

56
from pandas._typing import (
67
ArrayLike,
78
Scalar,
9+
TakeIndexer,
810
npt,
911
)
1012

1113
from pandas.core.dtypes.dtypes import ExtensionDtype as ExtensionDtype
12-
from pandas.core.dtypes.generic import ABCExtensionArray
1314

1415
class ExtensionArray:
15-
def __getitem__(self, item) -> None: ...
16+
def __getitem__(self, item) -> Any: ...
1617
def __setitem__(self, key: int | slice | np.ndarray, value) -> None: ...
1718
def __len__(self) -> int: ...
1819
def __iter__(self): ...
20+
def __contains__(self, item: object) -> bool | np.bool_: ...
1921
def to_numpy(
2022
self,
2123
dtype: npt.DTypeLike | None = ...,
@@ -37,22 +39,29 @@ class ExtensionArray:
3739
) -> np.ndarray: ...
3840
def fillna(self, value=..., method=..., limit=...): ...
3941
def dropna(self): ...
40-
def shift(
41-
self, periods: int = ..., fill_value: object = ...
42-
) -> ABCExtensionArray: ...
42+
def shift(self, periods: int = ..., fill_value: object = ...) -> Self: ...
4343
def unique(self): ...
4444
def searchsorted(self, value, side: str = ..., sorter=...): ...
4545
# TODO: remove keyword-only when pandas removed na_sentinel
46-
def factorize(
47-
self, *, use_na_sentinel: bool = ...
48-
) -> tuple[np.ndarray, ABCExtensionArray]: ...
46+
def factorize(self, *, use_na_sentinel: bool = ...) -> tuple[np.ndarray, Self]: ...
4947
def repeat(self, repeats, axis=...): ...
5048
def take(
51-
self, indices: Sequence[int], *, allow_fill: bool = ..., fill_value=...
52-
) -> ABCExtensionArray: ...
53-
def copy(self) -> ABCExtensionArray: ...
54-
def view(self, dtype=...) -> ABCExtensionArray | np.ndarray: ...
55-
def ravel(self, order=...) -> ABCExtensionArray: ...
49+
self,
50+
indexer: TakeIndexer,
51+
*,
52+
allow_fill: bool = ...,
53+
fill_value=...,
54+
) -> Self: ...
55+
def copy(self) -> Self: ...
56+
def view(self, dtype=...) -> Self | np.ndarray: ...
57+
def ravel(self, order=...) -> Self: ...
58+
59+
class ExtensionOpsMixin:
60+
@classmethod
61+
def _add_arithmetic_ops(cls) -> None: ...
62+
@classmethod
63+
def _add_comparison_ops(cls) -> None: ...
64+
@classmethod
65+
def _add_logical_ops(cls) -> None: ...
5666

57-
class ExtensionOpsMixin: ...
5867
class ExtensionScalarOpsMixin(ExtensionOpsMixin): ...

pandas-stubs/core/arrays/boolean.pyi

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import ClassVar
2+
13
import numpy as np
24

35
from pandas._libs.missing import NAType
@@ -8,9 +10,7 @@ from pandas.core.dtypes.base import ExtensionDtype as ExtensionDtype
810
from .masked import BaseMaskedArray as BaseMaskedArray
911

1012
class BooleanDtype(ExtensionDtype):
11-
name: str = ...
12-
@property
13-
def na_value(self) -> NAType: ...
13+
na_value: ClassVar[NAType]
1414
@classmethod
1515
def construct_array_type(cls) -> type_t[BooleanArray]: ...
1616

pandas-stubs/core/arrays/categorical.pyi

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ from pandas._typing import (
2424
ListLike,
2525
Ordered,
2626
Scalar,
27+
TakeIndexer,
2728
np_ndarray_bool,
2829
np_ndarray_int,
2930
)
@@ -165,7 +166,9 @@ class Categorical(ExtensionArray, PandasObject):
165166
def view(self, dtype=...): ...
166167
def to_dense(self): ...
167168
def fillna(self, value=..., method=..., limit=...): ...
168-
def take(self, indexer, *, allow_fill: bool = ..., fill_value=...): ...
169+
def take(
170+
self, indexer: TakeIndexer, *, allow_fill: bool = ..., fill_value=...
171+
) -> Categorical: ...
169172
def take_nd(self, indexer, allow_fill: bool = ..., fill_value=...): ...
170173
def __len__(self) -> int: ...
171174
def __iter__(self): ...

pandas-stubs/core/arrays/datetimelike.pyi

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ from pandas.core.arrays.base import (
55
ExtensionArray,
66
ExtensionOpsMixin,
77
)
8+
from typing_extensions import Self
89

910
from pandas._libs import (
1011
NaT as NaT,
1112
NaTType as NaTType,
1213
)
14+
from pandas._typing import TakeIndexer
1315

1416
class DatelikeOps:
1517
def strftime(self, date_format): ...
@@ -40,7 +42,9 @@ class DatetimeLikeArrayMixin(ExtensionOpsMixin, ExtensionArray):
4042
def astype(self, dtype, copy: bool = ...): ...
4143
def view(self, dtype=...): ...
4244
def unique(self): ...
43-
def take(self, indices, *, allow_fill: bool = ..., fill_value=...): ...
45+
def take(
46+
self: Self, indices: TakeIndexer, *, allow_fill: bool = ..., fill_value=...
47+
) -> Self: ...
4448
def copy(self): ...
4549
def shift(self, periods: int = ..., fill_value=..., axis: int = ...): ...
4650
def searchsorted(self, value, side: str = ..., sorter=...): ...

pandas-stubs/core/arrays/interval.pyi

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import numpy as np
22
from pandas import Index
33
from pandas.core.arrays.base import ExtensionArray as ExtensionArray
4+
from typing_extensions import Self
45

56
from pandas._libs.interval import (
67
Interval as Interval,
78
IntervalMixin as IntervalMixin,
89
)
9-
from pandas._typing import Axis
10-
11-
from pandas.core.dtypes.generic import ABCExtensionArray
10+
from pandas._typing import (
11+
Axis,
12+
TakeIndexer,
13+
)
1214

1315
class IntervalArray(IntervalMixin, ExtensionArray):
1416
ndim: int = ...
@@ -40,12 +42,16 @@ class IntervalArray(IntervalMixin, ExtensionArray):
4042
def nbytes(self) -> int: ...
4143
@property
4244
def size(self) -> int: ...
43-
def shift(
44-
self, periods: int = ..., fill_value: object = ...
45-
) -> ABCExtensionArray: ...
46-
def take(
47-
self, indices, *, allow_fill: bool = ..., fill_value=..., axis=..., **kwargs
48-
): ...
45+
def shift(self, periods: int = ..., fill_value: object = ...) -> IntervalArray: ...
46+
def take( # type: ignore[override]
47+
self: Self,
48+
indices: TakeIndexer,
49+
*,
50+
allow_fill: bool = ...,
51+
fill_value=...,
52+
axis=...,
53+
**kwargs,
54+
) -> Self: ...
4955
def value_counts(self, dropna: bool = ...): ...
5056
@property
5157
def left(self) -> Index: ...

pandas-stubs/core/arrays/masked.pyi

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ from pandas.core.arrays import (
66

77
from pandas._typing import (
88
Scalar,
9+
TakeIndexer,
910
npt,
1011
)
1112

@@ -26,6 +27,8 @@ class BaseMaskedArray(ExtensionArray, ExtensionOpsMixin):
2627
def isna(self): ...
2728
@property
2829
def nbytes(self) -> int: ...
29-
def take(self, indexer, *, allow_fill: bool = ..., fill_value=...): ...
30+
def take(
31+
self, indexer: TakeIndexer, allow_fill: bool = ..., fill_value=...
32+
) -> BaseMaskedArray: ...
3033
def copy(self): ...
3134
def value_counts(self, dropna: bool = ...): ...

pandas-stubs/core/arrays/sparse/array.pyi

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ from pandas.core.arrays import (
55
)
66
from pandas.core.base import PandasObject
77

8+
from pandas._typing import TakeIndexer
9+
810
class SparseArray(PandasObject, ExtensionArray, ExtensionOpsMixin):
911
def __init__(
1012
self,
@@ -42,12 +44,14 @@ class SparseArray(PandasObject, ExtensionArray, ExtensionOpsMixin):
4244
def fillna(self, value=..., method=..., limit=...): ...
4345
def shift(self, periods: int = ..., fill_value=...): ...
4446
def unique(self): ...
45-
def factorize( # type: ignore[override]
47+
def factorize(
4648
self, na_sentinel: int = ..., use_na_sentinel: bool = ...
4749
) -> tuple[np.ndarray, SparseArray]: ...
4850
def value_counts(self, dropna: bool = ...): ...
4951
def __getitem__(self, key): ...
50-
def take(self, indices, *, allow_fill: bool = ..., fill_value=...): ...
52+
def take(
53+
self, indices: TakeIndexer, *, allow_fill: bool = ..., fill_value=...
54+
) -> SparseArray: ...
5155
def searchsorted(self, v, side: str = ..., sorter=...): ...
5256
def copy(self): ...
5357
def astype(self, dtype=..., copy: bool = ...): ...

pandas-stubs/core/dtypes/base.pyi

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
from typing import Literal
1+
from typing import (
2+
ClassVar,
3+
Literal,
4+
)
25

36
from pandas.core.arrays import ExtensionArray
47

5-
from pandas._libs import NaTType
6-
from pandas._libs.missing import NAType
78
from pandas._typing import type_t
89

910
class ExtensionDtype:
11+
type: ClassVar[type_t]
12+
name: ClassVar[str]
13+
1014
@property
11-
def na_value(self) -> NAType | NaTType: ...
12-
@property
13-
def type(self) -> type_t: ...
15+
def na_value(self) -> object: ...
1416
@property
1517
def kind(
1618
self,
1719
) -> Literal["b", "i", "u", "f", "c", "m", "M", "O", "S", "U", "V"]: ...
1820
@property
19-
def name(self) -> str: ...
20-
@property
2121
def names(self) -> list[str] | None: ...
2222
def empty(self, size: int | tuple[int, ...]) -> type_t[ExtensionArray]: ...
2323
@classmethod

pandas-stubs/core/dtypes/dtypes.pyi

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import datetime as dt
22
from typing import (
33
Any,
44
Literal,
5+
TypeVar,
56
)
67

78
import numpy as np
@@ -17,7 +18,9 @@ from pandas._typing import (
1718

1819
from .base import ExtensionDtype as ExtensionDtype
1920

20-
def register_extension_dtype(cls: type[ExtensionDtype]) -> type[ExtensionDtype]: ...
21+
_ExtensionDtypeT = TypeVar("_ExtensionDtypeT", bound=ExtensionDtype)
22+
23+
def register_extension_dtype(cls: type[_ExtensionDtypeT]) -> type[_ExtensionDtypeT]: ...
2124

2225
class BaseMaskedDtype(ExtensionDtype): ...
2326
class PandasExtensionDtype(ExtensionDtype): ...

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ types-pytz = ">= 2022.1.1"
3838
mypy = "1.0"
3939
pyarrow = ">=10.0.1"
4040
pytest = ">=7.1.2"
41-
pyright = ">=1.1.286"
41+
pyright = ">=1.1.295"
4242
poethepoet = ">=0.16.5"
4343
loguru = ">=0.6.0"
4444
pandas = "1.5.3"

tests/extension/__init__.py

Whitespace-only changes.

tests/extension/decimal/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)