Skip to content

Commit d410f2e

Browse files
authored
upgrade mypy and pyright. close 8 issues (#1087)
* update mypy and allow timestamp slicing * fix for getitem with pythong 3.12 and mypy * allow apply to return an offset * allow loc setitem to accept a slice * allow indexing with .loc using Timestamp * define __bool__ for Series and DataFrame to be NoReturn * support Path div * change TypeVar to use Union where possible * support dict keys in constructor to Series * remove path overloads. add assert False for unreachable code
1 parent 8f48f32 commit d410f2e

File tree

10 files changed

+236
-71
lines changed

10 files changed

+236
-71
lines changed

pandas-stubs/_libs/tslibs/timestamps.pyi

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ from time import struct_time
1111
from typing import (
1212
ClassVar,
1313
Literal,
14+
SupportsIndex,
1415
overload,
1516
)
1617

@@ -48,7 +49,7 @@ _Nonexistent: TypeAlias = (
4849
Literal["raise", "NaT", "shift_backward", "shift_forward"] | Timedelta | timedelta
4950
)
5051

51-
class Timestamp(datetime):
52+
class Timestamp(datetime, SupportsIndex):
5253
min: ClassVar[Timestamp] # pyright: ignore[reportIncompatibleVariableOverride]
5354
max: ClassVar[Timestamp] # pyright: ignore[reportIncompatibleVariableOverride]
5455

@@ -309,3 +310,5 @@ class Timestamp(datetime):
309310
@property
310311
def unit(self) -> TimeUnit: ...
311312
def as_unit(self, unit: TimeUnit, round_ok: bool = ...) -> Self: ...
313+
# To support slicing
314+
def __index__(self) -> int: ...

pandas-stubs/_typing.pyi

+3-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ Incomplete: TypeAlias = Any
5757
ArrayLike: TypeAlias = ExtensionArray | np.ndarray[Any, Any]
5858
AnyArrayLike: TypeAlias = Index[Any] | Series[Any] | np.ndarray[Any, Any]
5959
PythonScalar: TypeAlias = str | bool | complex
60-
DatetimeLikeScalar = TypeVar("DatetimeLikeScalar", Period, Timestamp, Timedelta)
60+
DatetimeLikeScalar = TypeVar("DatetimeLikeScalar", bound=Period | Timestamp | Timedelta)
6161
PandasScalar: TypeAlias = bytes | datetime.date | datetime.datetime | datetime.timedelta
6262
IntStrT = TypeVar("IntStrT", int, str)
6363
# Scalar: TypeAlias = PythonScalar | PandasScalar
@@ -490,7 +490,8 @@ AxisColumn: TypeAlias = Literal["columns", 1]
490490
Axis: TypeAlias = AxisIndex | AxisColumn
491491
DtypeNp = TypeVar("DtypeNp", bound=np.dtype[np.generic])
492492
KeysArgType: TypeAlias = Any
493-
ListLike = TypeVar("ListLike", Sequence, np.ndarray, Series, Index)
493+
ListLike: TypeAlias = Sequence | np.ndarray | Series | Index
494+
ListLikeT = TypeVar("ListLikeT", bound=ListLike)
494495
ListLikeExceptSeriesAndStr: TypeAlias = (
495496
MutableSequence[Any] | np.ndarray[Any, Any] | tuple[Any, ...] | Index[Any]
496497
)

pandas-stubs/core/dtypes/concat.pyi

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ from pandas import (
66
Series,
77
)
88

9-
_CatT = TypeVar("_CatT", Categorical, CategoricalIndex, Series)
9+
_CatT = TypeVar("_CatT", bound=Categorical | CategoricalIndex | Series)
1010

1111
def union_categoricals(
1212
to_union: list[_CatT], sort_categories: bool = ..., ignore_order: bool = ...

pandas-stubs/core/frame.pyi

+39-12
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ from collections.abc import (
99
)
1010
import datetime as dt
1111
from re import Pattern
12+
import sys
1213
from typing import (
1314
Any,
1415
ClassVar,
1516
Literal,
17+
NoReturn,
1618
overload,
1719
)
1820

@@ -112,6 +114,7 @@ from pandas._typing import (
112114
ReplaceMethod,
113115
Scalar,
114116
ScalarT,
117+
SequenceNotStr,
115118
SeriesByT,
116119
SortKind,
117120
StataDateFormat,
@@ -193,7 +196,11 @@ class _LocIndexerFrame(_LocIndexer):
193196
def __getitem__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload]
194197
self,
195198
idx: tuple[
196-
int | StrLike | tuple[Scalar, ...] | Callable[[DataFrame], ScalarT],
199+
int
200+
| StrLike
201+
| Timestamp
202+
| tuple[Scalar, ...]
203+
| Callable[[DataFrame], ScalarT],
197204
int | StrLike | tuple[Scalar, ...],
198205
],
199206
) -> Scalar: ...
@@ -206,6 +213,7 @@ class _LocIndexerFrame(_LocIndexer):
206213
IndexType
207214
| MaskType
208215
| _IndexSliceTuple
216+
| SequenceNotStr[float | str | Timestamp]
209217
| Callable[
210218
[DataFrame], ScalarT | list[HashableT] | IndexType | MaskType
211219
],
@@ -219,7 +227,9 @@ class _LocIndexerFrame(_LocIndexer):
219227
@overload
220228
def __setitem__(
221229
self,
222-
idx: MaskType | StrLike | _IndexSliceTuple | list[ScalarT] | IndexingInt,
230+
idx: (
231+
MaskType | StrLike | _IndexSliceTuple | list[ScalarT] | IndexingInt | slice
232+
),
223233
value: Scalar | NAType | NaTType | ArrayLike | Series | DataFrame | list | None,
224234
) -> None: ...
225235
@overload
@@ -229,8 +239,32 @@ class _LocIndexerFrame(_LocIndexer):
229239
value: Scalar | NAType | NaTType | ArrayLike | Series | list | None,
230240
) -> None: ...
231241

232-
class DataFrame(NDFrame, OpsMixin):
233-
__hash__: ClassVar[None] # type: ignore[assignment]
242+
# With mypy 1.14.1 and python 3.12, the second overload needs a type-ignore statement
243+
if sys.version_info >= (3, 12):
244+
class _GetItemHack:
245+
@overload
246+
def __getitem__(self, key: Scalar | tuple[Hashable, ...]) -> Series: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload]
247+
@overload
248+
def __getitem__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload]
249+
self, key: Iterable[Hashable] | slice
250+
) -> DataFrame: ...
251+
@overload
252+
def __getitem__(self, key: Hashable) -> Series: ...
253+
254+
else:
255+
class _GetItemHack:
256+
@overload
257+
def __getitem__(self, key: Scalar | tuple[Hashable, ...]) -> Series: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload]
258+
@overload
259+
def __getitem__( # pyright: ignore[reportOverlappingOverload]
260+
self, key: Iterable[Hashable] | slice
261+
) -> DataFrame: ...
262+
@overload
263+
def __getitem__(self, key: Hashable) -> Series: ...
264+
265+
class DataFrame(NDFrame, OpsMixin, _GetItemHack):
266+
267+
__hash__: ClassVar[None] # type: ignore[assignment] # pyright: ignore[reportIncompatibleMethodOverride]
234268

235269
@overload
236270
def __new__(
@@ -607,14 +641,6 @@ class DataFrame(NDFrame, OpsMixin):
607641
@property
608642
def T(self) -> DataFrame: ...
609643
def __getattr__(self, name: str) -> Series: ...
610-
@overload
611-
def __getitem__(self, key: Scalar | tuple[Hashable, ...]) -> Series: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload]
612-
@overload
613-
def __getitem__( # pyright: ignore[reportOverlappingOverload]
614-
self, key: Iterable[Hashable] | slice
615-
) -> DataFrame: ...
616-
@overload
617-
def __getitem__(self, key: Hashable) -> Series: ...
618644
def isetitem(
619645
self, loc: int | Sequence[int], value: Scalar | ArrayLike | list[Any]
620646
) -> None: ...
@@ -2453,6 +2479,7 @@ class DataFrame(NDFrame, OpsMixin):
24532479
) -> Self: ...
24542480
def __truediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ...
24552481
def __rtruediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ...
2482+
def __bool__(self) -> NoReturn: ...
24562483

24572484
class _PandasNamedTuple(tuple[Any, ...]):
24582485
def __getattr__(self, field: str) -> Scalar: ...

pandas-stubs/core/indexes/accessors.pyi

+25-19
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ from pandas._typing import (
4242

4343
class Properties(PandasDelegate, NoNewAttributesMixin): ...
4444

45-
_DTFieldOpsReturnType = TypeVar("_DTFieldOpsReturnType", Series[int], Index[int])
45+
_DTFieldOpsReturnType = TypeVar("_DTFieldOpsReturnType", bound=Series[int] | Index[int])
4646

4747
class _DayLikeFieldOps(Generic[_DTFieldOpsReturnType]):
4848
@property
@@ -84,7 +84,9 @@ class _DatetimeFieldOps(
8484
_DayLikeFieldOps[_DTFieldOpsReturnType], _MiniSeconds[_DTFieldOpsReturnType]
8585
): ...
8686

87-
_DTBoolOpsReturnType = TypeVar("_DTBoolOpsReturnType", Series[bool], np_ndarray_bool)
87+
_DTBoolOpsReturnType = TypeVar(
88+
"_DTBoolOpsReturnType", bound=Series[bool] | np_ndarray_bool
89+
)
8890

8991
class _IsLeapYearProperty(Generic[_DTBoolOpsReturnType]):
9092
@property
@@ -106,7 +108,7 @@ class _DatetimeBoolOps(
106108
@property
107109
def is_year_end(self) -> _DTBoolOpsReturnType: ...
108110

109-
_DTFreqReturnType = TypeVar("_DTFreqReturnType", str, BaseOffset)
111+
_DTFreqReturnType = TypeVar("_DTFreqReturnType", bound=str | BaseOffset)
110112

111113
class _FreqProperty(Generic[_DTFreqReturnType]):
112114
@property
@@ -121,10 +123,10 @@ class _DatetimeObjectOps(
121123
): ...
122124

123125
_DTOtherOpsDateReturnType = TypeVar(
124-
"_DTOtherOpsDateReturnType", Series[dt.date], np.ndarray
126+
"_DTOtherOpsDateReturnType", bound=Series[dt.date] | np.ndarray
125127
)
126128
_DTOtherOpsTimeReturnType = TypeVar(
127-
"_DTOtherOpsTimeReturnType", Series[dt.time], np.ndarray
129+
"_DTOtherOpsTimeReturnType", bound=Series[dt.time] | np.ndarray
128130
)
129131

130132
class _DatetimeOtherOps(Generic[_DTOtherOpsDateReturnType, _DTOtherOpsTimeReturnType]):
@@ -157,11 +159,7 @@ class _DatetimeLikeOps(
157159

158160
_DTTimestampTimedeltaReturnType = TypeVar(
159161
"_DTTimestampTimedeltaReturnType",
160-
Series,
161-
TimestampSeries,
162-
TimedeltaSeries,
163-
DatetimeIndex,
164-
TimedeltaIndex,
162+
bound=Series | TimestampSeries | TimedeltaSeries | DatetimeIndex | TimedeltaIndex,
165163
)
166164

167165
class _DatetimeRoundingMethods(Generic[_DTTimestampTimedeltaReturnType]):
@@ -199,8 +197,10 @@ class _DatetimeRoundingMethods(Generic[_DTTimestampTimedeltaReturnType]):
199197
_DTNormalizeReturnType = TypeVar(
200198
"_DTNormalizeReturnType", TimestampSeries, DatetimeIndex
201199
)
202-
_DTStrKindReturnType = TypeVar("_DTStrKindReturnType", Series[str], Index)
203-
_DTToPeriodReturnType = TypeVar("_DTToPeriodReturnType", PeriodSeries, PeriodIndex)
200+
_DTStrKindReturnType = TypeVar("_DTStrKindReturnType", bound=Series[str] | Index)
201+
_DTToPeriodReturnType = TypeVar(
202+
"_DTToPeriodReturnType", bound=PeriodSeries | PeriodIndex
203+
)
204204

205205
class _DatetimeLikeNoTZMethods(
206206
_DatetimeRoundingMethods[_DTTimestampTimedeltaReturnType],
@@ -289,9 +289,11 @@ class DatetimeProperties(
289289
def as_unit(self, unit: TimeUnit) -> _DTTimestampTimedeltaReturnType: ...
290290

291291
_TDNoRoundingMethodReturnType = TypeVar(
292-
"_TDNoRoundingMethodReturnType", Series[int], Index
292+
"_TDNoRoundingMethodReturnType", bound=Series[int] | Index
293+
)
294+
_TDTotalSecondsReturnType = TypeVar(
295+
"_TDTotalSecondsReturnType", bound=Series[float] | Index
293296
)
294-
_TDTotalSecondsReturnType = TypeVar("_TDTotalSecondsReturnType", Series[float], Index)
295297

296298
class _TimedeltaPropertiesNoRounding(
297299
Generic[_TDNoRoundingMethodReturnType, _TDTotalSecondsReturnType]
@@ -318,11 +320,15 @@ class TimedeltaProperties(
318320
def unit(self) -> TimeUnit: ...
319321
def as_unit(self, unit: TimeUnit) -> TimedeltaSeries: ...
320322

321-
_PeriodDTReturnTypes = TypeVar("_PeriodDTReturnTypes", TimestampSeries, DatetimeIndex)
322-
_PeriodIntReturnTypes = TypeVar("_PeriodIntReturnTypes", Series[int], Index[int])
323-
_PeriodStrReturnTypes = TypeVar("_PeriodStrReturnTypes", Series[str], Index)
324-
_PeriodDTAReturnTypes = TypeVar("_PeriodDTAReturnTypes", DatetimeArray, DatetimeIndex)
325-
_PeriodPAReturnTypes = TypeVar("_PeriodPAReturnTypes", PeriodArray, PeriodIndex)
323+
_PeriodDTReturnTypes = TypeVar(
324+
"_PeriodDTReturnTypes", bound=TimestampSeries | DatetimeIndex
325+
)
326+
_PeriodIntReturnTypes = TypeVar("_PeriodIntReturnTypes", bound=Series[int] | Index[int])
327+
_PeriodStrReturnTypes = TypeVar("_PeriodStrReturnTypes", bound=Series[str] | Index)
328+
_PeriodDTAReturnTypes = TypeVar(
329+
"_PeriodDTAReturnTypes", bound=DatetimeArray | DatetimeIndex
330+
)
331+
_PeriodPAReturnTypes = TypeVar("_PeriodPAReturnTypes", bound=PeriodArray | PeriodIndex)
326332

327333
class _PeriodProperties(
328334
Generic[

pandas-stubs/core/series.pyi

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from collections import dict_keys # type: ignore[attr-defined]
12
from collections.abc import (
23
Callable,
34
Hashable,
@@ -13,11 +14,13 @@ from datetime import (
1314
time,
1415
timedelta,
1516
)
17+
from pathlib import Path
1618
from typing import (
1719
Any,
1820
ClassVar,
1921
Generic,
2022
Literal,
23+
NoReturn,
2124
overload,
2225
)
2326

@@ -139,6 +142,7 @@ from pandas._typing import (
139142
ReplaceMethod,
140143
Scalar,
141144
ScalarT,
145+
SequenceNotStr,
142146
SeriesByT,
143147
SortKind,
144148
StrDtypeArg,
@@ -195,8 +199,7 @@ class _LocIndexerSeries(_LocIndexer, Generic[S1]):
195199
idx: (
196200
MaskType
197201
| Index
198-
| Sequence[float]
199-
| list[str]
202+
| SequenceNotStr[float | str | Timestamp]
200203
| slice
201204
| _IndexSliceTuple
202205
| Sequence[_IndexSliceTuple]
@@ -208,7 +211,7 @@ class _LocIndexerSeries(_LocIndexer, Generic[S1]):
208211
@overload
209212
def __setitem__(
210213
self,
211-
idx: Index | MaskType,
214+
idx: Index | MaskType | slice,
212215
value: S1 | ArrayLike | Series[S1] | None,
213216
) -> None: ...
214217
@overload
@@ -352,7 +355,7 @@ class Series(IndexOpsMixin[S1], NDFrame):
352355
@overload
353356
def __new__(
354357
cls,
355-
data: S1 | _ListLike[S1] | dict[HashableT1, S1],
358+
data: S1 | _ListLike[S1] | dict[HashableT1, S1] | dict_keys[S1, Any],
356359
index: Axes | None = ...,
357360
*,
358361
dtype: Dtype = ...,
@@ -1030,6 +1033,14 @@ class Series(IndexOpsMixin[S1], NDFrame):
10301033
**kwds,
10311034
) -> Series: ...
10321035
@overload
1036+
def apply(
1037+
self,
1038+
func: Callable[..., BaseOffset],
1039+
convertDType: _bool = ...,
1040+
args: tuple = ...,
1041+
**kwds,
1042+
) -> OffsetSeries: ...
1043+
@overload
10331044
def apply(
10341045
self,
10351046
func: Callable[..., Series],
@@ -1640,7 +1651,7 @@ class Series(IndexOpsMixin[S1], NDFrame):
16401651
self, other: int | np_ndarray_anyint | Series[int]
16411652
) -> Series[int]: ...
16421653
def __rsub__(self, other: num | _ListLike | Series[S1]) -> Series: ...
1643-
def __rtruediv__(self, other: num | _ListLike | Series[S1]) -> Series: ...
1654+
def __rtruediv__(self, other: num | _ListLike | Series[S1] | Path) -> Series: ...
16441655
# ignore needed for mypy as we want different results based on the arguments
16451656
@overload # type: ignore[override]
16461657
def __rxor__( # pyright: ignore[reportOverlappingOverload]
@@ -1666,7 +1677,7 @@ class Series(IndexOpsMixin[S1], NDFrame):
16661677
) -> TimedeltaSeries: ...
16671678
@overload
16681679
def __sub__(self, other: num | _ListLike | Series) -> Series: ...
1669-
def __truediv__(self, other: num | _ListLike | Series[S1]) -> Series: ...
1680+
def __truediv__(self, other: num | _ListLike | Series[S1] | Path) -> Series: ...
16701681
# ignore needed for mypy as we want different results based on the arguments
16711682
@overload # type: ignore[override]
16721683
def __xor__( # pyright: ignore[reportOverlappingOverload]
@@ -2144,6 +2155,7 @@ class Series(IndexOpsMixin[S1], NDFrame):
21442155
level: Level | None = ...,
21452156
drop_level: _bool = ...,
21462157
) -> Self: ...
2158+
def __bool__(self) -> NoReturn: ...
21472159

21482160
class TimestampSeries(Series[Timestamp]):
21492161
@property

pandas-stubs/core/strings.pyi

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ from pandas._typing import (
2828
)
2929

3030
# The _TS type is what is used for the result of str.split with expand=True
31-
_TS = TypeVar("_TS", DataFrame, MultiIndex)
31+
_TS = TypeVar("_TS", bound=DataFrame | MultiIndex)
3232
# The _TS2 type is what is used for the result of str.split with expand=False
33-
_TS2 = TypeVar("_TS2", Series[list[str]], Index[list[str]])
33+
_TS2 = TypeVar("_TS2", bound=Series[list[str]] | Index[list[str]])
3434
# The _TM type is what is used for the result of str.match
35-
_TM = TypeVar("_TM", Series[bool], np_ndarray_bool)
35+
_TM = TypeVar("_TM", bound=Series[bool] | np_ndarray_bool)
3636

3737
class StringMethods(NoNewAttributesMixin, Generic[T, _TS, _TM, _TS2]):
3838
def __init__(self, data: T) -> None: ...

pyproject.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ types-pytz = ">= 2022.1.1"
3333
numpy = ">= 1.23.5"
3434

3535
[tool.poetry.group.dev.dependencies]
36-
mypy = "1.13.0"
36+
mypy = "1.14.1"
3737
pandas = "2.2.3"
3838
pyarrow = ">=10.0.1"
3939
pytest = ">=7.1.2"
40-
pyright = ">= 1.1.390"
40+
pyright = ">= 1.1.391"
4141
poethepoet = ">=0.16.5"
4242
loguru = ">=0.6.0"
4343
typing-extensions = ">=4.4.0"

0 commit comments

Comments
 (0)