From f17ef439f017c993501770f02ea16f61636ec967 Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 22 Dec 2025 16:41:49 +0100 Subject: [PATCH 1/3] feat: naming and default values --- pandas-stubs/_libs/interval.pyi | 4 +++- pandas-stubs/_typing.pyi | 25 ++++++++++++++++--------- pandas-stubs/core/frame.pyi | 8 ++++++-- pandas-stubs/core/indexes/base.pyi | 2 +- pandas-stubs/core/indexes/interval.pyi | 4 +++- pandas-stubs/core/reshape/pivot.pyi | 12 ++++++------ pandas-stubs/core/series.pyi | 15 ++++++--------- pandas-stubs/io/json/_json.pyi | 3 ++- tests/__init__.py | 3 ++- tests/frame/test_frame.py | 4 +++- 10 files changed, 48 insertions(+), 32 deletions(-) diff --git a/pandas-stubs/_libs/interval.pyi b/pandas-stubs/_libs/interval.pyi index b749329ef..4b5613fe5 100644 --- a/pandas-stubs/_libs/interval.pyi +++ b/pandas-stubs/_libs/interval.pyi @@ -26,7 +26,9 @@ VALID_CLOSED: frozenset[str] _OrderableScalarT = TypeVar("_OrderableScalarT", bound=int | float) _OrderableTimesT = TypeVar("_OrderableTimesT", bound=Timestamp | Timedelta) -_OrderableT = TypeVar("_OrderableT", bound=int | float | Timestamp | Timedelta) +_OrderableT = TypeVar( + "_OrderableT", bound=int | float | Timestamp | Timedelta, default=Any +) @type_check_only class _LengthDescriptor: diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index b802f79df..9c0798780 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -77,6 +77,7 @@ from pandas.tseries.offsets import ( P = ParamSpec("P") HashableT = TypeVar("HashableT", bound=Hashable) +HashableT0 = TypeVar("HashableT0", bound=Hashable, default=Any) HashableT1 = TypeVar("HashableT1", bound=Hashable) HashableT2 = TypeVar("HashableT2", bound=Hashable) HashableT3 = TypeVar("HashableT3", bound=Hashable) @@ -776,7 +777,7 @@ XMLParsers: TypeAlias = Literal["lxml", "etree"] HTMLFlavors: TypeAlias = Literal["lxml", "html5lib", "bs4"] # Interval closed type -IntervalT = TypeVar("IntervalT", bound=Interval) +IntervalT = TypeVar("IntervalT", bound=Interval, default=Interval) IntervalLeftRight: TypeAlias = Literal["left", "right"] IntervalClosedType: TypeAlias = IntervalLeftRight | Literal["both", "neither"] @@ -874,7 +875,11 @@ ExcelWriterMergeCells: TypeAlias = bool | Literal["columns"] # read_csv: usecols UsecolsArgType: TypeAlias = ( - SequenceNotStr[Hashable] | range | AnyArrayLike | Callable[[HashableT], bool] | None + SequenceNotStr[Hashable] + | range + | AnyArrayLike + | Callable[[HashableT0], bool] + | None ) # maintain the sub-type of any hashable sequence @@ -920,6 +925,7 @@ PyArrowNotStrDtypeArg: TypeAlias = ( StrLike: TypeAlias = str | np.str_ ScalarT = TypeVar("ScalarT", bound=Scalar) +ScalarT0 = TypeVar("ScalarT0", bound=Scalar, default=Scalar) # Refine the definitions below in 3.9 to use the specialized type. np_num: TypeAlias = np.bool | np.integer | np.floating | np.complexfloating np_ndarray_intp: TypeAlias = npt.NDArray[np.intp] @@ -1015,8 +1021,9 @@ SeriesDType: TypeAlias = ( | datetime.datetime # includes pd.Timestamp | datetime.timedelta # includes pd.Timedelta ) +S0 = TypeVar("S0", bound=SeriesDType, default=Any) S1 = TypeVar("S1", bound=SeriesDType, default=Any) -# Like S1, but without `default=Any`. +# Like S0 and S1, but without `default=Any`. S2 = TypeVar("S2", bound=SeriesDType) S2_contra = TypeVar("S2_contra", bound=SeriesDType, contravariant=True) S2_NDT_contra = TypeVar( @@ -1050,14 +1057,14 @@ IndexingInt: TypeAlias = ( ) # AxesData is used for data for Index -AxesData: TypeAlias = Mapping[S3, Any] | Axes | KeysView[S3] +AxesData: TypeAlias = Mapping[S0, Any] | Axes | KeysView[S0] # Any plain Python or numpy function Function: TypeAlias = np.ufunc | Callable[..., Any] # Use a distinct HashableT in shared types to avoid conflicts with # shared HashableT and HashableT#. This one can be used if the identical # type is need in a function that uses GroupByObjectNonScalar -_HashableTa = TypeVar("_HashableTa", bound=Hashable) +_HashableTa = TypeVar("_HashableTa", bound=Hashable, default=Any) if TYPE_CHECKING: # noqa: PYI002 ByT = TypeVar( "ByT", @@ -1075,7 +1082,7 @@ if TYPE_CHECKING: # noqa: PYI002 | Scalar | Period | Interval[int | float | Timestamp | Timedelta] - | tuple, + | tuple[Any, ...], ) # Use a distinct SeriesByT when using groupby with Series of known dtype. # Essentially, an intersection between Series S1 TypeVar, and ByT TypeVar @@ -1130,10 +1137,10 @@ StataDateFormat: TypeAlias = Literal[ # `DataFrame.replace` also accepts mappings of these. ReplaceValue: TypeAlias = ( Scalar - | Pattern + | Pattern[str] | NAType - | Sequence[Scalar | Pattern] - | Mapping[HashableT, ScalarT] + | Sequence[Scalar | Pattern[str]] + | Mapping[HashableT0, ScalarT0] | Series | None ) diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index 29b76ebfd..c8c439b5e 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -2761,8 +2761,12 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): def __rfloordiv__( self, other: float | DataFrame | Series[int] | Series[float] | Sequence[float] ) -> Self: ... - def __truediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ... - def __rtruediv__(self, other: float | DataFrame | Series | Sequence) -> Self: ... + def __truediv__( + self, other: float | DataFrame | Series | Sequence[Any] + ) -> Self: ... + def __rtruediv__( + self, other: float | DataFrame | Series | Sequence[Any] + ) -> Self: ... @final def __bool__(self) -> NoReturn: ... diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index ba5837002..2c1950cc9 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -313,7 +313,7 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): copy: bool = ..., name: Hashable = ..., tupleize_cols: bool = ..., - ) -> IntervalIndex[Interval[Any]]: ... + ) -> IntervalIndex[Interval]: ... @overload def __new__( cls, diff --git a/pandas-stubs/core/indexes/interval.pyi b/pandas-stubs/core/indexes/interval.pyi index c968845c8..388269031 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -243,7 +243,9 @@ class IntervalIndex(ExtensionIndex[IntervalT, np.object_], IntervalMixin): def __contains__(self, key: IntervalT) -> bool: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload def __contains__(self, key: object) -> Literal[False]: ... - def astype(self, dtype: DtypeArg, copy: bool = True) -> IntervalIndex: ... + def astype( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # ty: ignore[invalid-method-override] + self, dtype: DtypeArg, copy: bool = True + ) -> IntervalIndex: ... @property def inferred_type(self) -> str: ... def memory_usage(self, deep: bool = False) -> int: ... diff --git a/pandas-stubs/core/reshape/pivot.pyi b/pandas-stubs/core/reshape/pivot.pyi index 945e912e6..75ed1d038 100644 --- a/pandas-stubs/core/reshape/pivot.pyi +++ b/pandas-stubs/core/reshape/pivot.pyi @@ -61,7 +61,7 @@ _PivotTableColumnsTypes: TypeAlias = ( _PivotTableValuesTypes: TypeAlias = Label | Sequence[Hashable] | None _ExtendedAnyArrayLike: TypeAlias = AnyArrayLike | ArrayLike -_Values: TypeAlias = SequenceNotStr[Any] | _ExtendedAnyArrayLike +_CrossTabValues: TypeAlias = SequenceNotStr[Any] | _ExtendedAnyArrayLike @overload def pivot_table( @@ -118,9 +118,9 @@ def pivot( ) -> DataFrame: ... @overload def crosstab( - index: _Values | list[_Values], - columns: _Values | list[_Values], - values: _Values, + index: _CrossTabValues | list[_CrossTabValues], + columns: _CrossTabValues | list[_CrossTabValues], + values: _CrossTabValues, rownames: SequenceNotStr[Hashable] | None = None, colnames: SequenceNotStr[Hashable] | None = None, *, @@ -132,8 +132,8 @@ def crosstab( ) -> DataFrame: ... @overload def crosstab( - index: _Values | list[_Values], - columns: _Values | list[_Values], + index: _CrossTabValues | list[_CrossTabValues], + columns: _CrossTabValues | list[_CrossTabValues], values: None = None, rownames: SequenceNotStr[Hashable] | None = None, colnames: SequenceNotStr[Hashable] | None = None, diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 7c932b6d8..db3c6a71a 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -128,10 +128,7 @@ from typing_extensions import ( ) import xarray as xr -from pandas._libs.interval import ( - Interval, - _OrderableT, -) +from pandas._libs.interval import Interval from pandas._libs.lib import _NoDefaultDoNotUse from pandas._libs.missing import NAType from pandas._libs.tslibs import BaseOffset @@ -443,16 +440,16 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): def __new__( cls, data: ( - IntervalIndex[Interval[_OrderableT]] - | Interval[_OrderableT] - | Sequence[Interval[_OrderableT]] - | dict[HashableT1, Interval[_OrderableT]] + IntervalIndex[IntervalT] + | IntervalT + | Sequence[IntervalT] + | dict[Hashable, IntervalT] ), index: AxesData | None = None, dtype: Literal["Interval"] = ..., name: Hashable = None, copy: bool | None = None, - ) -> Series[Interval[_OrderableT]]: ... + ) -> Series[IntervalT]: ... @overload def __new__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] cls, diff --git a/pandas-stubs/io/json/_json.pyi b/pandas-stubs/io/json/_json.pyi index aabebb978..dc1f2ac0c 100644 --- a/pandas-stubs/io/json/_json.pyi +++ b/pandas-stubs/io/json/_json.pyi @@ -2,6 +2,7 @@ from collections import abc from collections.abc import Mapping from types import TracebackType from typing import ( + Any, Generic, Literal, overload, @@ -226,7 +227,7 @@ def read_json( engine: Literal["pyarrow"], ) -> DataFrame: ... -class JsonReader(abc.Iterator, Generic[NDFrameT]): +class JsonReader(abc.Iterator[Any], Generic[NDFrameT]): def read(self) -> NDFrameT: ... def close(self) -> None: ... def __iter__(self) -> JsonReader[NDFrameT]: ... diff --git a/tests/__init__.py b/tests/__init__.py index ca2525692..6653740a7 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -8,6 +8,7 @@ import sys from typing import ( TYPE_CHECKING, + Any, Final, Literal, get_args, @@ -160,7 +161,7 @@ def pytest_warns_bounded( upper: str | None = None, version_str: str | None = None, upper_exception: type[Exception] | None = None, -) -> AbstractContextManager: +) -> AbstractContextManager[Any]: """ Version conditional pytest.warns context manager diff --git a/tests/frame/test_frame.py b/tests/frame/test_frame.py index ac0499bb9..c72148337 100644 --- a/tests/frame/test_frame.py +++ b/tests/frame/test_frame.py @@ -3051,7 +3051,9 @@ def test_to_dict_simple() -> None: if TYPE_CHECKING_INVALID_USAGE: - def test(mapping: Mapping) -> None: # pyright: ignore[reportUnusedFunction] + def test( # pyright: ignore[reportUnusedFunction] + mapping: Mapping[Any, Any], + ) -> None: data.to_dict(into=mapping) # type: ignore[call-overload] # pyright: ignore[reportArgumentType,reportCallIssue] def _1() -> None: # pyright: ignore[reportUnusedFunction] From 927610b9496492a42107210c1ee7a9215f2453ba Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Mon, 22 Dec 2025 17:37:31 +0100 Subject: [PATCH 2/3] a few more any's --- pandas-stubs/io/parsers/readers.pyi | 2 +- pandas-stubs/io/sql.pyi | 6 +++--- pandas-stubs/io/stata.pyi | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pandas-stubs/io/parsers/readers.pyi b/pandas-stubs/io/parsers/readers.pyi index e414b4ca3..9f1b77b5e 100644 --- a/pandas-stubs/io/parsers/readers.pyi +++ b/pandas-stubs/io/parsers/readers.pyi @@ -452,7 +452,7 @@ def read_fwf( **kwds: Any, ) -> DataFrame: ... -class TextFileReader(abc.Iterator): +class TextFileReader(abc.Iterator[Any]): engine: CSVEngine orig_options: Mapping[str, Any] chunksize: int | None diff --git a/pandas-stubs/io/sql.pyi b/pandas-stubs/io/sql.pyi index 4d92623de..0d2b36dcf 100644 --- a/pandas-stubs/io/sql.pyi +++ b/pandas-stubs/io/sql.pyi @@ -24,7 +24,7 @@ from pandas._typing import ( DtypeBackend, Scalar, SequenceNotStr, - npt, + np_ndarray, ) _SQLConnection: TypeAlias = str | sqlalchemy.engine.Connectable | sqlite3.Connection @@ -155,7 +155,7 @@ class PandasSQL: dtype: DtypeArg | None = None, method: ( Literal["multi"] - | Callable[[SQLTable, Any, list[str], Iterable], int | None] + | Callable[[SQLTable, Any, list[str], Iterable[Any]], int | None] | None ) = None, engine: str = "auto", @@ -189,7 +189,7 @@ class SQLTable: def exists(self) -> bool: ... def sql_schema(self) -> str: ... def create(self) -> None: ... - def insert_data(self) -> tuple[list[str], list[npt.NDArray]]: ... + def insert_data(self) -> tuple[list[str], list[np_ndarray]]: ... def insert( self, chunksize: int | None = ..., method: str | None = ... ) -> int | None: ... diff --git a/pandas-stubs/io/stata.pyi b/pandas-stubs/io/stata.pyi index ce50b8083..91f47b858 100644 --- a/pandas-stubs/io/stata.pyi +++ b/pandas-stubs/io/stata.pyi @@ -4,6 +4,7 @@ import datetime from io import BytesIO from types import TracebackType from typing import ( + Any, Literal, overload, ) @@ -76,7 +77,7 @@ def read_stata( class StataParser: def __init__(self) -> None: ... -class StataReader(StataParser, abc.Iterator): +class StataReader(StataParser, abc.Iterator[Any]): col_sizes: list[int] = ... path_or_buf: BytesIO = ... def __init__( From 065d491ed820b370959f5b535c331afcf956764e Mon Sep 17 00:00:00 2001 From: cmp0xff Date: Tue, 23 Dec 2025 09:57:00 +0100 Subject: [PATCH 3/3] review --- pandas-stubs/core/indexes/base.pyi | 10 ++++------ pandas-stubs/io/json/_json.pyi | 8 +++++--- pandas-stubs/io/parsers/readers.pyi | 4 ++-- pandas-stubs/io/stata.pyi | 8 +++++--- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 2c1950cc9..e8167bb87 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -68,10 +68,7 @@ from typing_extensions import ( Self, ) -from pandas._libs.interval import ( - Interval, - _OrderableT, -) +from pandas._libs.interval import Interval from pandas._libs.tslibs.period import Period from pandas._libs.tslibs.timedeltas import Timedelta from pandas._typing import ( @@ -97,6 +94,7 @@ from pandas._typing import ( GenericT_co, HashableT, IgnoreRaise, + IntervalT, JoinHow, Just, Label, @@ -297,13 +295,13 @@ class Index(IndexOpsMixin[S1], ElementOpsMixin[S1]): @overload def __new__( cls, - data: Sequence[Interval[_OrderableT]] | IndexOpsMixin[Interval[_OrderableT]], + data: Sequence[IntervalT] | IndexOpsMixin[IntervalT], *, dtype: Literal["Interval"] = ..., copy: bool = ..., name: Hashable = ..., tupleize_cols: bool = ..., - ) -> IntervalIndex[Interval[_OrderableT]]: ... + ) -> IntervalIndex[IntervalT]: ... @overload def __new__( cls, diff --git a/pandas-stubs/io/json/_json.pyi b/pandas-stubs/io/json/_json.pyi index dc1f2ac0c..cae146fb4 100644 --- a/pandas-stubs/io/json/_json.pyi +++ b/pandas-stubs/io/json/_json.pyi @@ -1,5 +1,7 @@ -from collections import abc -from collections.abc import Mapping +from collections.abc import ( + Iterator, + Mapping, +) from types import TracebackType from typing import ( Any, @@ -227,7 +229,7 @@ def read_json( engine: Literal["pyarrow"], ) -> DataFrame: ... -class JsonReader(abc.Iterator[Any], Generic[NDFrameT]): +class JsonReader(Iterator[Any], Generic[NDFrameT]): def read(self) -> NDFrameT: ... def close(self) -> None: ... def __iter__(self) -> JsonReader[NDFrameT]: ... diff --git a/pandas-stubs/io/parsers/readers.pyi b/pandas-stubs/io/parsers/readers.pyi index 9f1b77b5e..90751dbae 100644 --- a/pandas-stubs/io/parsers/readers.pyi +++ b/pandas-stubs/io/parsers/readers.pyi @@ -1,10 +1,10 @@ from collections import ( - abc, defaultdict, ) from collections.abc import ( Callable, Hashable, + Iterator, Mapping, Sequence, ) @@ -452,7 +452,7 @@ def read_fwf( **kwds: Any, ) -> DataFrame: ... -class TextFileReader(abc.Iterator[Any]): +class TextFileReader(Iterator[Any]): engine: CSVEngine orig_options: Mapping[str, Any] chunksize: int | None diff --git a/pandas-stubs/io/stata.pyi b/pandas-stubs/io/stata.pyi index 91f47b858..cb42065ee 100644 --- a/pandas-stubs/io/stata.pyi +++ b/pandas-stubs/io/stata.pyi @@ -1,5 +1,7 @@ -from collections import abc -from collections.abc import Sequence +from collections.abc import ( + Iterator, + Sequence, +) import datetime from io import BytesIO from types import TracebackType @@ -77,7 +79,7 @@ def read_stata( class StataParser: def __init__(self) -> None: ... -class StataReader(StataParser, abc.Iterator[Any]): +class StataReader(StataParser, Iterator[Any]): col_sizes: list[int] = ... path_or_buf: BytesIO = ... def __init__(