diff --git a/pandas-stubs/_libs/interval.pyi b/pandas-stubs/_libs/interval.pyi index b749329ef..8a12a1c54 100644 --- a/pandas-stubs/_libs/interval.pyi +++ b/pandas-stubs/_libs/interval.pyi @@ -14,6 +14,7 @@ from pandas import ( Timedelta, Timestamp, ) +from typing_extensions import Self from pandas._typing import ( IntervalClosedType, @@ -26,7 +27,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: @@ -73,12 +76,12 @@ class Interval(IntervalMixin, Generic[_OrderableT]): def closed(self) -> IntervalClosedType: ... mid = _MidDescriptor() length = _LengthDescriptor() - def __init__( - self, + def __new__( + cls, left: _OrderableT, right: _OrderableT, closed: IntervalClosedType = ..., - ) -> None: ... + ) -> Self: ... def __hash__(self) -> int: ... @overload def __contains__(self: Interval[int], key: float | np.floating) -> bool: ... 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 24508f43a..0414d5730 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 906478325..15a032a6f 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -324,7 +324,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 e54359edc..cb29b78e3 100644 --- a/pandas-stubs/core/indexes/interval.pyi +++ b/pandas-stubs/core/indexes/interval.pyi @@ -243,7 +243,7 @@ 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: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override] + def astype(self, dtype: DtypeArg, copy: bool = True) -> IntervalIndex: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] # pyrefly: ignore[bad-override] # ty: ignore[invalid-method-override] @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 93db36672..ae905aa3d 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -446,7 +446,7 @@ class Series(IndexOpsMixin[S1], ElementOpsMixin[S1], NDFrame): IntervalIndex[Interval[_OrderableT]] | Interval[_OrderableT] | Sequence[Interval[_OrderableT]] - | dict[HashableT1, Interval[_OrderableT]] + | dict[Hashable, Interval[_OrderableT]] ), index: AxesData | None = None, dtype: Literal["Interval"] = ..., diff --git a/pandas-stubs/io/json/_json.pyi b/pandas-stubs/io/json/_json.pyi index aabebb978..cae146fb4 100644 --- a/pandas-stubs/io/json/_json.pyi +++ b/pandas-stubs/io/json/_json.pyi @@ -1,7 +1,10 @@ -from collections import abc -from collections.abc import Mapping +from collections.abc import ( + Iterator, + Mapping, +) from types import TracebackType from typing import ( + Any, Generic, Literal, overload, @@ -226,7 +229,7 @@ def read_json( engine: Literal["pyarrow"], ) -> DataFrame: ... -class JsonReader(abc.Iterator, 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 e414b4ca3..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): +class TextFileReader(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..cb42065ee 100644 --- a/pandas-stubs/io/stata.pyi +++ b/pandas-stubs/io/stata.pyi @@ -1,9 +1,12 @@ -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 from typing import ( + Any, Literal, overload, ) @@ -76,7 +79,7 @@ def read_stata( class StataParser: def __init__(self) -> None: ... -class StataReader(StataParser, abc.Iterator): +class StataReader(StataParser, Iterator[Any]): col_sizes: list[int] = ... path_or_buf: BytesIO = ... def __init__( 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] diff --git a/tests/series/test_series.py b/tests/series/test_series.py index cd406b31f..2dfadd624 100644 --- a/tests/series/test_series.py +++ b/tests/series/test_series.py @@ -163,6 +163,14 @@ def test_types_init() -> None: pd.Series, float, ) + check( + assert_type( + pd.Series([pd.Interval(pd.Timestamp(0), pd.Timestamp(1))]), + "pd.Series[pd.Interval[pd.Timestamp]]", + ), + pd.Series, + pd.Interval, + ) def test_types_any() -> None: @@ -3453,9 +3461,9 @@ def test_diff() -> None: # str -> TypeError: unsupported operand type(s) for -: 'str' and 'str' pd.Series(["a", "b"]).diff() # type: ignore[misc] # pyright: ignore[reportAttributeAccessIssue] - def _diff_invalid0() -> None: # pyright: ignore[reportUnusedFunction] - # interval -> TypeError: IntervalArray has no 'diff' method. Convert to a suitable dtype prior to calling 'diff'. - assert_type(pd.Series([pd.Interval(0, 2), pd.Interval(1, 4)]).diff(), Never) + def _diff_invalid0() -> None: # pyright: ignore[reportUnusedFunction] + # interval -> TypeError: IntervalArray has no 'diff' method. Convert to a suitable dtype prior to calling 'diff'. + assert_type(pd.Series([pd.Interval(0, 2), pd.Interval(1, 4)]).diff(), Never) def test_operator_constistency() -> None: