From 367ee7d353d159627e2e7f08081d39c385317d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Diridollou?= Date: Fri, 14 Nov 2025 21:04:27 -0500 Subject: [PATCH 1/9] GH1432 Partial resolution --- pandas-stubs/_libs/tslibs/timestamps.pyi | 13 +++++++++++-- pandas-stubs/io/orc.pyi | 6 +++--- pyproject.toml | 1 + tests/scalars/test_scalars.py | 13 ++++++++++++- tests/test_timefuncs.py | 4 ++++ 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index 5dbb28c8f..e2a693307 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -32,6 +32,7 @@ from pandas._libs.tslibs import ( Tick, Timedelta, ) +from pandas._libs.tslibs.nattype import NaTType from pandas._typing import ( PeriodFrequency, ShapeT, @@ -228,7 +229,7 @@ class Timestamp(datetime, SupportsIndex): def __radd__( self, other: np_ndarray[ShapeT, np.timedelta64] ) -> np_ndarray[ShapeT, np.datetime64]: ... - # TODO: pandas-dev/pandas-stubs#1432 test dt64 + def __rsub__(self, other: datetime | np.datetime64) -> Timedelta: ... @overload # type: ignore[override] def __sub__(self, other: datetime | np.datetime64) -> Timedelta: ... @overload @@ -284,7 +285,15 @@ class Timestamp(datetime, SupportsIndex): @property def asm8(self) -> np.datetime64: ... def tz_convert(self, tz: TimeZones) -> Self: ... - # TODO: pandas-dev/pandas-stubs#1432 could return NaT? + @overload + def tz_localize( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, + tz: TimeZones, + ambiguous: _Ambiguous = "raise", + *, + nonexistent: Literal["NaT"], + ) -> Self | NaTType: ... + @overload def tz_localize( self, tz: TimeZones, diff --git a/pandas-stubs/io/orc.pyi b/pandas-stubs/io/orc.pyi index 3bcda0499..d361df0b1 100644 --- a/pandas-stubs/io/orc.pyi +++ b/pandas-stubs/io/orc.pyi @@ -1,6 +1,8 @@ from typing import Any +from fsspec.spec import AbstractFileSystem # pyright: ignore[reportMissingTypeStubs] from pandas import DataFrame +from pyarrow.fs import FileSystem from pandas._libs.lib import _NoDefaultDoNotUse from pandas._typing import ( @@ -14,8 +16,6 @@ def read_orc( path: FilePath | ReadBuffer[bytes], columns: list[HashableT] | None = None, dtype_backend: DtypeBackend | _NoDefaultDoNotUse = "numpy_nullable", - # TODO: pandas-dev/pandas-stubs#1432 type with the correct pyarrow types - # filesystem: pyarrow.fs.FileSystem | fsspec.spec.AbstractFileSystem - filesystem: Any | None = None, + filesystem: FileSystem | AbstractFileSystem | None = None, **kwargs: Any, ) -> DataFrame: ... diff --git a/pyproject.toml b/pyproject.toml index 8d476f581..c6c34172e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,7 @@ beautifulsoup4 = ">=4.14.2" html5lib = ">=1.1" python-calamine = ">=0.2.0" pyarrow-stubs = { version = ">=20.0.0.20250928", python = "<4" } +fsspec = "^2025.10.0" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/scalars/test_scalars.py b/tests/scalars/test_scalars.py index 36c7f59fc..4c59e82db 100644 --- a/tests/scalars/test_scalars.py +++ b/tests/scalars/test_scalars.py @@ -1385,9 +1385,20 @@ def test_timestamp_misc_methods() -> None: pd.Timestamp, ) check( - assert_type(ts.tz_localize("US/Pacific", nonexistent="NaT"), pd.Timestamp), + assert_type( + ts.tz_localize("US/Pacific", nonexistent="NaT"), pd.Timestamp | NaTType + ), pd.Timestamp, ) + check( + assert_type( + pd.Timestamp(2025, 3, 9, 2, 30, 0).tz_localize( + "US/Eastern", nonexistent="NaT" + ), + pd.Timestamp | NaTType, + ), + NaTType, + ) check( assert_type(ts.tz_localize("US/Pacific", nonexistent="raise"), pd.Timestamp), pd.Timestamp, diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 6d599ecfa..c90913c3f 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -95,9 +95,13 @@ def test_types_init() -> None: def test_types_arithmetic() -> None: ts = pd.to_datetime("2021-03-01") ts2 = pd.to_datetime("2021-01-01") + ts_np = np.datetime64("2021-01-01") delta = pd.to_timedelta("1 day") check(assert_type(ts - ts2, pd.Timedelta), pd.Timedelta) + check(assert_type(ts - ts_np, pd.Timedelta), pd.Timedelta) + # TODO: pandas-dev/pandas-stubs#1432 mypy sees datetime.timedelta but pyright is correct + # check(assert_type(ts_np - ts, pd.Timedelta), pd.Timedelta) check(assert_type(ts + delta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - delta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - dt.datetime(2021, 1, 3), pd.Timedelta), pd.Timedelta) From f12e0fef610dc07fe091408969b44cf824bf20bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Diridollou?= Date: Sun, 16 Nov 2025 21:21:56 -0500 Subject: [PATCH 2/9] GH1432 PR Feedback --- pandas-stubs/core/indexes/interval.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas-stubs/core/indexes/interval.pyi b/pandas-stubs/core/indexes/interval.pyi index 193ceb08e..c36384e34 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -322,8 +322,8 @@ def interval_range( ) -> IntervalIndex[Interval[pd.Timestamp]]: ... @overload def interval_range( - *, start: None = None, + *, end: _TimestampLike, periods: int | None = ..., freq: Frequency | dt.timedelta | None = ..., @@ -341,8 +341,8 @@ def interval_range( ) -> IntervalIndex[Interval[pd.Timedelta]]: ... @overload def interval_range( - *, start: None = None, + *, end: _TimedeltaLike, periods: int | None = ..., freq: Frequency | dt.timedelta | None = ..., From b82986c40bb3da8888c836b91baee2c9c9276d26 Mon Sep 17 00:00:00 2001 From: Marco Edward Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 26 Nov 2025 16:50:00 +0000 Subject: [PATCH 3/9] type Index methods: putmask, asof, asof_locs, sort_values, get_indexer_non_unique, get_indexer_for, map, get_slice_bound (#1505) * type Index methods: putmask, asof, asof_locs, sort_values, get_indexer_non_unique, get_indexer_for, map, get_slice_bound * remove redundant `IntervalIndexer.get_indexer_non_unique` * slice_locs can return either `np.integer` or `int` * fix slice_locs test * Apply suggestions from code review Co-authored-by: Yi-Fan Wang * np.integer -> np.intp * test more mask types for `putmask` * Apply suggestions from code review Co-authored-by: Yi-Fan Wang * test asof with str --------- Co-authored-by: Yi-Fan Wang --- pandas-stubs/core/indexes/base.pyi | 47 +++++++++++----- pandas-stubs/core/indexes/interval.pyi | 3 - tests/indexes/test_indexes.py | 76 ++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 16 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 42ef02183..e26b41adb 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -106,6 +106,7 @@ from pandas._typing import ( PandasFloatDtypeArg, PyArrowFloatDtypeArg, ReindexMethod, + Renamer, S2_contra, Scalar, SequenceNotStr, @@ -532,39 +533,59 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): ) -> Index[C2]: ... @overload def append(self, other: Index | Sequence[Index]) -> Index: ... - def putmask(self, mask, value): ... + def putmask( + self, + mask: Sequence[bool] | np_ndarray_bool | BooleanArray | IndexOpsMixin[bool], + value: Scalar, + ) -> Index: ... def equals(self, other: Any) -> bool: ... @final def identical(self, other: Any) -> bool: ... @final - def asof(self, label): ... - def asof_locs(self, where, mask): ... + def asof(self, label: Scalar) -> Scalar: ... + def asof_locs( + self, where: DatetimeIndex, mask: np_ndarray_bool + ) -> np_1darray_intp: ... + @overload def sort_values( self, *, - return_indexer: bool = ..., - ascending: bool = ..., - na_position: NaPosition = ..., + return_indexer: Literal[False] = False, + ascending: bool = True, + na_position: NaPosition = "last", key: Callable[[Index], Index] | None = None, - ): ... + ) -> Self: ... + @overload + def sort_values( + self, + *, + return_indexer: Literal[True], + ascending: bool = True, + na_position: NaPosition = "last", + key: Callable[[Index], Index] | None = None, + ) -> tuple[Self, np_1darray_intp]: ... @final def sort(self, *args: Any, **kwargs: Any) -> None: ... def argsort(self, *args: Any, **kwargs: Any) -> np_1darray_intp: ... - def get_indexer_non_unique(self, target): ... + def get_indexer_non_unique( + self, target: Index + ) -> tuple[np_1darray_intp, np_1darray_intp]: ... @final - def get_indexer_for(self, target, **kwargs: Any): ... - def map(self, mapper, na_action=...) -> Index: ... + def get_indexer_for(self, target: Index) -> np_1darray_intp: ... + def map( + self, mapper: Renamer, na_action: Literal["ignore"] | None = None + ) -> Index: ... def isin(self, values, level=...) -> np_1darray_bool: ... def slice_indexer( self, start: Label | None = None, end: Label | None = None, step: int | None = None, - ): ... - def get_slice_bound(self, label, side): ... + ) -> slice: ... + def get_slice_bound(self, label: Scalar, side: Literal["left", "right"]) -> int: ... def slice_locs( self, start: SliceType = None, end: SliceType = None, step: int | None = None - ): ... + ) -> tuple[int | np.intp, int | np.intp]: ... def delete( self, loc: np.integer | int | AnyArrayLikeInt | Sequence[int] ) -> Self: ... diff --git a/pandas-stubs/core/indexes/interval.pyi b/pandas-stubs/core/indexes/interval.pyi index 0b4d18517..186a7a0a1 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -214,9 +214,6 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): @property def is_overlapping(self) -> bool: ... def get_loc(self, key: Label) -> int | slice | np_1darray_bool: ... - def get_indexer_non_unique( - self, target: Index - ) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp]]: ... @property def left(self) -> Index: ... @property diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index f155efaff..f876c19aa 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -23,6 +23,8 @@ assert_type, ) +from pandas._typing import Scalar # noqa: F401 + from tests import ( PD_LTE_23, TYPE_CHECKING_INVALID_USAGE, @@ -1582,3 +1584,77 @@ def test_index_setitem() -> None: idx = pd.Index([1, 2]) if TYPE_CHECKING_INVALID_USAGE: idx[0] = 999 # type: ignore[index] # pyright: ignore[reportIndexIssue] + + +def test_index_putmask() -> None: + idx = pd.Index([1, 2]) + check(assert_type(idx.putmask([True, False], 11.4), "pd.Index"), pd.Index) + check(assert_type(idx.putmask(np.array([True, False]), 11.4), "pd.Index"), pd.Index) + check( + assert_type(idx.putmask(pd.Series([True, False]), 11.4), "pd.Index"), pd.Index + ) + check(assert_type(idx.putmask(pd.Index([True, False]), 11.4), "pd.Index"), pd.Index) + check(assert_type(idx.putmask(pd.array([True, False]), 11.5), "pd.Index"), pd.Index) + + +def test_index_asof() -> None: + check(assert_type(pd.Index([1, 2]).asof(1), "Scalar"), np.integer) + check(assert_type(pd.Index(["a", "b", "c"]).asof("c"), "Scalar"), str) + + +def test_index_asof_locs() -> None: + idx = pd.DatetimeIndex(["2020-01-01", "2020-01-02", "2020-01-03"]) + check( + assert_type( + idx.asof_locs( + pd.DatetimeIndex(["2020-01-01 11:00"]), np.array([True, True, True]) + ), + np_1darray_intp, + ), + np_1darray_intp, + ) + + +def test_index_sort_values() -> None: + idx = pd.DatetimeIndex(["2020-01-01", "2020-01-02", "2020-01-03"]) + check(assert_type(idx.sort_values(), pd.DatetimeIndex), pd.DatetimeIndex) + sorted_index, indexer = idx.sort_values(return_indexer=True) + check(assert_type(sorted_index, pd.DatetimeIndex), pd.DatetimeIndex) + check(assert_type(indexer, np_1darray_intp), np_1darray_intp) + + +def test_index_get_indexer_non_unique() -> None: + idx = pd.Index([1, 3]) + indexer, missing = idx.get_indexer_non_unique(pd.Index([3])) + check(assert_type(indexer, np_1darray_intp), np_1darray_intp) + check(assert_type(missing, np_1darray_intp), np_1darray_intp) + + +def test_index_get_indexer_for() -> None: + idx = pd.Index([1, 3]) + check( + assert_type(idx.get_indexer_for(pd.Index([3])), np_1darray_intp), + np_1darray_intp, + ) + + +def test_index_map() -> None: + idx = pd.Index([1, 3]) + check(assert_type(idx.map(lambda x: str(x)), pd.Index), pd.Index) + + +def test_index_slice_indexer() -> None: + idx = pd.Index([1, 3]) + check(assert_type(idx.slice_indexer(0, 1), slice), slice) + + +def test_index_get_slice_bound() -> None: + idx = pd.Index([1, 3]) + check(assert_type(idx.get_slice_bound(1, side="left"), int), int) + + +def test_index_slice_locs() -> None: + idx = pd.Index([1, 3]) + start, end = idx.slice_locs(0, 1) + check(assert_type(start, np.intp | int), np.integer) + check(assert_type(end, np.intp | int), int) From b04b3e4e813ad7bc4f273a475d231b30d1d5e0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Diridollou?= Date: Thu, 27 Nov 2025 09:01:10 -0500 Subject: [PATCH 4/9] GH1432 PR Feedback --- tests/test_timefuncs.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index c90913c3f..00ed514d7 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -96,16 +96,21 @@ def test_types_arithmetic() -> None: ts = pd.to_datetime("2021-03-01") ts2 = pd.to_datetime("2021-01-01") ts_np = np.datetime64("2021-01-01") + ts_np_time = np.datetime64("2021-01-01 08:00:05") delta = pd.to_timedelta("1 day") check(assert_type(ts - ts2, pd.Timedelta), pd.Timedelta) check(assert_type(ts - ts_np, pd.Timedelta), pd.Timedelta) - # TODO: pandas-dev/pandas-stubs#1432 mypy sees datetime.timedelta but pyright is correct - # check(assert_type(ts_np - ts, pd.Timedelta), pd.Timedelta) + check(assert_type(ts - ts_np_time, pd.Timedelta), pd.Timedelta) check(assert_type(ts + delta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - delta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - dt.datetime(2021, 1, 3), pd.Timedelta), pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + # TODO: pandas-dev/pandas-stubs#1432 mypy sees datetime.timedelta but pyright is correct + assert_type(ts_np - ts, pd.Timedelta) # type: ignore[assert-type] + assert_type(ts_np_time - ts, pd.Timedelta) # type: ignore[assert-type] + def test_types_comparison() -> None: ts = pd.to_datetime("2021-03-01") From 852ef644eeeaa8c67434deea18da9e73e88481f8 Mon Sep 17 00:00:00 2001 From: Yi-Fan Wang Date: Sun, 30 Nov 2025 21:02:44 +0100 Subject: [PATCH 5/9] FIX: #1508 numpy 1darrays in tests (#1512) fix: #1508 numpy arrays in tests --- pandas-stubs/core/base.pyi | 3 +++ pandas-stubs/core/indexes/base.pyi | 11 ++++++++- pandas-stubs/core/series.pyi | 29 ++++++++++++++++++------ tests/__init__.py | 10 ++++----- tests/series/test_series.py | 21 +++++++++-------- tests/test_timefuncs.py | 36 ++++++++++-------------------- 6 files changed, 64 insertions(+), 46 deletions(-) diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index 1e3a93bf9..1dc1d1c2c 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -10,6 +10,7 @@ from typing import ( Literal, Protocol, TypeAlias, + TypeVar, final, overload, type_check_only, @@ -53,6 +54,8 @@ from pandas._typing import ( ) from pandas.util._decorators import cache_readonly +T_INTERVAL_NP = TypeVar("T_INTERVAL_NP", bound=np.bytes_ | np.str_) + class NoNewAttributesMixin: def __setattr__(self, key: str, value: Any) -> None: ... diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index e26b41adb..2c7d9aeb0 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -32,6 +32,7 @@ import numpy as np from pandas.core.arrays.boolean import BooleanArray from pandas.core.arrays.floating import FloatingArray from pandas.core.base import ( + T_INTERVAL_NP, ArrayIndexTimedeltaNoSeq, ElementOpsMixin, IndexComplex, @@ -1189,6 +1190,14 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @type_check_only class _IndexSubclassBase(Index[S1], Generic[S1, GenericT_co]): + @overload + def to_numpy( + self: _IndexSubclassBase[Interval], + dtype: type[T_INTERVAL_NP], + copy: bool = False, + na_value: Scalar = ..., + **kwargs: Any, + ) -> np_1darray: ... @overload def to_numpy( self, @@ -1206,7 +1215,7 @@ class _IndexSubclassBase(Index[S1], Generic[S1, GenericT_co]): **kwargs: Any, ) -> np_1darray[GenericT]: ... @overload - def to_numpy( + def to_numpy( # pyright: ignore[reportIncompatibleMethodOverride] self, dtype: DTypeLike, copy: bool = False, diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 9b5fc9619..a31926ced 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -29,7 +29,6 @@ from typing import ( NoReturn, Protocol, TypeAlias, - TypeVar, final, overload, type_check_only, @@ -71,6 +70,7 @@ from pandas.core.arrays.datetimes import DatetimeArray from pandas.core.arrays.floating import FloatingArray from pandas.core.arrays.timedeltas import TimedeltaArray from pandas.core.base import ( + T_INTERVAL_NP, ArrayIndexSeriesTimedeltaNoSeq, ArrayIndexTimedeltaNoSeq, ElementOpsMixin, @@ -189,6 +189,7 @@ from pandas._typing import ( MaskType, NaPosition, NsmallestNlargestKeep, + NumpyStrDtypeArg, ObjectDtypeArg, PandasAstypeComplexDtypeArg, PandasAstypeFloatDtypeArg, @@ -251,8 +252,6 @@ from pandas.core.dtypes.dtypes import CategoricalDtype from pandas.plotting import PlotAccessor -_T_INTERVAL_NP = TypeVar("_T_INTERVAL_NP", bound=np.bytes_ | np.str_) - @type_check_only class _SupportsAdd(Protocol[_T_co]): def __add__(self, value: Self, /) -> _T_co: ... @@ -4503,7 +4502,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): copy: bool = False, na_value: Scalar = ..., **kwargs: Any, - ) -> np_1darray_bytes: ... + ) -> np_1darray: ... @overload def to_numpy( self: Series[Interval], @@ -4515,11 +4514,11 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def to_numpy( self: Series[Interval], - dtype: type[_T_INTERVAL_NP], + dtype: type[T_INTERVAL_NP], copy: bool = False, na_value: Scalar = ..., **kwargs: Any, - ) -> np_1darray[_T_INTERVAL_NP]: ... + ) -> np_1darray: ... @overload def to_numpy( self: Series[int], @@ -4555,12 +4554,28 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): @overload def to_numpy( self: Series[_str], - dtype: DTypeLike | None = None, + dtype: NumpyStrDtypeArg, copy: bool = False, na_value: Scalar = ..., **kwargs: Any, ) -> np_1darray_str: ... @overload + def to_numpy( + self: Series[_str], + dtype: DTypeLike, + copy: bool = False, + na_value: Scalar = ..., + **kwargs: Any, + ) -> np_1darray: ... + @overload + def to_numpy( + self: Series[_str], + dtype: None = None, + copy: bool = False, + na_value: Scalar = ..., + **kwargs: Any, + ) -> np_1darray_object: ... + @overload def to_numpy( self: Series[bytes], dtype: DTypeLike | None = None, diff --git a/tests/__init__.py b/tests/__init__.py index 34530dfee..facc36a8a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -439,11 +439,11 @@ _S = TypeVar("_S", bound=tuple[int, ...]) # Separately define here so pytest works np_1darray: TypeAlias = np.ndarray[tuple[int], np.dtype[_G]] - np_1darray_bool: TypeAlias = np.ndarray[tuple[int], np.bool_] - np_1darray_str: TypeAlias = np.ndarray[tuple[int], np.str_] - np_1darray_bytes: TypeAlias = np.ndarray[tuple[int], np.bytes_] - np_1darray_complex: TypeAlias = np.ndarray[tuple[int], np.complexfloating] - np_1darray_object: TypeAlias = np.ndarray[tuple[int], np.object_] + np_1darray_bool: TypeAlias = np_1darray[np.bool_] + np_1darray_str: TypeAlias = np_1darray[np.str_] + np_1darray_bytes: TypeAlias = np_1darray[np.bytes_] + np_1darray_complex: TypeAlias = np_1darray[np.complexfloating] + np_1darray_object: TypeAlias = np_1darray[np.object_] np_1darray_intp: TypeAlias = np_1darray[np.intp] np_1darray_int64: TypeAlias = np_1darray[np.int64] np_1darray_anyint: TypeAlias = np_1darray[np.integer] diff --git a/tests/series/test_series.py b/tests/series/test_series.py index dc2417a8d..81082b7fd 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -73,7 +73,6 @@ np_1darray_dt, np_1darray_float, np_1darray_object, - np_1darray_str, np_1darray_td, np_ndarray_num, pytest_warns_bounded, @@ -2004,18 +2003,22 @@ def test_dtype_type() -> None: def test_types_to_numpy() -> None: s = pd.Series(["a", "b", "c"], dtype=str) - check(assert_type(s.to_numpy(), np_1darray_str), np_1darray_str) + check(assert_type(s.to_numpy(), np_1darray_object), np_1darray_object) + check( # None: def test_to_numpy() -> None: """Test Series.to_numpy for different types.""" s_str = pd.Series(["a", "b", "c"], dtype=str) - check(assert_type(s_str.to_numpy(), np_1darray_str), np_1darray_str) + check(assert_type(s_str.to_numpy(), np_1darray_object), np_1darray_object) s_bytes = pd.Series(["a", "b", "c"]).astype(bytes) check(assert_type(s_bytes.to_numpy(), np_1darray_bytes), np_1darray, np.bytes_) diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 6d599ecfa..066259d7c 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -30,11 +30,9 @@ check, np_1darray, np_1darray_bool, - np_1darray_bytes, np_1darray_dt, np_1darray_int64, np_1darray_object, - np_1darray_str, np_1darray_td, pytest_warns_bounded, ) @@ -956,14 +954,8 @@ def test_series_types_to_numpy() -> None: np_1darray, dtype=np.integer, ) - check( - assert_type(o_s.to_numpy(dtype="bytes", copy=True), np_1darray), - np_1darray_bytes, - ) - check( - assert_type(i_s.to_numpy(dtype="bytes", copy=True), np_1darray), - np_1darray_bytes, - ) + check(assert_type(o_s.to_numpy(dtype="bytes", copy=True), np_1darray), np_1darray) + check(assert_type(i_s.to_numpy(dtype="bytes", copy=True), np_1darray), np_1darray) # passed dtype-like with statically known generic check( @@ -991,13 +983,12 @@ def test_series_types_to_numpy() -> None: np_1darray, np.int64, ) - check( - assert_type(o_s.to_numpy(dtype=np.bytes_), np_1darray_bytes), np_1darray_bytes - ) - check( - assert_type(i_s.to_numpy(dtype=np.bytes_), np_1darray_bytes), np_1darray_bytes - ) - check(assert_type(i_s.to_numpy(dtype=np.str_), np_1darray_str), np_1darray_str) + # |S20, not bytes_ + check(assert_type(o_s.to_numpy(dtype=np.bytes_), np_1darray), np_1darray) + # |S6, not bytes_ + check(assert_type(i_s.to_numpy(dtype=np.bytes_), np_1darray), np_1darray) + # None: @@ -1056,10 +1047,8 @@ def test_index_types_to_numpy() -> None: np_1darray, dtype=np.integer, ) - check( - assert_type(i_i.to_numpy(dtype="bytes", copy=True), np_1darray), - np_1darray_bytes, - ) + # |S6, not bytes_ + check(assert_type(i_i.to_numpy(dtype="bytes", copy=True), np_1darray), np_1darray) # passed dtype-like with statically known generic check( @@ -1077,9 +1066,8 @@ def test_index_types_to_numpy() -> None: np_1darray, np.int64, ) - check( - assert_type(i_i.to_numpy(dtype=np.bytes_), np_1darray_bytes), np_1darray_bytes - ) + # |S6, not bytes_ + check(assert_type(i_i.to_numpy(dtype=np.bytes_), np_1darray), np_1darray) def test_to_timedelta_units() -> None: From 2448b5fb8cf8c9e699d342c629fa7f90bbfd733d Mon Sep 17 00:00:00 2001 From: Loic Diridollou Date: Sun, 30 Nov 2025 15:20:30 -0500 Subject: [PATCH 6/9] GH1484 Upgrade ty (#1509) * GH1484 Upgrade ty * GH1484 Fix formatting * GH1484 Update PR --- pandas-stubs/_libs/missing.pyi | 4 ++-- pandas-stubs/_libs/tslibs/timedeltas.pyi | 2 +- pandas-stubs/_libs/tslibs/timestamps.pyi | 18 +++++++++++----- pandas-stubs/core/arrays/categorical.pyi | 4 ++-- pandas-stubs/core/arrays/datetimelike.pyi | 4 ++-- pandas-stubs/core/arrays/interval.pyi | 4 ++-- pandas-stubs/core/arrays/sparse/array.pyi | 4 ++-- pandas-stubs/core/frame.pyi | 26 +++++++++++------------ pandas-stubs/core/groupby/generic.pyi | 12 ++++++----- pandas-stubs/core/indexes/datetimes.pyi | 2 +- pandas-stubs/core/indexes/interval.pyi | 14 ++++++------ pandas-stubs/core/indexes/multi.pyi | 2 +- pandas-stubs/core/indexes/period.pyi | 4 ++-- pandas-stubs/core/indexes/range.pyi | 4 ++-- pandas-stubs/core/indexes/timedeltas.pyi | 22 +++++++++++-------- pandas-stubs/core/series.pyi | 26 +++++++++++++---------- pyproject.toml | 2 +- 17 files changed, 86 insertions(+), 68 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index 4b7f244b9..8e02c6ae0 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -117,7 +117,7 @@ class NAType: @overload def __eq__(self, other: Index, /) -> BooleanArray: ... @overload - def __eq__( # pyright: ignore[reportIncompatibleMethodOverride] + def __eq__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: Scalar, / ) -> NAType: ... @overload # type: ignore[override] @@ -127,7 +127,7 @@ class NAType: @overload def __ne__(self, other: Index, /) -> BooleanArray: ... @overload - def __ne__( # pyright: ignore[reportIncompatibleMethodOverride] + def __ne__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: Scalar, / ) -> NAType: ... @overload diff --git a/pandas-stubs/_libs/tslibs/timedeltas.pyi b/pandas-stubs/_libs/tslibs/timedeltas.pyi index 5d808bb09..aea145dc3 100644 --- a/pandas-stubs/_libs/tslibs/timedeltas.pyi +++ b/pandas-stubs/_libs/tslibs/timedeltas.pyi @@ -259,7 +259,7 @@ class Timedelta(timedelta): self, other: np_ndarray[ShapeT, np.integer | np.floating] ) -> np_ndarray[ShapeT, np.timedelta64]: ... @overload - def __truediv__( + def __truediv__( # ty: ignore[invalid-method-override] self, other: np_ndarray[ShapeT, np.timedelta64] ) -> np_ndarray[ShapeT, np.floating]: ... @overload diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index 5dbb28c8f..ce2a2dee8 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -180,7 +180,9 @@ class Timestamp(datetime, SupportsIndex): self, other: np_ndarray[ShapeT, np.datetime64] ) -> np_ndarray[ShapeT, np.bool]: ... @overload - def __le__(self, other: Series[Timestamp]) -> Series[bool]: ... + def __le__( # ty: ignore[invalid-method-override] + self, other: Series[Timestamp] + ) -> Series[bool]: ... @overload # type: ignore[override] def __lt__(self, other: datetime | np.datetime64 | Self) -> bool: ... @overload @@ -190,7 +192,9 @@ class Timestamp(datetime, SupportsIndex): self, other: np_ndarray[ShapeT, np.datetime64] ) -> np_ndarray[ShapeT, np.bool]: ... @overload - def __lt__(self, other: Series[Timestamp]) -> Series[bool]: ... + def __lt__( # ty: ignore[invalid-method-override] + self, other: Series[Timestamp] + ) -> Series[bool]: ... @overload # type: ignore[override] def __ge__(self, other: datetime | np.datetime64 | Self) -> bool: ... @overload @@ -200,7 +204,9 @@ class Timestamp(datetime, SupportsIndex): self, other: np_ndarray[ShapeT, np.datetime64] ) -> np_ndarray[ShapeT, np.bool]: ... @overload - def __ge__(self, other: Series[Timestamp]) -> Series[bool]: ... + def __ge__( # ty: ignore[invalid-method-override] + self, other: Series[Timestamp] + ) -> Series[bool]: ... @overload # type: ignore[override] def __gt__(self, other: datetime | np.datetime64 | Self) -> bool: ... @overload @@ -210,7 +216,9 @@ class Timestamp(datetime, SupportsIndex): self, other: np_ndarray[ShapeT, np.datetime64] ) -> np_ndarray[ShapeT, np.bool]: ... @overload - def __gt__(self, other: Series[Timestamp]) -> Series[bool]: ... + def __gt__( # ty: ignore[invalid-method-override] + self, other: Series[Timestamp] + ) -> Series[bool]: ... # error: Signature of "__add__" incompatible with supertype "date"/"datetime" @overload # type: ignore[override] def __add__( @@ -236,7 +244,7 @@ class Timestamp(datetime, SupportsIndex): @overload def __sub__(self, other: TimedeltaIndex) -> DatetimeIndex: ... @overload - def __sub__( + def __sub__( # ty: ignore[invalid-method-override] self, other: np_ndarray[ShapeT, np.timedelta64] ) -> np_ndarray[ShapeT, np.datetime64]: ... @overload diff --git a/pandas-stubs/core/arrays/categorical.pyi b/pandas-stubs/core/arrays/categorical.pyi index 3ea880995..77f2a23ae 100644 --- a/pandas-stubs/core/arrays/categorical.pyi +++ b/pandas-stubs/core/arrays/categorical.pyi @@ -111,11 +111,11 @@ class Categorical(ExtensionArray): def take( self, indexer: TakeIndexer, *, allow_fill: bool = ..., fill_value=... ) -> Categorical: ... - def __contains__(self, key) -> bool: ... + def __contains__(self, item) -> bool: ... @overload def __getitem__(self, key: ScalarIndexer) -> Any: ... @overload - def __getitem__( + def __getitem__( # ty: ignore[invalid-method-override] self, key: SequenceIndexer | PositionalIndexerTuple, ) -> Self: ... diff --git a/pandas-stubs/core/arrays/datetimelike.pyi b/pandas-stubs/core/arrays/datetimelike.pyi index f392f64f2..a699b43e2 100644 --- a/pandas-stubs/core/arrays/datetimelike.pyi +++ b/pandas-stubs/core/arrays/datetimelike.pyi @@ -73,9 +73,9 @@ class DatetimeLikeArrayMixin(ExtensionOpsMixin, ExtensionArray): @overload def __getitem__(self, key: ScalarIndexer) -> DTScalarOrNaT: ... @overload - def __getitem__( + def __getitem__( # ty: ignore[invalid-method-override] self, - key: SequenceIndexer | PositionalIndexerTuple, + item: SequenceIndexer | PositionalIndexerTuple, ) -> Self: ... def __setitem__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] self, key: int | Sequence[int] | Sequence[bool] | slice, value diff --git a/pandas-stubs/core/arrays/interval.pyi b/pandas-stubs/core/arrays/interval.pyi index cdad76567..169a295e7 100644 --- a/pandas-stubs/core/arrays/interval.pyi +++ b/pandas-stubs/core/arrays/interval.pyi @@ -61,9 +61,9 @@ class IntervalArray(IntervalMixin, ExtensionArray): self, dtype: NpDtype | None = None, copy: bool | None = None ) -> np_1darray: ... @overload - def __getitem__(self, key: ScalarIndexer) -> IntervalOrNA: ... + def __getitem__(self, item: ScalarIndexer) -> IntervalOrNA: ... @overload - def __getitem__(self, key: SequenceIndexer) -> Self: ... + def __getitem__(self, item: SequenceIndexer) -> Self: ... def __setitem__(self, key, value) -> None: ... def __eq__(self, other): ... def __ne__(self, other): ... diff --git a/pandas-stubs/core/arrays/sparse/array.pyi b/pandas-stubs/core/arrays/sparse/array.pyi index 780d1786e..0d6863bbb 100644 --- a/pandas-stubs/core/arrays/sparse/array.pyi +++ b/pandas-stubs/core/arrays/sparse/array.pyi @@ -63,9 +63,9 @@ class SparseArray(ExtensionArray, ExtensionOpsMixin): @overload def __getitem__(self, key: ScalarIndexer) -> Any: ... @overload - def __getitem__( + def __getitem__( # ty: ignore[invalid-method-override] self, - key: SequenceIndexer | tuple[int | ellipsis, ...], + item: SequenceIndexer | tuple[int | ellipsis, ...], ) -> Self: ... def copy(self): ... def map(self, mapper): ... diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index d03189dca..344121c01 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -182,17 +182,17 @@ _T_MUTABLE_MAPPING_co = TypeVar( class _iLocIndexerFrame(_iLocIndexer, Generic[_T]): @overload - def __getitem__(self, idx: tuple[int, int]) -> Scalar: ... + def __getitem__(self, key: tuple[int, int]) -> Scalar: ... @overload - def __getitem__(self, idx: IndexingInt) -> Series: ... + def __getitem__(self, key: IndexingInt) -> Series: ... @overload - def __getitem__(self, idx: tuple[IndexType | MaskType, int]) -> Series: ... + def __getitem__(self, key: tuple[IndexType | MaskType, int]) -> Series: ... @overload - def __getitem__(self, idx: tuple[int, IndexType | MaskType]) -> Series: ... + def __getitem__(self, key: tuple[int, IndexType | MaskType]) -> Series: ... @overload def __getitem__( self, - idx: ( + key: ( IndexType | MaskType | tuple[IndexType | MaskType, IndexType | MaskType] @@ -203,7 +203,7 @@ class _iLocIndexerFrame(_iLocIndexer, Generic[_T]): # Keep in sync with `DataFrame.__setitem__` def __setitem__( self, - idx: ( + key: ( int | IndexType | tuple[int, int] @@ -262,7 +262,7 @@ class _LocIndexerFrame(_LocIndexer, Generic[_T]): @overload def __getitem__( self, - idx: ( + key: ( IndexType | MaskType | Callable[[DataFrame], IndexType | MaskType | Sequence[Hashable]] @@ -283,7 +283,7 @@ class _LocIndexerFrame(_LocIndexer, Generic[_T]): @overload def __setitem__( self, - idx: ( + key: ( MaskType | StrLike | _IndexSliceTuple | list[ScalarT] | IndexingInt | slice ), value: ( @@ -302,7 +302,7 @@ class _LocIndexerFrame(_LocIndexer, Generic[_T]): @overload def __setitem__( self, - idx: tuple[_IndexSliceTuple, Hashable], + key: tuple[_IndexSliceTuple, Hashable], value: ( Scalar | NAType @@ -317,17 +317,17 @@ class _LocIndexerFrame(_LocIndexer, Generic[_T]): ) -> None: ... class _iAtIndexerFrame(_iAtIndexer): - def __getitem__(self, idx: tuple[int, int]) -> Scalar: ... + def __getitem__(self, key: tuple[int, int]) -> Scalar: ... def __setitem__( self, - idx: tuple[int, int], + key: tuple[int, int], value: Scalar | NAType | NaTType | None, ) -> None: ... class _AtIndexerFrame(_AtIndexer): def __getitem__( self, - idx: tuple[ + key: tuple[ int | StrLike | Timestamp @@ -338,7 +338,7 @@ class _AtIndexerFrame(_AtIndexer): ) -> Scalar: ... def __setitem__( self, - idx: ( + key: ( MaskType | StrLike | _IndexSliceTuple | list[ScalarT] | IndexingInt | slice ), value: ( diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index bbd764d77..ac06e7311 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -205,7 +205,7 @@ class SeriesGroupBy(GroupBy[Series[S2]], Generic[S2, ByT]): # Overrides that provide more precise return types over the GroupBy class @final # type: ignore[misc] # pyrefly: ignore # bad-override - def __iter__( # pyright: ignore[reportIncompatibleMethodOverride] + def __iter__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[override-of-final-method] self, ) -> Iterator[tuple[ByT, Series[S2]]]: ... @@ -244,7 +244,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT, _TT]): **kwargs: P.kwargs, ) -> DataFrame: ... @overload - def apply( + def apply( # ty: ignore[invalid-method-override] self, func: DFCallable3[P], /, @@ -297,7 +297,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT, _TT]): @overload def __getitem__(self, key: Scalar) -> SeriesGroupBy[Any, ByT]: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload - def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] + def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, key: Iterable[Hashable] ) -> DataFrameGroupBy[ByT, _TT]: ... def nunique(self, dropna: bool = True) -> DataFrame: ... @@ -449,11 +449,13 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT, _TT]): ) -> Series: ... # Series[Axes] but this is not allowed @property def dtypes(self) -> Series: ... - def __getattr__(self, name: str) -> SeriesGroupBy[Any, ByT]: ... + def __getattr__( + self, name: str + ) -> SeriesGroupBy[Any, ByT]: ... # ty: ignore[invalid-method-override] # Overrides that provide more precise return types over the GroupBy class @final # type: ignore[misc] # pyrefly: ignore # bad-override - def __iter__( # pyright: ignore[reportIncompatibleMethodOverride] + def __iter__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[override-of-final-method] self, ) -> Iterator[tuple[ByT, DataFrame]]: ... @overload diff --git a/pandas-stubs/core/indexes/datetimes.pyi b/pandas-stubs/core/indexes/datetimes.pyi index 662f4fc4f..dac70fd07 100644 --- a/pandas-stubs/core/indexes/datetimes.pyi +++ b/pandas-stubs/core/indexes/datetimes.pyi @@ -73,7 +73,7 @@ class DatetimeIndex( self, other: datetime | np.datetime64 | np_ndarray_dt | Self ) -> TimedeltaIndex: ... @overload - def __sub__( # pyright: ignore[reportIncompatibleMethodOverride] + def __sub__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: timedelta | np.timedelta64 | np_ndarray_td | BaseOffset ) -> Self: ... def __truediv__( # type: ignore[override] # pyrefly: ignore[bad-override] diff --git a/pandas-stubs/core/indexes/interval.pyi b/pandas-stubs/core/indexes/interval.pyi index 186a7a0a1..8470b8b78 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -236,7 +236,7 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): ), ) -> IntervalIndex[IntervalT]: ... @overload - def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] + def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, idx: int ) -> IntervalT: ... @overload # type: ignore[override] @@ -244,7 +244,7 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): self, other: IntervalT | IntervalIndex[IntervalT] ) -> np_1darray_bool: ... @overload - def __gt__( # pyright: ignore[reportIncompatibleMethodOverride] + def __gt__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: pd.Series[IntervalT] ) -> pd.Series[bool]: ... @overload # type: ignore[override] @@ -252,7 +252,7 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): self, other: IntervalT | IntervalIndex[IntervalT] ) -> np_1darray_bool: ... @overload - def __ge__( # pyright: ignore[reportIncompatibleMethodOverride] + def __ge__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: pd.Series[IntervalT] ) -> pd.Series[bool]: ... @overload # type: ignore[override] @@ -260,7 +260,7 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): self, other: IntervalT | IntervalIndex[IntervalT] ) -> np_1darray_bool: ... @overload - def __le__( # pyright: ignore[reportIncompatibleMethodOverride] + def __le__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: pd.Series[IntervalT] ) -> pd.Series[bool]: ... @overload # type: ignore[override] @@ -268,7 +268,7 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): self, other: IntervalT | IntervalIndex[IntervalT] ) -> np_1darray_bool: ... @overload - def __lt__( # pyright: ignore[reportIncompatibleMethodOverride] + def __lt__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: pd.Series[IntervalT] ) -> pd.Series[bool]: ... @overload # type: ignore[override] @@ -276,7 +276,7 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): @overload def __eq__(self, other: pd.Series[IntervalT]) -> pd.Series[bool]: ... # type: ignore[overload-overlap] @overload - def __eq__( # pyright: ignore[reportIncompatibleMethodOverride] + def __eq__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: object ) -> Literal[False]: ... @overload # type: ignore[override] @@ -284,7 +284,7 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): @overload def __ne__(self, other: pd.Series[IntervalT]) -> pd.Series[bool]: ... # type: ignore[overload-overlap] @overload - def __ne__( # pyright: ignore[reportIncompatibleMethodOverride] + def __ne__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: object ) -> Literal[True]: ... diff --git a/pandas-stubs/core/indexes/multi.pyi b/pandas-stubs/core/indexes/multi.pyi index 3b3564295..64c0c85c9 100644 --- a/pandas-stubs/core/indexes/multi.pyi +++ b/pandas-stubs/core/indexes/multi.pyi @@ -132,7 +132,7 @@ class MultiIndex(Index): idx: slice | np_ndarray_anyint | Sequence[int] | Index | MaskType, ) -> Self: ... @overload - def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] + def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, key: int ) -> tuple: ... def append(self, other): ... diff --git a/pandas-stubs/core/indexes/period.pyi b/pandas-stubs/core/indexes/period.pyi index 96052bab8..b70fac3e4 100644 --- a/pandas-stubs/core/indexes/period.pyi +++ b/pandas-stubs/core/indexes/period.pyi @@ -54,7 +54,7 @@ class PeriodIndex(DatetimeIndexOpsMixin[pd.Period, np.object_], PeriodIndexField @overload def __sub__(self, other: NaTType) -> NaTType: ... @overload - def __sub__( # pyright: ignore[reportIncompatibleMethodOverride] + def __sub__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: TimedeltaIndex | pd.Timedelta ) -> Self: ... @overload # type: ignore[override] @@ -63,7 +63,7 @@ class PeriodIndex(DatetimeIndexOpsMixin[pd.Period, np.object_], PeriodIndexField @overload def __rsub__(self, other: Self) -> Index: ... @overload - def __rsub__( # pyright: ignore[reportIncompatibleMethodOverride] + def __rsub__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: NaTType ) -> NaTType: ... def asof_locs( diff --git a/pandas-stubs/core/indexes/range.pyi b/pandas-stubs/core/indexes/range.pyi index b752fe2c5..8b3ca4b82 100644 --- a/pandas-stubs/core/indexes/range.pyi +++ b/pandas-stubs/core/indexes/range.pyi @@ -60,7 +60,7 @@ class RangeIndex(_IndexSubclassBase[int, np.int64]): def is_monotonic_decreasing(self) -> bool: ... @property def has_duplicates(self) -> bool: ... - def factorize( + def factorize( # ty: ignore[invalid-method-override] self, sort: bool = False, use_na_sentinel: bool = True ) -> tuple[np_1darray_intp, RangeIndex]: ... @property @@ -81,7 +81,7 @@ class RangeIndex(_IndexSubclassBase[int, np.int64]): idx: slice | np_ndarray_anyint | Sequence[int] | Index | MaskType, ) -> Index: ... @overload - def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] + def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, idx: int ) -> int: ... def where( # type: ignore[override] diff --git a/pandas-stubs/core/indexes/timedeltas.pyi b/pandas-stubs/core/indexes/timedeltas.pyi index 46d861bdf..0f80fec5c 100644 --- a/pandas-stubs/core/indexes/timedeltas.pyi +++ b/pandas-stubs/core/indexes/timedeltas.pyi @@ -74,7 +74,7 @@ class TimedeltaIndex( @overload def __add__(self, other: datetime | DatetimeIndex) -> DatetimeIndex: ... @overload - def __add__( # pyright: ignore[reportIncompatibleMethodOverride] + def __add__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: timedelta | Self ) -> Self: ... @overload # type: ignore[override] @@ -83,7 +83,7 @@ class TimedeltaIndex( @overload def __radd__(self, other: datetime | DatetimeIndex) -> DatetimeIndex: ... @overload - def __radd__( # pyright: ignore[reportIncompatibleMethodOverride] + def __radd__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: timedelta | Self ) -> Self: ... def __sub__( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] @@ -95,17 +95,21 @@ class TimedeltaIndex( self, other: timedelta | np.timedelta64 | np_ndarray_td | BaseOffset | Self ) -> Self: ... @overload - def __rsub__( # pyright: ignore[reportIncompatibleMethodOverride] + def __rsub__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: datetime | np.datetime64 | np_ndarray_dt | DatetimeIndex ) -> DatetimeIndex: ... @overload # type: ignore[override] def __mul__(self, other: np_ndarray_bool | np_ndarray_complex) -> Never: ... @overload - def __mul__(self, other: _NUM_FACTOR_SEQ) -> Self: ... + def __mul__( + self, other: _NUM_FACTOR_SEQ + ) -> Self: ... # ty: ignore[invalid-method-override] @overload # type: ignore[override] def __rmul__(self, other: np_ndarray_bool | np_ndarray_complex) -> Never: ... @overload - def __rmul__(self, other: _NUM_FACTOR_SEQ) -> Self: ... + def __rmul__( + self, other: _NUM_FACTOR_SEQ + ) -> Self: ... # ty: ignore[invalid-method-override] @overload # type: ignore[override] def __truediv__( # type: ignore[overload-overlap] self, other: Index[Never] @@ -117,7 +121,7 @@ class TimedeltaIndex( @overload def __truediv__(self, other: _NUM_FACTOR_SEQ) -> Self: ... @overload - def __truediv__( # pyright: ignore[reportIncompatibleMethodOverride] + def __truediv__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: _DT_FACTOR_SEQ | Self ) -> Index[float]: ... @overload # type: ignore[override] @@ -125,7 +129,7 @@ class TimedeltaIndex( self, other: np_ndarray_bool | np_ndarray_complex | np_ndarray_dt ) -> Never: ... @overload - def __rtruediv__( # pyright: ignore[reportIncompatibleMethodOverride] + def __rtruediv__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: _DT_FACTOR_SEQ | Self ) -> Index[float]: ... @overload # type: ignore[override] @@ -135,7 +139,7 @@ class TimedeltaIndex( @overload def __floordiv__(self, other: _NUM_FACTOR_SEQ) -> Self: ... @overload - def __floordiv__( # pyright: ignore[reportIncompatibleMethodOverride] + def __floordiv__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: _DT_FACTOR_SEQ | Self ) -> Index[int]: ... @overload @@ -143,7 +147,7 @@ class TimedeltaIndex( self, other: np_ndarray_num | np_ndarray_dt ) -> Never: ... @overload - def __rfloordiv__( # pyright: ignore[reportIncompatibleMethodOverride] + def __rfloordiv__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, other: _DT_FACTOR_SEQ | Self ) -> Index[int]: ... @property diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index a31926ced..dfa25dc93 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -275,7 +275,7 @@ class _iLocIndexerSeries(_iLocIndexer, Generic[S1]): def __getitem__(self, idx: IndexingInt) -> S1: ... @overload def __getitem__( - self, idx: Index | Series | slice | np_ndarray_anyint + self, key: Index | Series | slice | np_ndarray_anyint ) -> Series[S1]: ... # set item @@ -285,7 +285,7 @@ class _iLocIndexerSeries(_iLocIndexer, Generic[S1]): @overload def __setitem__( self, - idx: Index | slice | np_ndarray_anyint | list[int], + key: Index | slice | np_ndarray_anyint | list[int], value: S1 | IndexOpsMixin[S1] | None, ) -> None: ... @@ -294,9 +294,9 @@ class _LocIndexerSeries(_LocIndexer, Generic[S1]): # ignore needed because of mypy. Overlapping, but we want to distinguish # having a tuple of just scalars, versus tuples that include slices or Index @overload - def __getitem__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + def __getitem__( # type: ignore[overload-overlap] self, - idx: Scalar | tuple[Scalar, ...], + key: Scalar | tuple[Scalar, ...], # tuple case is for getting a specific element when using a MultiIndex ) -> S1: ... @overload @@ -332,14 +332,11 @@ class _LocIndexerSeries(_LocIndexer, Generic[S1]): @overload def __setitem__( self, - idx: MaskType | StrLike | _IndexSliceTuple | list[ScalarT], + key: MaskType | StrLike | _IndexSliceTuple | list[ScalarT], value: S1 | ArrayLike | IndexOpsMixin[S1] | None, ) -> None: ... _DataLike: TypeAlias = ArrayLike | dict[str, np_ndarray] | SequenceNotStr[S1] -_DataLikeS1: TypeAlias = ( - ArrayLike | dict[_str, np_ndarray] | Sequence[S1] | IndexOpsMixin[S1] -) class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): # Define __index__ because mypy thinks Series follows protocol `SupportsIndex` https://github.com/pandas-dev/pandas-stubs/pull/1332#discussion_r2285648790 @@ -516,7 +513,14 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): def __new__( cls, data: ( - S1 | _DataLikeS1[S1] | dict[HashableT1, S1] | KeysView[S1] | ValuesView[S1] + S1 + | ArrayLike + | dict[_str, np_ndarray] + | Sequence[S1] + | IndexOpsMixin[S1] + | dict[HashableT1, S1] + | KeysView[S1] + | ValuesView[S1] ), index: AxesData | None = None, dtype: Dtype | None = None, @@ -558,7 +562,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): def __array_ufunc__( self, ufunc: Callable, method: _str, *inputs: Any, **kwargs: Any ) -> Any: ... - def __array__( + def __array__( # ty: ignore[invalid-method-override] self, dtype: _str | np.dtype = ..., copy: bool | None = ... ) -> np_1darray: ... @property @@ -4646,7 +4650,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): copy: _bool | _NoDefaultDoNotUse = ..., ) -> Self: ... @final - def xs( # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override] + def xs( # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override] # ty: ignore[invalid-method-override] self, key: Hashable, axis: AxisIndex = 0, # type: ignore[override] diff --git a/pyproject.toml b/pyproject.toml index 8d476f581..6faae00e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,7 @@ pandas = "2.3.3" pyarrow = ">=10.0.1" pytest = ">=8.4.2" pyright = ">=1.1.407" -ty = "0.0.1a25" +ty = ">=0.0.1a28" pyrefly = ">=0.39.4" poethepoet = ">=0.16.5" loguru = ">=0.6.0" From 8ea03998207236b161676e931636f693ed1e2582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Diridollou?= Date: Fri, 14 Nov 2025 21:04:27 -0500 Subject: [PATCH 7/9] GH1432 Partial resolution --- pandas-stubs/_libs/tslibs/timestamps.pyi | 13 +++++++++++-- pandas-stubs/io/orc.pyi | 6 +++--- pyproject.toml | 1 + tests/scalars/test_scalars.py | 13 ++++++++++++- tests/test_timefuncs.py | 4 ++++ 5 files changed, 31 insertions(+), 6 deletions(-) diff --git a/pandas-stubs/_libs/tslibs/timestamps.pyi b/pandas-stubs/_libs/tslibs/timestamps.pyi index ce2a2dee8..250158c2d 100644 --- a/pandas-stubs/_libs/tslibs/timestamps.pyi +++ b/pandas-stubs/_libs/tslibs/timestamps.pyi @@ -32,6 +32,7 @@ from pandas._libs.tslibs import ( Tick, Timedelta, ) +from pandas._libs.tslibs.nattype import NaTType from pandas._typing import ( PeriodFrequency, ShapeT, @@ -236,7 +237,7 @@ class Timestamp(datetime, SupportsIndex): def __radd__( self, other: np_ndarray[ShapeT, np.timedelta64] ) -> np_ndarray[ShapeT, np.datetime64]: ... - # TODO: pandas-dev/pandas-stubs#1432 test dt64 + def __rsub__(self, other: datetime | np.datetime64) -> Timedelta: ... @overload # type: ignore[override] def __sub__(self, other: datetime | np.datetime64) -> Timedelta: ... @overload @@ -292,7 +293,15 @@ class Timestamp(datetime, SupportsIndex): @property def asm8(self) -> np.datetime64: ... def tz_convert(self, tz: TimeZones) -> Self: ... - # TODO: pandas-dev/pandas-stubs#1432 could return NaT? + @overload + def tz_localize( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, + tz: TimeZones, + ambiguous: _Ambiguous = "raise", + *, + nonexistent: Literal["NaT"], + ) -> Self | NaTType: ... + @overload def tz_localize( self, tz: TimeZones, diff --git a/pandas-stubs/io/orc.pyi b/pandas-stubs/io/orc.pyi index 3bcda0499..d361df0b1 100644 --- a/pandas-stubs/io/orc.pyi +++ b/pandas-stubs/io/orc.pyi @@ -1,6 +1,8 @@ from typing import Any +from fsspec.spec import AbstractFileSystem # pyright: ignore[reportMissingTypeStubs] from pandas import DataFrame +from pyarrow.fs import FileSystem from pandas._libs.lib import _NoDefaultDoNotUse from pandas._typing import ( @@ -14,8 +16,6 @@ def read_orc( path: FilePath | ReadBuffer[bytes], columns: list[HashableT] | None = None, dtype_backend: DtypeBackend | _NoDefaultDoNotUse = "numpy_nullable", - # TODO: pandas-dev/pandas-stubs#1432 type with the correct pyarrow types - # filesystem: pyarrow.fs.FileSystem | fsspec.spec.AbstractFileSystem - filesystem: Any | None = None, + filesystem: FileSystem | AbstractFileSystem | None = None, **kwargs: Any, ) -> DataFrame: ... diff --git a/pyproject.toml b/pyproject.toml index 6faae00e8..46fc93532 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,7 @@ beautifulsoup4 = ">=4.14.2" html5lib = ">=1.1" python-calamine = ">=0.2.0" pyarrow-stubs = { version = ">=20.0.0.20250928", python = "<4" } +fsspec = "^2025.10.0" [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/scalars/test_scalars.py b/tests/scalars/test_scalars.py index 36c7f59fc..4c59e82db 100644 --- a/tests/scalars/test_scalars.py +++ b/tests/scalars/test_scalars.py @@ -1385,9 +1385,20 @@ def test_timestamp_misc_methods() -> None: pd.Timestamp, ) check( - assert_type(ts.tz_localize("US/Pacific", nonexistent="NaT"), pd.Timestamp), + assert_type( + ts.tz_localize("US/Pacific", nonexistent="NaT"), pd.Timestamp | NaTType + ), pd.Timestamp, ) + check( + assert_type( + pd.Timestamp(2025, 3, 9, 2, 30, 0).tz_localize( + "US/Eastern", nonexistent="NaT" + ), + pd.Timestamp | NaTType, + ), + NaTType, + ) check( assert_type(ts.tz_localize("US/Pacific", nonexistent="raise"), pd.Timestamp), pd.Timestamp, diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 066259d7c..9f8775f2d 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -93,9 +93,13 @@ def test_types_init() -> None: def test_types_arithmetic() -> None: ts = pd.to_datetime("2021-03-01") ts2 = pd.to_datetime("2021-01-01") + ts_np = np.datetime64("2021-01-01") delta = pd.to_timedelta("1 day") check(assert_type(ts - ts2, pd.Timedelta), pd.Timedelta) + check(assert_type(ts - ts_np, pd.Timedelta), pd.Timedelta) + # TODO: pandas-dev/pandas-stubs#1432 mypy sees datetime.timedelta but pyright is correct + # check(assert_type(ts_np - ts, pd.Timedelta), pd.Timedelta) check(assert_type(ts + delta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - delta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - dt.datetime(2021, 1, 3), pd.Timedelta), pd.Timedelta) From 2b2d4df90ae82ec103182c1d06e08cf2e61a5170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Diridollou?= Date: Thu, 27 Nov 2025 09:01:10 -0500 Subject: [PATCH 8/9] GH1432 PR Feedback --- tests/test_timefuncs.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 9f8775f2d..9d855c079 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -94,16 +94,21 @@ def test_types_arithmetic() -> None: ts = pd.to_datetime("2021-03-01") ts2 = pd.to_datetime("2021-01-01") ts_np = np.datetime64("2021-01-01") + ts_np_time = np.datetime64("2021-01-01 08:00:05") delta = pd.to_timedelta("1 day") check(assert_type(ts - ts2, pd.Timedelta), pd.Timedelta) check(assert_type(ts - ts_np, pd.Timedelta), pd.Timedelta) - # TODO: pandas-dev/pandas-stubs#1432 mypy sees datetime.timedelta but pyright is correct - # check(assert_type(ts_np - ts, pd.Timedelta), pd.Timedelta) + check(assert_type(ts - ts_np_time, pd.Timedelta), pd.Timedelta) check(assert_type(ts + delta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - delta, pd.Timestamp), pd.Timestamp) check(assert_type(ts - dt.datetime(2021, 1, 3), pd.Timedelta), pd.Timedelta) + if TYPE_CHECKING_INVALID_USAGE: + # TODO: pandas-dev/pandas-stubs#1432 mypy sees datetime.timedelta but pyright is correct + assert_type(ts_np - ts, pd.Timedelta) # type: ignore[assert-type] + assert_type(ts_np_time - ts, pd.Timedelta) # type: ignore[assert-type] + def test_types_comparison() -> None: ts = pd.to_datetime("2021-03-01") From d21b13e0cb562dfd0eb9715d4b462864bcdcf235 Mon Sep 17 00:00:00 2001 From: Loic Diridollou Date: Sun, 30 Nov 2025 15:33:58 -0500 Subject: [PATCH 9/9] Update tests/test_timefuncs.py Co-authored-by: Yi-Fan Wang --- tests/test_timefuncs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_timefuncs.py b/tests/test_timefuncs.py index 00ed514d7..cc6487d0f 100644 --- a/tests/test_timefuncs.py +++ b/tests/test_timefuncs.py @@ -107,9 +107,9 @@ def test_types_arithmetic() -> None: check(assert_type(ts - dt.datetime(2021, 1, 3), pd.Timedelta), pd.Timedelta) if TYPE_CHECKING_INVALID_USAGE: - # TODO: pandas-dev/pandas-stubs#1432 mypy sees datetime.timedelta but pyright is correct - assert_type(ts_np - ts, pd.Timedelta) # type: ignore[assert-type] - assert_type(ts_np_time - ts, pd.Timedelta) # type: ignore[assert-type] + # TODO: pandas-dev/pandas-stubs#1511 numpy.datetime64.__sub__ gives datetime.timedelta, which has higher priority + assert_type(ts_np - ts, dt.timedelta) # pyright: ignore[reportAssertTypeFailure] + assert_type(ts_np_time - ts, dt.timedelta) # pyright: ignore[reportAssertTypeFailure def test_types_comparison() -> None: