diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index eb63ee31..c199a371 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -464,6 +464,7 @@ T = TypeVar("T") P = ParamSpec("P") FuncType: TypeAlias = Callable[..., Any] F = TypeVar("F", bound=FuncType) +TypeT = TypeVar("TypeT", bound=type) HashableT = TypeVar("HashableT", bound=Hashable) HashableT1 = TypeVar("HashableT1", bound=Hashable) HashableT2 = TypeVar("HashableT2", bound=Hashable) diff --git a/pandas-stubs/core/accessor.pyi b/pandas-stubs/core/accessor.pyi index 62ff02e3..0b95bb1b 100644 --- a/pandas-stubs/core/accessor.pyi +++ b/pandas-stubs/core/accessor.pyi @@ -1,15 +1,9 @@ -from typing import Any +from typing import Callable -class PandasDelegate: ... - -def delegate_names( - delegate: Any, accessors: Any, typ: str, overwrite: bool = ... -) -> Any: ... +from pandas._typing import TypeT -class CachedAccessor: - def __init__(self, name: str, accessor: Any) -> None: ... - def __get__(self, obj: Any, cls: Any): ... +class PandasDelegate: ... -def register_dataframe_accessor(name: Any): ... -def register_series_accessor(name: Any): ... -def register_index_accessor(name: Any): ... +def register_dataframe_accessor(name: str) -> Callable[[TypeT], TypeT]: ... +def register_series_accessor(name: str) -> Callable[[TypeT], TypeT]: ... +def register_index_accessor(name: str) -> Callable[[TypeT], TypeT]: ... diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index 826ba3ad..aa69c5d8 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -13,6 +13,7 @@ import sys from typing import ( Any, ClassVar, + Generic, Literal, NoReturn, overload, @@ -138,7 +139,7 @@ from pandas.plotting import PlotAccessor _str = str _bool = bool -class _iLocIndexerFrame(_iLocIndexer): +class _iLocIndexerFrame(_iLocIndexer, Generic[_T]): @overload def __getitem__(self, idx: tuple[int, int]) -> Scalar: ... @overload @@ -156,7 +157,7 @@ class _iLocIndexerFrame(_iLocIndexer): | tuple[IndexType | MaskType, IndexType | MaskType] | tuple[slice] ), - ) -> DataFrame: ... + ) -> _T: ... def __setitem__( self, idx: ( @@ -170,9 +171,9 @@ class _iLocIndexerFrame(_iLocIndexer): value: Scalar | Series | DataFrame | np.ndarray | NAType | NaTType | None, ) -> None: ... -class _LocIndexerFrame(_LocIndexer): +class _LocIndexerFrame(_LocIndexer, Generic[_T]): @overload - def __getitem__(self, idx: Scalar) -> Series | DataFrame: ... + def __getitem__(self, idx: Scalar) -> Series | _T: ... @overload def __getitem__( self, @@ -191,7 +192,7 @@ class _LocIndexerFrame(_LocIndexer): MaskType | list[HashableT] | slice | Callable, ] ), - ) -> DataFrame: ... + ) -> _T: ... @overload def __getitem__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, @@ -223,7 +224,7 @@ class _LocIndexerFrame(_LocIndexer): ), ) -> Series: ... @overload - def __getitem__(self, idx: tuple[Scalar, slice]) -> Series | DataFrame: ... + def __getitem__(self, idx: tuple[Scalar, slice]) -> Series | _T: ... @overload def __setitem__( self, @@ -247,7 +248,7 @@ if sys.version_info >= (3, 12): @overload def __getitem__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, key: Iterable[Hashable] | slice - ) -> DataFrame: ... + ) -> Self: ... @overload def __getitem__(self, key: Hashable) -> Series: ... @@ -258,7 +259,7 @@ else: @overload def __getitem__( # pyright: ignore[reportOverlappingOverload] self, key: Iterable[Hashable] | slice - ) -> DataFrame: ... + ) -> Self: ... @overload def __getitem__(self, key: Hashable) -> Series: ... @@ -312,15 +313,15 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): ) -> Iterable[tuple[Any, ...]]: ... def __len__(self) -> int: ... @overload - def dot(self, other: DataFrame | ArrayLike) -> DataFrame: ... + def dot(self, other: DataFrame | ArrayLike) -> Self: ... @overload def dot(self, other: Series) -> Series: ... @overload - def __matmul__(self, other: DataFrame) -> DataFrame: ... + def __matmul__(self, other: DataFrame) -> Self: ... @overload def __matmul__(self, other: Series) -> Series: ... @overload - def __matmul__(self, other: np.ndarray) -> DataFrame: ... + def __matmul__(self, other: np.ndarray) -> Self: ... def __rmatmul__(self, other): ... @overload @classmethod @@ -330,7 +331,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): orient: Literal["index"], dtype: AstypeArg | None = ..., columns: Axes | None = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload @classmethod def from_dict( @@ -338,7 +339,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): data: dict[Any, Any], orient: Literal["columns", "tight"] = ..., dtype: AstypeArg | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def to_numpy( self, dtype: npt.DTypeLike | None = ..., @@ -426,7 +427,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): @classmethod def from_records( cls, data, index=..., exclude=..., columns=..., coerce_float=..., nrows=... - ) -> DataFrame: ... + ) -> Self: ... def to_records( self, index: _bool = ..., @@ -637,9 +638,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): show_counts: bool | None = ..., ) -> None: ... def memory_usage(self, index: _bool = ..., deep: _bool = ...) -> Series: ... - def transpose(self, *args, copy: _bool = ...) -> DataFrame: ... + def transpose(self, *args, copy: _bool = ...) -> Self: ... @property - def T(self) -> DataFrame: ... + def T(self) -> Self: ... def __getattr__(self, name: str) -> Series: ... def isetitem( self, loc: int | Sequence[int], value: Scalar | ArrayLike | list[Any] @@ -648,15 +649,13 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): @overload def query(self, expr: _str, *, inplace: Literal[True], **kwargs) -> None: ... @overload - def query( - self, expr: _str, *, inplace: Literal[False] = ..., **kwargs - ) -> DataFrame: ... + def query(self, expr: _str, *, inplace: Literal[False] = ..., **kwargs) -> Self: ... @overload def eval(self, expr: _str, *, inplace: Literal[True], **kwargs) -> None: ... @overload def eval( self, expr: _str, *, inplace: Literal[False] = ..., **kwargs - ) -> Scalar | np.ndarray | DataFrame | Series: ... + ) -> Scalar | np.ndarray | Self | Series: ... AstypeArgExt: TypeAlias = ( AstypeArg | Literal[ @@ -688,18 +687,18 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): self, include: AstypeArgExtList, exclude: AstypeArgExtList | None = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def select_dtypes( self, include: AstypeArgExtList | None, exclude: AstypeArgExtList, - ) -> DataFrame: ... + ) -> Self: ... @overload def select_dtypes( self, exclude: AstypeArgExtList, - ) -> DataFrame: ... + ) -> Self: ... def insert( self, loc: int, @@ -707,7 +706,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): value: Scalar | ListLikeU | None, allow_duplicates: _bool = ..., ) -> None: ... - def assign(self, **kwargs) -> DataFrame: ... + def assign(self, **kwargs) -> Self: ... def align( self, other: NDFrameT, @@ -720,7 +719,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): limit: int | None = ..., fill_axis: Axis = ..., broadcast_axis: Axis | None = ..., - ) -> tuple[DataFrame, NDFrameT]: ... + ) -> tuple[Self, NDFrameT]: ... def reindex( self, labels: Axes | None = ..., @@ -733,7 +732,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): fill_value: Scalar | None = ..., limit: int | None = ..., tolerance: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def rename( self, @@ -759,7 +758,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): inplace: Literal[False] = ..., level: Level | None = ..., errors: IgnoreRaise = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def rename( self, @@ -772,7 +771,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): inplace: bool = ..., level: Level | None = ..., errors: IgnoreRaise = ..., - ) -> DataFrame | None: ... + ) -> Self | None: ... @overload def fillna( self, @@ -792,7 +791,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): limit: int = ..., downcast: dict | None = ..., inplace: Literal[False] = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def fillna( self, @@ -802,7 +801,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): inplace: _bool | None = ..., limit: int = ..., downcast: dict | None = ..., - ) -> DataFrame | None: ... + ) -> Self | None: ... @overload def replace( self, @@ -824,7 +823,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): limit: int | None = ..., regex=..., method: ReplaceMethod = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def replace( self, @@ -835,14 +834,14 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): limit: int | None = ..., regex=..., method: ReplaceMethod = ..., - ) -> DataFrame | None: ... + ) -> Self | None: ... def shift( self, periods: int = ..., freq=..., axis: Axis = ..., fill_value: Hashable | None = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def set_index( self, @@ -866,7 +865,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): append: _bool = ..., verify_integrity: _bool = ..., inplace: Literal[False] = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def reset_index( self, @@ -890,7 +889,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): inplace: Literal[False] = ..., allow_duplicates: _bool = ..., names: Hashable | list[HashableT] = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def reset_index( self, @@ -902,11 +901,11 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): col_fill: Hashable = ..., allow_duplicates: _bool = ..., names: Hashable | list[HashableT] = ..., - ) -> DataFrame | None: ... - def isna(self) -> DataFrame: ... - def isnull(self) -> DataFrame: ... - def notna(self) -> DataFrame: ... - def notnull(self) -> DataFrame: ... + ) -> Self | None: ... + def isna(self) -> Self: ... + def isnull(self) -> Self: ... + def notna(self) -> Self: ... + def notnull(self) -> Self: ... @overload def dropna( self, @@ -928,7 +927,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): subset: ListLikeU | Scalar | None = ..., inplace: Literal[False] = ..., ignore_index: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def dropna( self, @@ -939,7 +938,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): subset: ListLikeU | Scalar | None = ..., inplace: _bool | None = ..., ignore_index: _bool = ..., - ) -> DataFrame | None: ... + ) -> Self | None: ... @overload def drop_duplicates( self, @@ -957,7 +956,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): keep: NaPosition | _bool = ..., inplace: Literal[False] = ..., ignore_index: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def drop_duplicates( self, @@ -966,7 +965,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): keep: NaPosition | _bool = ..., inplace: _bool = ..., ignore_index: _bool = ..., - ) -> DataFrame | None: ... + ) -> Self | None: ... def duplicated( self, subset: Hashable | Iterable[Hashable] | None = ..., @@ -997,7 +996,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): ignore_index: _bool = ..., inplace: Literal[False] = ..., key: Callable | None = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def sort_values( self, @@ -1010,7 +1009,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): na_position: NaPosition = ..., ignore_index: _bool = ..., key: Callable | None = ..., - ) -> DataFrame | None: ... + ) -> Self | None: ... @overload def sort_index( self, @@ -1038,7 +1037,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): ignore_index: _bool = ..., inplace: Literal[False] = ..., key: Callable | None = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def sort_index( self, @@ -1052,7 +1051,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): sort_remaining: _bool = ..., ignore_index: _bool = ..., key: Callable | None = ..., - ) -> DataFrame | None: ... + ) -> Self | None: ... @overload def value_counts( self, @@ -1076,17 +1075,15 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): n: int, columns: _str | list[_str], keep: NaPosition | Literal["all"] = ..., - ) -> DataFrame: ... + ) -> Self: ... def nsmallest( self, n: int, columns: _str | list[_str], keep: NaPosition | Literal["all"] = ..., - ) -> DataFrame: ... - def swaplevel( - self, i: Level = ..., j: Level = ..., axis: Axis = ... - ) -> DataFrame: ... - def reorder_levels(self, order: list, axis: Axis = ...) -> DataFrame: ... + ) -> Self: ... + def swaplevel(self, i: Level = ..., j: Level = ..., axis: Axis = ...) -> Self: ... + def reorder_levels(self, order: list, axis: Axis = ...) -> Self: ... def compare( self, other: DataFrame, @@ -1094,15 +1091,15 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): keep_shape: bool = ..., keep_equal: bool = ..., result_names: Suffixes = ..., - ) -> DataFrame: ... + ) -> Self: ... def combine( self, other: DataFrame, func: Callable, fill_value=..., overwrite: _bool = ..., - ) -> DataFrame: ... - def combine_first(self, other: DataFrame) -> DataFrame: ... + ) -> Self: ... + def combine_first(self, other: DataFrame) -> Self: ... def update( self, other: DataFrame | Series, @@ -1309,7 +1306,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): index: IndexLabel = ..., columns: IndexLabel = ..., values: IndexLabel = ..., - ) -> DataFrame: ... + ) -> Self: ... def pivot_table( self, values: _str | None | Sequence[_str] = ..., @@ -1322,23 +1319,23 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): margins_name: _str = ..., observed: _bool = ..., sort: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def stack( self, level: Level | list[Level] = ..., dropna: _bool = ..., sort: _bool = ... - ) -> DataFrame | Series[Any]: ... + ) -> Self | Series[Any]: ... @overload def stack( self, level: Level | list[Level] = ..., future_stack: _bool = ... - ) -> DataFrame | Series[Any]: ... + ) -> Self | Series[Any]: ... def explode( self, column: Sequence[Hashable], ignore_index: _bool = ... - ) -> DataFrame: ... + ) -> Self: ... def unstack( self, level: Level = ..., fill_value: int | _str | dict | None = ..., - ) -> DataFrame | Series: ... + ) -> Self | Series: ... def melt( self, id_vars: tuple | Sequence | np.ndarray | None = ..., @@ -1347,8 +1344,8 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): value_name: Scalar = ..., col_level: int | _str | None = ..., ignore_index: _bool = ..., - ) -> DataFrame: ... - def diff(self, periods: int = ..., axis: Axis = ...) -> DataFrame: ... + ) -> Self: ... + def diff(self, periods: int = ..., axis: Axis = ...) -> Self: ... @overload def agg( # pyright: ignore[reportOverlappingOverload] self, func: AggFuncTypeBase | AggFuncTypeDictSeries, axis: Axis = ..., **kwargs @@ -1359,7 +1356,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): func: list[AggFuncTypeBase] | AggFuncTypeDictFrame = ..., axis: Axis = ..., **kwargs, - ) -> DataFrame: ... + ) -> Self: ... @overload def aggregate( # pyright: ignore[reportOverlappingOverload] self, func: AggFuncTypeBase | AggFuncTypeDictSeries, axis: Axis = ..., **kwargs @@ -1370,14 +1367,14 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): func: list[AggFuncTypeBase] | AggFuncTypeDictFrame, axis: Axis = ..., **kwargs, - ) -> DataFrame: ... + ) -> Self: ... def transform( self, func: AggFuncTypeFrame, axis: Axis = ..., *args, **kwargs, - ) -> DataFrame: ... + ) -> Self: ... # apply() overloads with default result_type of None, and is indifferent to axis @overload @@ -1389,7 +1386,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): result_type: None = ..., args: Any = ..., **kwargs: Any, - ) -> DataFrame: ... + ) -> Self: ... @overload def apply( self, @@ -1435,7 +1432,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): *, result_type: Literal["expand"], **kwargs: Any, - ) -> DataFrame: ... + ) -> Self: ... @overload def apply( self, @@ -1459,7 +1456,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): *, result_type: Literal["broadcast"], **kwargs: Any, - ) -> DataFrame: ... + ) -> Self: ... # apply() overloads with keyword result_type, and axis does matter @overload @@ -1507,7 +1504,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): *, axis: AxisColumn, **kwargs: Any, - ) -> DataFrame: ... + ) -> Self: ... # apply() overloads with keyword axis=1 and keyword result_type @overload @@ -1520,12 +1517,12 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: AxisColumn, result_type: Literal["reduce"], **kwargs: Any, - ) -> DataFrame: ... + ) -> Self: ... # Add spacing between apply() overloads and remaining annotations def map( self, func: Callable, na_action: Literal["ignore"] | None = ..., **kwargs - ) -> DataFrame: ... + ) -> Self: ... def join( self, other: DataFrame | Series | list[DataFrame | Series], @@ -1535,7 +1532,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): rsuffix: _str = ..., sort: _bool = ..., validate: ValidationOptions | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def merge( self, right: DataFrame | Series[Any], @@ -1550,19 +1547,17 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): copy: _bool = ..., indicator: _bool | _str = ..., validate: _str | None = ..., - ) -> DataFrame: ... - def round( - self, decimals: int | dict | Series = ..., *args, **kwargs - ) -> DataFrame: ... + ) -> Self: ... + def round(self, decimals: int | dict | Series = ..., *args, **kwargs) -> Self: ... def corr( self, method: Literal["pearson", "kendall", "spearman"] = ..., min_periods: int = ..., numeric_only: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... def cov( self, min_periods: int | None = ..., ddof: int = ..., numeric_only: _bool = ... - ) -> DataFrame: ... + ) -> Self: ... def corrwith( self, other: DataFrame | Series, @@ -1574,7 +1569,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): @overload def count( self, axis: Axis = ..., numeric_only: _bool = ..., *, level: Level - ) -> DataFrame: ... + ) -> Self: ... @overload def count( self, axis: Axis = ..., level: None = ..., numeric_only: _bool = ... @@ -1595,7 +1590,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): *, level: Level, **kwargs, - ) -> DataFrame: ... + ) -> Self: ... @overload def mode( self, @@ -1622,18 +1617,18 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): numeric_only: _bool = ..., interpolation: QuantileInterpolation = ..., method: CalculationMethod = ..., - ) -> DataFrame: ... + ) -> Self: ... def to_timestamp( self, freq=..., how: TimestampConvention = ..., axis: Axis = ..., copy: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... def to_period( self, freq: _str | None = ..., axis: Axis = ..., copy: _bool = ... - ) -> DataFrame: ... - def isin(self, values: Iterable | Series | DataFrame | dict) -> DataFrame: ... + ) -> Self: ... + def isin(self, values: Iterable | Series | DataFrame | dict) -> Self: ... @property def plot(self) -> PlotAccessor: ... def hist( @@ -1695,13 +1690,13 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): @property def iat(self): ... # Not sure what to do with this yet; look at source @property - def iloc(self) -> _iLocIndexerFrame: ... + def iloc(self) -> _iLocIndexerFrame[Self]: ... @property def index(self) -> Index: ... @index.setter def index(self, idx: Index) -> None: ... @property - def loc(self) -> _LocIndexerFrame: ... + def loc(self) -> _LocIndexerFrame[Self]: ... @property def ndim(self) -> int: ... @property @@ -1709,16 +1704,16 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): @property def values(self) -> np.ndarray: ... # methods - def abs(self) -> DataFrame: ... + def abs(self) -> Self: ... def add( self, other: num | ListLike | DataFrame, axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... - def add_prefix(self, prefix: _str, axis: Axis | None = None) -> DataFrame: ... - def add_suffix(self, suffix: _str, axis: Axis | None = None) -> DataFrame: ... + ) -> Self: ... + def add_prefix(self, prefix: _str, axis: Axis | None = None) -> Self: ... + def add_suffix(self, suffix: _str, axis: Axis | None = None) -> Self: ... @overload def all( self, @@ -1753,7 +1748,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): skipna: _bool = ..., **kwargs, ) -> Series[_bool]: ... - def asof(self, where, subset: _str | list[_str] | None = ...) -> DataFrame: ... + def asof(self, where, subset: _str | list[_str] | None = ...) -> Self: ... def asfreq( self, freq, @@ -1761,25 +1756,25 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): how: Literal["start", "end"] | None = ..., normalize: _bool = ..., fill_value: Scalar | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def astype( self, dtype: AstypeArg | Mapping[Any, Dtype] | Series, copy: _bool = ..., errors: IgnoreRaise = ..., - ) -> DataFrame: ... + ) -> Self: ... def at_time( self, time: _str | dt.time, asof: _bool = ..., axis: Axis | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def between_time( self, start_time: _str | dt.time, end_time: _str | dt.time, axis: Axis | None = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def bfill( self, @@ -1799,7 +1794,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): limit: int | None = ..., limit_area: Literal["inside", "outside"] | None = ..., downcast: dict | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def clip( self, lower: float | AnyArrayLike | None = ..., @@ -1808,42 +1803,42 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: Axis | None = ..., inplace: _bool = ..., **kwargs, - ) -> DataFrame: ... - def copy(self, deep: _bool = ...) -> DataFrame: ... + ) -> Self: ... + def copy(self, deep: _bool = ...) -> Self: ... def cummax( self, axis: Axis | None = ..., skipna: _bool = ..., *args, **kwargs - ) -> DataFrame: ... + ) -> Self: ... def cummin( self, axis: Axis | None = ..., skipna: _bool = ..., *args, **kwargs - ) -> DataFrame: ... + ) -> Self: ... def cumprod( self, axis: Axis | None = ..., skipna: _bool = ..., *args, **kwargs - ) -> DataFrame: ... + ) -> Self: ... def cumsum( self, axis: Axis | None = ..., skipna: _bool = ..., *args, **kwargs - ) -> DataFrame: ... + ) -> Self: ... def describe( self, percentiles: list[float] | None = ..., include: Literal["all"] | list[Dtype] | None = ..., exclude: list[Dtype] | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def div( self, other: num | ListLike | DataFrame, axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def divide( self, other: num | ListLike | DataFrame, axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... - def droplevel(self, level: Level | list[Level], axis: Axis = ...) -> DataFrame: ... - def eq(self, other, axis: Axis = ..., level: Level | None = ...) -> DataFrame: ... + ) -> Self: ... + def droplevel(self, level: Level | list[Level], axis: Axis = ...) -> Self: ... + def eq(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ... def equals(self, other: Series | DataFrame) -> _bool: ... def ewm( self, @@ -1855,13 +1850,13 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): adjust: _bool = ..., ignore_na: _bool = ..., axis: Axis = ..., - ) -> ExponentialMovingWindow[DataFrame]: ... + ) -> ExponentialMovingWindow[Self]: ... def expanding( self, min_periods: int = ..., axis: AxisIndex = ..., method: CalculationMethod = ..., - ) -> Expanding[DataFrame]: ... + ) -> Expanding[Self]: ... @overload def ffill( self, @@ -1881,15 +1876,15 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): limit: int | None = ..., limit_area: Literal["inside", "outside"] | None = ..., downcast: dict | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def filter( self, items: ListLike | None = ..., like: _str | None = ..., regex: _str | None = ..., axis: Axis | None = ..., - ) -> DataFrame: ... - def first(self, offset) -> DataFrame: ... + ) -> Self: ... + def first(self, offset) -> Self: ... def first_valid_index(self) -> Scalar: ... def floordiv( self, @@ -1897,21 +1892,21 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... # def from_dict # def from_records - def ge(self, other, axis: Axis = ..., level: Level | None = ...) -> DataFrame: ... + def ge(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ... @overload def get(self, key: Hashable, default: None = ...) -> Series | None: ... @overload def get(self, key: Hashable, default: _T) -> Series | _T: ... @overload - def get(self, key: list[Hashable], default: None = ...) -> DataFrame | None: ... + def get(self, key: list[Hashable], default: None = ...) -> Self | None: ... @overload - def get(self, key: list[Hashable], default: _T) -> DataFrame | _T: ... - def gt(self, other, axis: Axis = ..., level: Level | None = ...) -> DataFrame: ... - def head(self, n: int = ...) -> DataFrame: ... - def infer_objects(self) -> DataFrame: ... + def get(self, key: list[Hashable], default: _T) -> Self | _T: ... + def gt(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ... + def head(self, n: int = ...) -> Self: ... + def infer_objects(self) -> Self: ... # def info @overload def interpolate( @@ -1938,7 +1933,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): downcast: Literal["infer"] | None = ..., inplace: Literal[False] = ..., **kwargs, - ) -> DataFrame: ... + ) -> Self: ... @overload def interpolate( self, @@ -1951,7 +1946,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): limit_area: Literal["inside", "outside"] | None = ..., downcast: Literal["infer"] | None = ..., **kwargs, - ) -> DataFrame | None: ... + ) -> Self | None: ... def keys(self) -> Index: ... def kurt( self, @@ -1969,10 +1964,10 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): numeric_only: _bool = ..., **kwargs, ) -> Series: ... - def last(self, offset) -> DataFrame: ... + def last(self, offset) -> Self: ... def last_valid_index(self) -> Scalar: ... - def le(self, other, axis: Axis = ..., level: Level | None = ...) -> DataFrame: ... - def lt(self, other, axis: Axis = ..., level: Level | None = ...) -> DataFrame: ... + def le(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ... + def lt(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ... def mask( self, cond: ( @@ -1987,7 +1982,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): inplace: _bool = ..., axis: Axis | None = ..., level: Level | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def max( self, axis: Axis | None = ..., @@ -2026,22 +2021,22 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def mul( self, other: num | ListLike | DataFrame, axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def multiply( self, other: num | ListLike | DataFrame, axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... - def ne(self, other, axis: Axis = ..., level: Level | None = ...) -> DataFrame: ... + ) -> Self: ... + def ne(self, other, axis: Axis = ..., level: Level | None = ...) -> Self: ... def pct_change( self, periods: int = ..., @@ -2049,7 +2044,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): limit: int | None = ..., freq=..., **kwargs, - ) -> DataFrame: ... + ) -> Self: ... def pop(self, item: _str) -> Series: ... def pow( self, @@ -2057,7 +2052,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def prod( self, axis: Axis | None = ..., @@ -2082,7 +2077,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: Axis = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def rank( self, axis: Axis = ..., @@ -2091,14 +2086,14 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): na_option: Literal["keep", "top", "bottom"] = ..., ascending: _bool = ..., pct: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... def rdiv( self, other, axis: Axis = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def reindex_like( self, other: DataFrame, @@ -2106,7 +2101,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): copy: _bool = ..., limit: int | None = ..., tolerance=..., - ) -> DataFrame: ... + ) -> Self: ... # Rename axis with `mapper`, `axis`, and `inplace=True` @overload def rename_axis( @@ -2126,7 +2121,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: Axis | None = ..., copy: _bool = ..., inplace: Literal[False] = ..., - ) -> DataFrame: ... + ) -> Self: ... # Rename axis with `index` and/or `columns` and `inplace=True` @overload def rename_axis( @@ -2146,28 +2141,28 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): columns: _str | Sequence[_str] | dict[_str | int, _str] | Callable | None = ..., copy: _bool = ..., inplace: Literal[False] = ..., - ) -> DataFrame: ... + ) -> Self: ... def rfloordiv( self, other, axis: Axis = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def rmod( self, other, axis: Axis = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def rmul( self, other, axis: Axis = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... @overload def rolling( self, @@ -2181,7 +2176,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): method: CalculationMethod = ..., *, win_type: _str, - ) -> Window[DataFrame]: ... + ) -> Window[Self]: ... @overload def rolling( self, @@ -2195,28 +2190,28 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): method: CalculationMethod = ..., *, win_type: None = ..., - ) -> Rolling[DataFrame]: ... + ) -> Rolling[Self]: ... def rpow( self, other, axis: Axis = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def rsub( self, other, axis: Axis = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def rtruediv( self, other, axis: Axis = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... # sample is missing a weights arg def sample( self, @@ -2227,7 +2222,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): random_state: RandomState | None = ..., axis: AxisIndex | None = ..., ignore_index: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... def sem( self, axis: Axis | None = ..., @@ -2238,7 +2233,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): **kwargs, ) -> Series: ... # Not actually positional, but used to handle removal of deprecated - def set_axis(self, labels, *, axis: Axis, copy: _bool = ...) -> DataFrame: ... + def set_axis(self, labels, *, axis: Axis, copy: _bool = ...) -> Self: ... def skew( self, axis: Axis | None = ..., @@ -2263,14 +2258,14 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def subtract( self, other: num | ListLike | DataFrame, axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def sum( self, axis: Axis | None = ..., @@ -2280,9 +2275,9 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): min_count: int = ..., **kwargs, ) -> Series: ... - def swapaxes(self, axis1: Axis, axis2: Axis, copy: _bool = ...) -> DataFrame: ... - def tail(self, n: int = ...) -> DataFrame: ... - def take(self, indices: list, axis: Axis = ..., **kwargs) -> DataFrame: ... + def swapaxes(self, axis1: Axis, axis2: Axis, copy: _bool = ...) -> Self: ... + def tail(self, n: int = ...) -> Self: ... + def take(self, indices: list, axis: Axis = ..., **kwargs) -> Self: ... def to_clipboard( self, excel: _bool = ..., sep: _str | None = ..., **kwargs ) -> None: ... @@ -2413,21 +2408,21 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): axis: Axis | None = ..., level: Level | None = ..., fill_value: float | None = ..., - ) -> DataFrame: ... + ) -> Self: ... def truncate( self, before: dt.date | _str | int | None = ..., after: dt.date | _str | int | None = ..., axis: Axis | None = ..., copy: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... def tz_convert( self, tz, axis: Axis = ..., level: Level | None = ..., copy: _bool = ..., - ) -> DataFrame: ... + ) -> Self: ... def tz_localize( self, tz, @@ -2436,7 +2431,7 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): copy: _bool = ..., ambiguous=..., nonexistent: _str = ..., - ) -> DataFrame: ... + ) -> Self: ... def var( self, axis: Axis | None = ..., @@ -2460,16 +2455,16 @@ class DataFrame(NDFrame, OpsMixin, _GetItemHack): inplace: _bool = ..., axis: Axis | None = ..., level: Level | None = ..., - ) -> DataFrame: ... + ) -> Self: ... # Move from generic because Series is Generic and it returns Series[bool] there - def __invert__(self) -> DataFrame: ... + def __invert__(self) -> Self: ... def xs( self, key: Hashable, axis: Axis = ..., level: Level | None = ..., drop_level: _bool = ..., - ) -> DataFrame | Series: ... + ) -> Self | Series: ... # floordiv overload def __floordiv__( self, other: float | DataFrame | Series[int] | Series[float] | Sequence[float] diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index 763aae02..1bfe42f8 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -229,7 +229,7 @@ class Index(IndexOpsMixin[S1]): @overload def __new__( cls, - data: Iterable[S1] | IndexOpsMixin[S1] = ..., + data: Iterable[S1] | IndexOpsMixin[S1], *, dtype: type[S1] = ..., copy: bool = ..., @@ -252,7 +252,7 @@ class Index(IndexOpsMixin[S1]): @overload def __new__( cls, - data: Iterable = ..., + data: Iterable, *, dtype=..., copy: bool = ..., diff --git a/tests/test_frame.py b/tests/test_frame.py index bd90d0ce..ad7bb645 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -3801,3 +3801,20 @@ def test_frame_bool_fails() -> None: s = df["a"] except ValueError: pass + + +def test_frame_subclass() -> None: + class MyClass(pd.DataFrame): + @property + def _constructor(self) -> type[MyClass]: + return MyClass + + df = MyClass({"a": [1, 2, 3], "b": [4, 5, 6]}) + check(assert_type(df.iloc[1:2], MyClass), MyClass) + check(assert_type(df.loc[:, ["a", "b"]], MyClass), MyClass) + check(assert_type(df[["a", "b"]], MyClass), MyClass) + + +# GH 906 +@pd.api.extensions.register_dataframe_accessor("geo") +class GeoAccessor: ... diff --git a/tests/test_indexes.py b/tests/test_indexes.py index 5f4f96f9..e77371cf 100644 --- a/tests/test_indexes.py +++ b/tests/test_indexes.py @@ -1195,3 +1195,9 @@ def test_index_factorize() -> None: ) check(assert_type(codes, np.ndarray), np.ndarray) check(assert_type(idx_uniques, np.ndarray | Index | Categorical), pd.Index) + + +def test_disallow_empty_index() -> None: + # From GH 826 + if TYPE_CHECKING_INVALID_USAGE: + i0 = pd.Index() # type: ignore[call-overload] # pyright: ignore[reportCallIssue]