From 5a28b37d98fc1e598dd150862ea7ab10da5bd829 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 4 Dec 2025 16:52:31 +0100 Subject: [PATCH 1/2] tuple + space --- pandas-stubs/core/frame.pyi | 4 ++-- pandas-stubs/core/series.pyi | 4 ++-- pandas-stubs/core/tools/datetimes.pyi | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index 69345fa6e..b05050a5d 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -1505,8 +1505,8 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): ) -> Self | Series: ... def melt( self, - id_vars: tuple | Sequence | np_ndarray | None = ..., - value_vars: tuple | Sequence | np_ndarray | None = ..., + id_vars: Sequence[Hashable] | np_ndarray | None = ..., + value_vars: Sequence[Hashable] | np_ndarray | None = ..., var_name: Scalar | None = None, value_name: Scalar = "value", col_level: int | _str | None = ..., diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index c732e3826..7344c977d 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -1179,7 +1179,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): self, func: Callable[..., BaseOffset], convertDType: _bool = ..., - args: tuple = ..., + args: tuple[Any, ...] = ..., **kwargs: Any, ) -> Series[BaseOffset]: ... @overload @@ -1187,7 +1187,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): self, func: Callable[..., Series], convertDType: _bool = ..., - args: tuple = ..., + args: tuple[Any, ...] = ..., **kwargs: Any, ) -> DataFrame: ... @final diff --git a/pandas-stubs/core/tools/datetimes.pyi b/pandas-stubs/core/tools/datetimes.pyi index ebc25900a..61453771f 100644 --- a/pandas-stubs/core/tools/datetimes.pyi +++ b/pandas-stubs/core/tools/datetimes.pyi @@ -4,6 +4,7 @@ from datetime import ( datetime, ) from typing import ( + Any, Literal, TypeAlias, TypedDict, @@ -31,7 +32,7 @@ from pandas._typing import ( np_ndarray_str, ) -ArrayConvertible: TypeAlias = list | tuple | AnyArrayLike +ArrayConvertible: TypeAlias = list[Any] | tuple[Any, ...] | AnyArrayLike Scalar: TypeAlias = float | str DatetimeScalar: TypeAlias = Scalar | datetime | np.datetime64 | date From a9c601c3d20fa4f0c2f24430ef1a39746baaab29 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Thu, 4 Dec 2025 17:24:01 +0100 Subject: [PATCH 2/2] other cases --- pandas-stubs/_typing.pyi | 2 +- pandas-stubs/core/frame.pyi | 4 ++-- pandas-stubs/core/groupby/indexing.pyi | 10 ++++------ pandas-stubs/core/indexes/multi.pyi | 2 +- pandas-stubs/core/series.pyi | 4 ++-- pandas-stubs/io/parquet.pyi | 10 ++++++++-- tests/indexes/test_indexes.py | 12 +++--------- tests/series/test_series.py | 14 +++++++------- tests/test_frame.py | 16 +++++++++------- tests/test_pandas.py | 4 ++-- 10 files changed, 39 insertions(+), 39 deletions(-) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index f7dcd1cfc..04de561d5 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -1080,7 +1080,7 @@ if TYPE_CHECKING: # noqa: PYI002 | Interval[int | float | Timestamp | Timedelta], ) GroupByObjectNonScalar: TypeAlias = ( - tuple + tuple[_HashableTa, ...] | list[_HashableTa] | Function | list[Function] diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index b05050a5d..a855735c5 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -1401,7 +1401,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): group_keys: _bool = ..., observed: _bool | _NoDefaultDoNotUse = ..., dropna: _bool = ..., - ) -> DataFrameGroupBy[tuple, Literal[True]]: ... + ) -> DataFrameGroupBy[tuple[Hashable, ...], Literal[True]]: ... @overload def groupby( # type: ignore[overload-overlap] self, @@ -1412,7 +1412,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): group_keys: _bool = ..., observed: _bool | _NoDefaultDoNotUse = ..., dropna: _bool = ..., - ) -> DataFrameGroupBy[tuple, Literal[False]]: ... + ) -> DataFrameGroupBy[tuple[Hashable, ...], Literal[False]]: ... @overload def groupby( # pyright: ignore reportOverlappingOverload self, diff --git a/pandas-stubs/core/groupby/indexing.pyi b/pandas-stubs/core/groupby/indexing.pyi index 150a7a86b..03b355606 100644 --- a/pandas-stubs/core/groupby/indexing.pyi +++ b/pandas-stubs/core/groupby/indexing.pyi @@ -17,16 +17,14 @@ _GroupByT = TypeVar("_GroupByT", bound=groupby.GroupBy[Any]) class GroupByIndexingMixin: ... -class GroupByPositionalSelector: - groupby_object: groupby.GroupBy - def __getitem__(self, arg: PositionalIndexer | tuple) -> DataFrame | Series: ... - class GroupByNthSelector(Generic[_GroupByT]): groupby_object: _GroupByT def __call__( self, - n: PositionalIndexer | tuple, + n: PositionalIndexer | tuple[int, ...], dropna: Literal["any", "all"] | None = ..., ) -> DataFrame | Series: ... - def __getitem__(self, n: PositionalIndexer | tuple) -> DataFrame | Series: ... + def __getitem__( + self, n: PositionalIndexer | tuple[int, ...] + ) -> DataFrame | Series: ... diff --git a/pandas-stubs/core/indexes/multi.pyi b/pandas-stubs/core/indexes/multi.pyi index dbb9b766e..720ea4a37 100644 --- a/pandas-stubs/core/indexes/multi.pyi +++ b/pandas-stubs/core/indexes/multi.pyi @@ -135,7 +135,7 @@ class MultiIndex(Index): @overload def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] self, key: int - ) -> tuple: ... + ) -> tuple[Hashable, ...]: ... def append(self, other): ... def repeat(self, repeats, axis=...): ... def drop(self, codes, level: Level | None = None, errors: str = "raise") -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 7344c977d..2ba77208f 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -845,7 +845,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): group_keys: _bool = ..., observed: _bool | _NoDefaultDoNotUse = ..., dropna: _bool = ..., - ) -> SeriesGroupBy[S1, tuple]: ... + ) -> SeriesGroupBy[S1, tuple[Hashable, ...]]: ... @overload def groupby( self, @@ -1171,7 +1171,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): ..., Scalar | Sequence | set | Mapping | NAType | frozenset | None ], convertDType: _bool = ..., - args: tuple = ..., + args: tuple[Any, ...] = ..., **kwargs: Any, ) -> Series: ... @overload diff --git a/pandas-stubs/io/parquet.pyi b/pandas-stubs/io/parquet.pyi index c9c9bd154..faf69aaf7 100644 --- a/pandas-stubs/io/parquet.pyi +++ b/pandas-stubs/io/parquet.pyi @@ -1,4 +1,8 @@ -from typing import Any +from collections.abc import Sequence +from typing import ( + Any, + TypeAlias, +) from pandas import DataFrame @@ -10,6 +14,8 @@ from pandas._typing import ( StorageOptions, ) +_Filter: TypeAlias = tuple[str, str, Any] + def read_parquet( path: FilePath | ReadBuffer[bytes], engine: ParquetEngine = "auto", @@ -17,6 +23,6 @@ def read_parquet( storage_options: StorageOptions = None, dtype_backend: DtypeBackend = "numpy_nullable", filesystem: Any = None, - filters: list[tuple] | list[list[tuple]] | None = None, + filters: Sequence[_Filter] | Sequence[Sequence[_Filter]] | None = None, **kwargs: Any, ) -> DataFrame: ... diff --git a/tests/indexes/test_indexes.py b/tests/indexes/test_indexes.py index 56e1e87ae..d044e65d4 100644 --- a/tests/indexes/test_indexes.py +++ b/tests/indexes/test_indexes.py @@ -964,10 +964,7 @@ def test_getitem() -> None: iints = pd.interval_range(dt.datetime(2000, 1, 1), dt.datetime(2010, 1, 1), 5) check( - assert_type( - iints, - "pd.IntervalIndex[pd.Interval[pd.Timestamp]]", - ), + assert_type(iints, "pd.IntervalIndex[pd.Interval[pd.Timestamp]]"), pd.IntervalIndex, pd.Interval, ) @@ -980,10 +977,7 @@ def test_getitem() -> None: iintd = pd.interval_range(pd.Timedelta("1D"), pd.Timedelta("10D")) check( - assert_type( - iintd, - "pd.IntervalIndex[pd.Interval[pd.Timedelta]]", - ), + assert_type(iintd, "pd.IntervalIndex[pd.Interval[pd.Timedelta]]"), pd.IntervalIndex, pd.Interval, ) @@ -1005,7 +999,7 @@ def test_getitem() -> None: mi = pd.MultiIndex.from_product([["a", "b"], ["c", "d"]], names=["ab", "cd"]) check(assert_type(mi, pd.MultiIndex), pd.MultiIndex) - check(assert_type(mi[0], tuple), tuple) + check(assert_type(mi[0], tuple[Hashable, ...]), tuple, str) check(assert_type(mi[[0, 2]], pd.MultiIndex), pd.MultiIndex, tuple) i0 = pd.Index(["a", "b", "c"]) diff --git a/tests/series/test_series.py b/tests/series/test_series.py index be96e4a9b..406846fca 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -1015,14 +1015,14 @@ def test_groupby_result() -> None: multi_index = pd.MultiIndex.from_tuples([(0, 0), (0, 1), (1, 0)], names=["a", "b"]) s = pd.Series([0, 1, 2], index=multi_index, dtype=int) iterator = s.groupby(["a", "b"]).__iter__() - assert_type(iterator, Iterator[tuple[tuple, "pd.Series[int]"]]) + assert_type(iterator, Iterator[tuple[tuple[Hashable, ...], "pd.Series[int]"]]) index, value = next(iterator) - assert_type((index, value), tuple[tuple, "pd.Series[int]"]) + assert_type((index, value), tuple[tuple[Hashable, ...], "pd.Series[int]"]) if PD_LTE_23: - check(assert_type(index, tuple), tuple, np.integer) + check(assert_type(index, tuple[Hashable, ...]), tuple, np.integer) else: - check(assert_type(index, tuple), tuple, int) + check(assert_type(index, tuple[Hashable, ...]), tuple, int) check(assert_type(value, "pd.Series[int]"), pd.Series, np.integer) @@ -1037,11 +1037,11 @@ def test_groupby_result() -> None: # GH 674 # grouping by pd.MultiIndex should always resolve to a tuple as well iterator3 = s.groupby(multi_index).__iter__() - assert_type(iterator3, Iterator[tuple[tuple, "pd.Series[int]"]]) + assert_type(iterator3, Iterator[tuple[tuple[Hashable, ...], "pd.Series[int]"]]) index3, value3 = next(iterator3) - assert_type((index3, value3), tuple[tuple, "pd.Series[int]"]) + assert_type((index3, value3), tuple[tuple[Hashable, ...], "pd.Series[int]"]) - check(assert_type(index3, tuple), tuple, int) + check(assert_type(index3, tuple[Hashable, ...]), tuple, int) check(assert_type(value3, "pd.Series[int]"), pd.Series, np.integer) # Explicit by=None diff --git a/tests/test_frame.py b/tests/test_frame.py index 60e6292e6..569d48f02 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -2959,6 +2959,8 @@ def test_groupby_series_methods() -> None: check(assert_type(gb.nlargest(), pd.Series), pd.Series) check(assert_type(gb.nsmallest(), pd.Series), pd.Series) check(assert_type(gb.nth(0), pd.DataFrame | pd.Series), pd.Series) + check(assert_type(gb.nth[0, 1, 2], pd.DataFrame | pd.Series), pd.Series) + check(assert_type(gb.nth((0, 1, 2)), pd.DataFrame | pd.Series), pd.Series) def test_dataframe_pct_change() -> None: @@ -3591,14 +3593,14 @@ def test_groupby_result() -> None: # GH 142 df = pd.DataFrame({"a": [0, 1, 2], "b": [4, 5, 6], "c": [7, 8, 9]}) iterator = df.groupby(["a", "b"]).__iter__() - assert_type(iterator, Iterator[tuple[tuple, pd.DataFrame]]) + assert_type(iterator, Iterator[tuple[tuple[Hashable, ...], pd.DataFrame]]) index, value = next(iterator) - assert_type((index, value), tuple[tuple, pd.DataFrame]) + assert_type((index, value), tuple[tuple[Hashable, ...], pd.DataFrame]) if PD_LTE_23: - check(assert_type(index, tuple), tuple, np.integer) + check(assert_type(index, tuple[Hashable, ...]), tuple, np.integer) else: - check(assert_type(index, tuple), tuple, int) + check(assert_type(index, tuple[Hashable, ...]), tuple, int) check(assert_type(value, pd.DataFrame), pd.DataFrame) @@ -3614,11 +3616,11 @@ def test_groupby_result() -> None: # grouping by pd.MultiIndex should always resolve to a tuple as well multi_index = pd.MultiIndex.from_frame(df[["a", "b"]]) iterator3 = df.groupby(multi_index).__iter__() - assert_type(iterator3, Iterator[tuple[tuple, pd.DataFrame]]) + assert_type(iterator3, Iterator[tuple[tuple[Hashable, ...], pd.DataFrame]]) index3, value3 = next(iterator3) - assert_type((index3, value3), tuple[tuple, pd.DataFrame]) + assert_type((index3, value3), tuple[tuple[Hashable, ...], pd.DataFrame]) - check(assert_type(index3, tuple), tuple, int) + check(assert_type(index3, tuple[Hashable, ...]), tuple, int) check(assert_type(value3, pd.DataFrame), pd.DataFrame) # Want to make sure these cases are differentiated diff --git a/tests/test_pandas.py b/tests/test_pandas.py index 98a70ebb4..fe60bc889 100644 --- a/tests/test_pandas.py +++ b/tests/test_pandas.py @@ -1712,8 +1712,8 @@ def m2(x: pd.Series) -> int: assert_type(pd.crosstab(a, b, colnames=["a"], rownames=["b"]), pd.DataFrame), pd.DataFrame, ) - rownames: list[tuple] = [("b", 1)] - colnames: list[tuple] = [("a",)] + rownames: list[tuple[str, int]] = [("b", 1)] + colnames: list[tuple[str]] = [("a",)] check( assert_type( pd.crosstab(a, b, colnames=colnames, rownames=rownames),