From c5a98cf44658561c16256b0a652897a321a1d572 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 6 Jan 2024 20:59:45 +0100 Subject: [PATCH 01/23] Rework groupby and resample core modules --- .pre-commit-config.yaml | 2 +- pandas-stubs/_libs/properties.pyi | 5 +- pandas-stubs/_typing.pyi | 17 + pandas-stubs/core/apply.pyi | 242 ++++++ pandas-stubs/core/base.pyi | 17 +- pandas-stubs/core/frame.pyi | 57 +- pandas-stubs/core/generic.pyi | 22 + pandas-stubs/core/groupby/__init__.pyi | 15 +- pandas-stubs/core/groupby/base.pyi | 8 +- pandas-stubs/core/groupby/categorical.pyi | 9 +- pandas-stubs/core/groupby/generic.pyi | 484 +++++------ pandas-stubs/core/groupby/groupby.pyi | 483 +++++++++-- pandas-stubs/core/groupby/grouper.pyi | 139 +++- pandas-stubs/core/groupby/indexing.pyi | 34 + pandas-stubs/core/groupby/ops.pyi | 179 ++-- pandas-stubs/core/indexes/base.pyi | 2 + pandas-stubs/core/resample.pyi | 311 ++++--- pandas-stubs/core/series.pyi | 73 +- pandas-stubs/core/window/__init__.pyi | 15 +- pandas-stubs/core/window/ewm.pyi | 113 ++- pandas-stubs/core/window/expanding.pyi | 119 +-- pandas-stubs/core/window/rolling.pyi | 198 +++-- pandas-stubs/plotting/__init__.pyi | 1 + pandas-stubs/plotting/_core.pyi | 49 ++ pandas-stubs/util/_decorators.pyi | 59 +- tests/__init__.py | 3 + tests/test_frame.py | 20 +- tests/test_groupby.py | 947 ++++++++++++++++++++++ tests/test_plotting.py | 82 +- tests/test_resampler.py | 162 +++- tests/test_series.py | 54 +- 31 files changed, 3029 insertions(+), 892 deletions(-) create mode 100644 pandas-stubs/core/apply.pyi create mode 100644 pandas-stubs/core/groupby/indexing.pyi create mode 100644 tests/test_groupby.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 35165128e..054d20aca 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: --exit-non-zero-on-fix, --target-version, py39, --extend-select, "PYI,UP,RUF100", - --ignore, "E501,E731,F841,PYI042", + --ignore, "E501,E731,F841,PYI042,PYI053", --per-file-ignores, "_*.pyi:PYI001", --fix ] diff --git a/pandas-stubs/_libs/properties.pyi b/pandas-stubs/_libs/properties.pyi index 761a00cea..f3351308b 100644 --- a/pandas-stubs/_libs/properties.pyi +++ b/pandas-stubs/_libs/properties.pyi @@ -5,7 +5,10 @@ class CachedProperty: def __get__(self, obj, typ): ... def __set__(self, obj, value) -> None: ... -cache_readonly: CachedProperty = ... +# note: this is a lie to make type checkers happy (they special +# case property). cache_readonly uses attribute names similar to +# property (fget) but it does not provide fset and fdel. +cache_readonly = property class AxisProperty: def __init__(self, axis: int = ..., doc: str = ...) -> None: ... diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index d8f655b50..26781e941 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -48,6 +48,8 @@ from pandas.core.dtypes.dtypes import ( from pandas.io.formats.format import EngFormatter +Incomplete: TypeAlias = Any + ArrayLike: TypeAlias = ExtensionArray | np.ndarray AnyArrayLike: TypeAlias = Index | Series | np.ndarray PythonScalar: TypeAlias = str | bool | complex @@ -80,6 +82,10 @@ class FulldatetimeDict(YearMonthDayDict, total=False): us: DatetimeDictArg ns: DatetimeDictArg +CorrelationMethod: TypeAlias = ( + Literal["pearson", "kendall", "spearman"] + | Callable[[np.ndarray, np.ndarray], float] +) # dtypes NpDtype: TypeAlias = str | np.dtype[np.generic] | type[str | complex | bool | object] Dtype: TypeAlias = ExtensionDtype | NpDtype @@ -444,6 +450,7 @@ class SequenceNotStr(Protocol[_T_co]): IndexLabel: TypeAlias = Hashable | Sequence[Hashable] Label: TypeAlias = Hashable | None Level: TypeAlias = Hashable | int +Shape: TypeAlias = tuple[int, ...] Suffixes: TypeAlias = tuple[str | None, str | None] Ordered: TypeAlias = bool | None JSONSerializable: TypeAlias = PythonScalar | list | dict @@ -469,8 +476,11 @@ AggFuncTypeSeriesToFrame: TypeAlias = list[AggFuncTypeBase] | AggFuncTypeDictSer AggFuncTypeFrame: TypeAlias = ( AggFuncTypeBase | list[AggFuncTypeBase] | AggFuncTypeDictFrame ) +AggFuncTypeDict: TypeAlias = AggFuncTypeDictSeries | AggFuncTypeDictFrame +AggFuncType: TypeAlias = AggFuncTypeBase | list[AggFuncTypeBase] | AggFuncTypeDict num: TypeAlias = complex +AxisInt: TypeAlias = int AxisIndex: TypeAlias = Literal["index", 0] AxisColumn: TypeAlias = Literal["columns", 1] Axis: TypeAlias = AxisIndex | AxisColumn @@ -563,6 +573,9 @@ IndexT = TypeVar("IndexT", bound=Index) IntervalT = TypeVar("IntervalT", bound=Interval) IntervalClosedType: TypeAlias = Literal["left", "right", "both", "neither"] +ScalarIndexer: TypeAlias = int | np.integer +SequenceIndexer: TypeAlias = slice | list[int] | np.ndarray +PositionalIndexer: TypeAlias = ScalarIndexer | SequenceIndexer TakeIndexer: TypeAlias = Sequence[int] | Sequence[np.integer] | npt.NDArray[np.integer] IgnoreRaiseCoerce: TypeAlias = Literal["ignore", "raise", "coerce"] @@ -758,5 +771,9 @@ RandomState: TypeAlias = ( | np.random.BitGenerator | np.random.RandomState ) +Frequency: TypeAlias = str | BaseOffset +TimeGrouperOrigin: TypeAlias = ( + Timestamp | Literal["epoch", "start", "start_day", "end", "end_day"] +) __all__ = ["npt", "type_t"] diff --git a/pandas-stubs/core/apply.pyi b/pandas-stubs/core/apply.pyi new file mode 100644 index 000000000..12f2c176c --- /dev/null +++ b/pandas-stubs/core/apply.pyi @@ -0,0 +1,242 @@ +import abc +from abc import abstractmethod +from collections.abc import ( + Callable, + Hashable, + Iterable, + Iterator, + Sequence, +) +from typing import ( + Any, + Generic, + Literal, + TypeVar, +) + +import numpy as np +from pandas import ( + DataFrame, + Index, + Series, +) +from pandas.core.generic import NDFrame +from pandas.core.groupby import GroupBy +from pandas.core.resample import Resampler +from pandas.core.window.rolling import BaseWindow + +from pandas._libs.lib import NoDefault +from pandas._typing import ( + AggFuncType, + AggFuncTypeDict, + Axis, + AxisInt, + Incomplete, + NDFrameT, + npt, +) +from pandas.util._decorators import cache_readonly + +_AggObjT = TypeVar("_AggObjT", bound=NDFrame | GroupBy | BaseWindow | Resampler) +_AggGroupByObjT = TypeVar("_AggGroupByObjT", bound=GroupBy | BaseWindow | Resampler) +_AggResamplerWindowObjT = TypeVar( + "_AggResamplerWindowObjT", bound=BaseWindow | Resampler +) + +ResType = dict[int, Any] # noqa: PYI026 + +def frame_apply( + obj: DataFrame, + func: AggFuncType, + axis: Axis = 0, + raw: bool = False, + result_type: str | None = None, + by_row: Literal[False, "compat"] = "compat", + args=None, + kwargs=None, +) -> FrameApply: ... + +class Apply(Generic[_AggObjT], metaclass=abc.ABCMeta): + axis: AxisInt + obj: _AggObjT + raw: bool + by_row: Literal[False, "compat", "_compat"] + args: Incomplete + kwargs: Incomplete + result_type: Literal["reduce", "broadcast", "expand"] | None + func: AggFuncType + def __init__( + self, + obj: _AggObjT, + func: AggFuncType, + raw: bool, + result_type: Literal["reduce", "broadcast", "expand"] | None, + *, + by_row: Literal[False, "compat", "_compat"] = "compat", + args, + kwargs, + ) -> None: ... + @abstractmethod + def apply(self): ... + @abstractmethod + def agg_or_apply_list_like(self, op_name: Literal["agg", "apply"]): ... + @abstractmethod + def agg_or_apply_dict_like(self, op_name: Literal["agg", "apply"]): ... + def agg(self): ... + def transform(self): ... + def transform_dict_like(self, func: AggFuncTypeDict) -> DataFrame: ... + def transform_str_or_callable(self, func: str | Callable[..., Incomplete]): ... + def agg_list_like(self): ... + def compute_list_like( + self, + op_name: Literal["agg", "apply"], + selected_obj: Series | DataFrame, + kwargs: dict[str, Any], + ) -> tuple[list[Hashable], list[Any]]: ... + def wrap_results_list_like( + self, keys: list[Hashable], results: list[Series | DataFrame] + ): ... + def agg_dict_like(self): ... + def compute_dict_like( + self, + op_name: Literal["agg", "apply"], + selected_obj: Series | DataFrame, + selection: Hashable | Sequence[Hashable], + kwargs: dict[str, Any], + ) -> tuple[list[Hashable], list[Any]]: ... + def wrap_results_dict_like( + self, + selected_obj: Series | DataFrame, + result_index: list[Hashable], + result_data: list, + ) -> Series | DataFrame: ... + def apply_str(self): ... + def apply_list_or_dict_like(self): ... + def normalize_dictlike_arg( + self, how: str, obj: DataFrame | Series, func: AggFuncTypeDict + ) -> AggFuncTypeDict: ... + +class NDFrameApply(Apply[NDFrameT], metaclass=abc.ABCMeta): + @property + def index(self) -> Index: ... + @property + def agg_axis(self) -> Index: ... + def agg_or_apply_list_like(self, op_name: Literal["agg", "apply"]): ... + def agg_or_apply_dict_like(self, op_name: Literal["agg", "apply"]): ... + +class FrameApply(NDFrameApply[DataFrame]): + def __init__( + self, + obj: DataFrame, + func: AggFuncType, + raw: bool, + result_type: Literal["reduce", "broadcast", "expand"] | None, + *, + by_row: Literal[False, "compat"] = False, + args, + kwargs, + ) -> None: ... + @property + @abstractmethod + def result_index(self) -> Index: ... + @property + @abstractmethod + def result_columns(self) -> Index: ... + @property + @abstractmethod + def series_generator(self) -> Iterator[Series]: ... + @abstractmethod + def wrap_results_for_axis(self, results: ResType, res_index: Index): ... + @property + def res_columns(self) -> Index: ... + @property + def columns(self) -> Index: ... + @cache_readonly + def values(self): ... + def apply(self): ... + def agg(self): ... + def apply_empty_result(self): ... + def apply_raw(self): ... + def apply_broadcast(self, target: DataFrame) -> DataFrame: ... + def apply_standard(self): ... + def apply_series_generator(self) -> tuple[ResType, Index]: ... + def wrap_results(self, results: ResType, res_index: Index): ... + def apply_str(self): ... + +class FrameRowApply(FrameApply): + @property + def series_generator(self) -> Iterator[Series]: ... + @property + def result_index(self) -> Index: ... + @property + def result_columns(self) -> Index: ... + def wrap_results_for_axis(self, results: ResType, res_index: Index): ... + +class FrameColumnApply(FrameApply): + def apply_broadcast(self, target: DataFrame) -> DataFrame: ... + @property + def series_generator(self) -> Iterator[Series]: ... + @property + def result_index(self) -> Index: ... + @property + def result_columns(self) -> Index: ... + def wrap_results_for_axis(self, results: ResType, res_index: Index): ... + def infer_to_same_shape(self, results: ResType, res_index: Index) -> DataFrame: ... + +class SeriesApply(NDFrameApply[Series]): + by_row: Literal[False, "compat", "_compat"] + convert_dtype: bool + def __init__( + self, + obj: Series, + func: AggFuncType, + *, + convert_dtype: bool | NoDefault = ..., + by_row: Literal[False, "compat", "_compat"] = "compat", + args, + kwargs, + ) -> None: ... + def apply(self): ... + def agg(self): ... + def apply_empty_result(self) -> Series: ... + def apply_compat(self): ... + def apply_standard(self): ... + +class GroupByApply(Apply[_AggGroupByObjT]): + def __init__( + self, obj: _AggGroupByObjT, func: AggFuncType, *, args, kwargs + ) -> None: ... + def apply(self): ... + def transform(self): ... + def agg_or_apply_list_like(self, op_name: Literal["agg", "apply"]): ... + def agg_or_apply_dict_like(self, op_name: Literal["agg", "apply"]): ... + +class ResamplerWindowApply(GroupByApply[_AggResamplerWindowObjT]): + def __init__( + self, obj: _AggResamplerWindowObjT, func: AggFuncType, *, args, kwargs + ) -> None: ... + def apply(self): ... + def transform(self): ... + +def reconstruct_func( + func: AggFuncType | None, **kwargs +) -> tuple[bool, AggFuncType, list[str] | None, npt.NDArray[np.intp] | None]: ... +def is_multi_agg_with_relabel(**kwargs) -> bool: ... +def normalize_keyword_aggregation( + kwargs: dict, +) -> tuple[dict[str, list], list[str], npt.NDArray[np.intp]]: ... +def relabel_result( + result: DataFrame | Series, + func: dict[str, list[Callable | str]], + columns: Iterable[Hashable], + order: Iterable[int], +) -> dict[Hashable, Series]: ... +def reconstruct_and_relabel_result(result, func, **kwargs): ... +def maybe_mangle_lambdas(agg_spec: Any) -> Any: ... +def validate_func_kwargs( + kwargs: dict, +) -> tuple[list[str], list[str | Callable[..., Any]]]: ... +def include_axis( + op_name: Literal["agg", "apply"], colg: Series | DataFrame +) -> bool: ... +def warn_alias_replacement(obj, func: Callable, alias: str) -> None: ... diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index fb31f13f6..c1f36fcfa 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -1,7 +1,12 @@ -from collections.abc import Iterator +from collections.abc import ( + Hashable, + Iterator, +) from typing import ( + Any, Generic, Literal, + final, ) import numpy as np @@ -19,13 +24,21 @@ from pandas._typing import ( Scalar, npt, ) +from pandas.util._decorators import cache_readonly + +class PandasObject: ... class NoNewAttributesMixin: - def __setattr__(self, key, value) -> None: ... + def __setattr__(self, key: str, value: Any) -> None: ... class SelectionMixin(Generic[NDFrameT]): + obj: NDFrameT + exclusions: frozenset[Hashable] + @final + @cache_readonly def ndim(self) -> int: ... def __getitem__(self, key): ... + def aggregate(self, func, *args, **kwargs): ... class IndexOpsMixin(OpsMixin, Generic[S1]): __array_priority__: int = ... diff --git a/pandas-stubs/core/frame.pyi b/pandas-stubs/core/frame.pyi index ff34e31ad..45f02ca25 100644 --- a/pandas-stubs/core/frame.pyi +++ b/pandas-stubs/core/frame.pyi @@ -41,7 +41,6 @@ from pandas.core.indexing import ( _LocIndexer, ) from pandas.core.interchange.dataframe_protocol import DataFrame as DataFrameXchg -from pandas.core.resample import Resampler from pandas.core.series import Series from pandas.core.window import ( Expanding, @@ -54,6 +53,7 @@ from pandas.core.window.rolling import ( from typing_extensions import Self import xarray as xr +from pandas._libs.lib import NoDefault from pandas._libs.missing import NAType from pandas._libs.tslibs import BaseOffset from pandas._libs.tslibs.nattype import NaTType @@ -1006,104 +1006,96 @@ class DataFrame(NDFrame, OpsMixin): def groupby( self, by: Scalar, - axis: AxisIndex = ..., + axis: AxisIndex | NoDefault = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> DataFrameGroupBy[Scalar]: ... @overload def groupby( self, by: DatetimeIndex, - axis: AxisIndex = ..., + axis: AxisIndex | NoDefault = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> DataFrameGroupBy[Timestamp]: ... @overload def groupby( self, by: TimedeltaIndex, - axis: AxisIndex = ..., + axis: AxisIndex | NoDefault = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> DataFrameGroupBy[Timedelta]: ... @overload def groupby( self, by: PeriodIndex, - axis: AxisIndex = ..., + axis: AxisIndex | NoDefault = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> DataFrameGroupBy[Period]: ... @overload def groupby( self, by: IntervalIndex[IntervalT], - axis: AxisIndex = ..., + axis: AxisIndex | NoDefault = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> DataFrameGroupBy[IntervalT]: ... @overload def groupby( self, by: MultiIndex | GroupByObjectNonScalar | None = ..., - axis: AxisIndex = ..., + axis: AxisIndex | NoDefault = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> DataFrameGroupBy[tuple]: ... @overload def groupby( self, by: Series[SeriesByT], - axis: AxisIndex = ..., + axis: AxisIndex | NoDefault = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> DataFrameGroupBy[SeriesByT]: ... @overload def groupby( self, by: CategoricalIndex | Index | Series, - axis: AxisIndex = ..., + axis: AxisIndex | NoDefault = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> DataFrameGroupBy[Any]: ... def pivot( @@ -1921,21 +1913,6 @@ class DataFrame(NDFrame, OpsMixin): *, inplace: Literal[False] = ..., ) -> DataFrame: ... - def resample( - self, - rule, - axis: Axis = ..., - closed: _str | None = ..., - label: _str | None = ..., - convention: TimestampConvention = ..., - kind: Literal["timestamp", "period"] | None = ..., - on: _str | None = ..., - level: Level | None = ..., - origin: Timestamp - | Literal["epoch", "start", "start_day", "end", "end_day"] = ..., - offset: dt.timedelta | Timedelta | _str | None = ..., - group_keys: _bool = ..., - ) -> Resampler[DataFrame]: ... def rfloordiv( self, other, diff --git a/pandas-stubs/core/generic.pyi b/pandas-stubs/core/generic.pyi index e491b918f..75fb8c106 100644 --- a/pandas-stubs/core/generic.pyi +++ b/pandas-stubs/core/generic.pyi @@ -17,6 +17,7 @@ from typing import ( import numpy as np from pandas import Index import pandas.core.indexing as indexing +from pandas.core.resample import DatetimeIndexResampler from pandas.core.series import Series import sqlalchemy.engine from typing_extensions import ( @@ -24,6 +25,7 @@ from typing_extensions import ( Self, ) +from pandas._libs.lib import NoDefault from pandas._typing import ( S1, ArrayLike, @@ -37,6 +39,7 @@ from pandas._typing import ( FilePath, FileWriteMode, FillnaOptions, + Frequency, HashableT1, HashableT2, HDFCompLib, @@ -48,6 +51,10 @@ from pandas._typing import ( SortKind, StorageOptions, T, + TimedeltaConvertibleTypes, + TimeGrouperOrigin, + TimestampConvention, + TimestampConvertibleTypes, WriteBuffer, ) @@ -432,6 +439,21 @@ class NDFrame(indexing.IndexingMixin): end_time, axis=..., ) -> Self: ... + @final + def resample( + self, + rule: Frequency, + axis: Axis | NoDefault = ..., + closed: Literal["right", "left"] | None = None, + label: Literal["right", "left"] | None = None, + convention: TimestampConvention = "start", + kind: Literal["period", "timestamp", "timedelta"] | None = None, + on: Level | None = None, + level: Level | None = None, + origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", + offset: TimedeltaConvertibleTypes | None = None, + group_keys: _bool = False, + ) -> DatetimeIndexResampler[Self]: ... def first(self, offset) -> Self: ... def last(self, offset) -> Self: ... def rank( diff --git a/pandas-stubs/core/groupby/__init__.pyi b/pandas-stubs/core/groupby/__init__.pyi index 178542b2f..27ed3b004 100644 --- a/pandas-stubs/core/groupby/__init__.pyi +++ b/pandas-stubs/core/groupby/__init__.pyi @@ -1,2 +1,15 @@ -from pandas.core.groupby.generic import NamedAgg as NamedAgg +from pandas.core.groupby.generic import ( + DataFrameGroupBy as DataFrameGroupBy, + NamedAgg as NamedAgg, + SeriesGroupBy as SeriesGroupBy, +) +from pandas.core.groupby.groupby import GroupBy as GroupBy from pandas.core.groupby.grouper import Grouper as Grouper + +__all__ = [ + "DataFrameGroupBy", + "NamedAgg", + "SeriesGroupBy", + "GroupBy", + "Grouper", +] diff --git a/pandas-stubs/core/groupby/base.pyi b/pandas-stubs/core/groupby/base.pyi index 199eb6b3d..7de0b07b9 100644 --- a/pandas-stubs/core/groupby/base.pyi +++ b/pandas-stubs/core/groupby/base.pyi @@ -1,4 +1,3 @@ -# from pandas.core.dtypes.common import is_list_like as is_list_like, is_scalar as is_scalar from collections.abc import Hashable import dataclasses @@ -6,3 +5,10 @@ import dataclasses class OutputKey: label: Hashable position: int + +plotting_methods: frozenset[str] +cythonized_kernels: frozenset[str] +reduction_kernels: frozenset[str] +transformation_kernels: frozenset[str] +groupby_other_methods: frozenset[str] +transform_kernel_allowlist: frozenset[str] diff --git a/pandas-stubs/core/groupby/categorical.pyi b/pandas-stubs/core/groupby/categorical.pyi index 002de503b..bb0fd51a7 100644 --- a/pandas-stubs/core/groupby/categorical.pyi +++ b/pandas-stubs/core/groupby/categorical.pyi @@ -1,6 +1,5 @@ -from pandas.core.arrays.categorical import ( # , CategoricalDtype as CategoricalDtype - Categorical, -) +from pandas.core.arrays.categorical import Categorical -def recode_for_groupby(c: Categorical, sort: bool, observed: bool): ... -def recode_from_groupby(c: Categorical, sort: bool, ci): ... +def recode_for_groupby( + c: Categorical, sort: bool, observed: bool +) -> tuple[Categorical, Categorical | None]: ... diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 878ea633d..008357932 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -1,7 +1,9 @@ from collections.abc import ( Callable, + Hashable, Iterable, Iterator, + Mapping, Sequence, ) from typing import ( @@ -9,142 +11,181 @@ from typing import ( Generic, Literal, NamedTuple, + TypeVar, + final, overload, ) -from matplotlib.axes import ( - Axes as PlotAxes, - SubplotBase as AxesSubplot, -) +from matplotlib.axes import Axes as PlotAxes +import numpy as np from pandas.core.frame import DataFrame -from pandas.core.generic import NDFrame -from pandas.core.groupby.groupby import ( # , get_groupby as get_groupby - GroupBy as GroupBy, +from pandas.core.groupby.groupby import ( + GroupBy, + GroupByPlot, ) -from pandas.core.groupby.grouper import Grouper from pandas.core.series import Series -from typing_extensions import TypeAlias +from typing_extensions import ( + Self, + TypeAlias, +) +from pandas._libs.lib import NoDefault from pandas._typing import ( S1, AggFuncTypeBase, AggFuncTypeFrame, + ArrayLike, Axis, ByT, + CorrelationMethod, + Dtype, + FillnaOptions, + IndexLabel, Level, ListLike, - RandomState, Scalar, + TakeIndexer, + WindowingEngine, + WindowingEngineKwargs, ) +from pandas.plotting import boxplot_frame_groupby + AggScalar: TypeAlias = str | Callable[..., Any] -ScalarResult = ... +ScalarResult = TypeVar("ScalarResult") # noqa: PYI001 class NamedAgg(NamedTuple): - column: str = ... - aggfunc: AggScalar = ... - -def generate_property(name: str, klass: type[NDFrame]): ... + column: str + aggfunc: AggScalar -class SeriesGroupBy(GroupBy, Generic[S1, ByT]): - def any(self, skipna: bool = ...) -> Series[bool]: ... - def all(self, skipna: bool = ...) -> Series[bool]: ... - def apply(self, func, *args, **kwargs) -> Series: ... +class SeriesGroupBy(GroupBy[Series[S1]], Generic[S1, ByT]): @overload - def aggregate(self, func: list[AggFuncTypeBase], *args, **kwargs) -> DataFrame: ... + def aggregate( + self, + func: list[AggFuncTypeBase], + *args, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + **kwargs, + ) -> DataFrame: ... @overload - def aggregate(self, func: AggFuncTypeBase, *args, **kwargs) -> Series: ... + def aggregate( + self, + func: AggFuncTypeBase | None = None, + *args, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + **kwargs, + ) -> Series: ... agg = aggregate - def transform(self, func: Callable | str, *args, **kwargs) -> Series: ... - def filter(self, func, dropna: bool = ..., *args, **kwargs): ... - def nunique(self, dropna: bool = ...) -> Series: ... - def describe(self, **kwargs) -> DataFrame: ... + def transform( + self, + func: Callable | str, + *args, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + **kwargs, + ) -> Series: ... + def filter( + self, func: Callable | str, dropna: bool = True, *args, **kwargs + ) -> Series: ... + def nunique(self, dropna: bool = True) -> Series[int]: ... + # describe delegates to super() method but here it has keyword-only parameters + def describe( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + self, + *, + percentiles: Iterable[float] | None = None, + include: Literal["all"] | list[Dtype] | None = None, + exclude: list[Dtype] | None = None, + ) -> DataFrame: ... @overload def value_counts( self, - normalize: Literal[False] = ..., - sort: bool = ..., - ascending: bool = ..., - bins=..., - dropna: bool = ..., + normalize: Literal[False] = False, + sort: bool = True, + ascending: bool = False, + bins=None, + dropna: bool = True, ) -> Series[int]: ... @overload def value_counts( self, normalize: Literal[True], - sort: bool = ..., - ascending: bool = ..., - bins=..., - dropna: bool = ..., + sort: bool = True, + ascending: bool = False, + bins=None, + dropna: bool = True, ) -> Series[float]: ... - def count(self) -> Series[int]: ... - def pct_change( + def fillna( self, - periods: int = ..., - fill_method: str = ..., - limit=..., - freq=..., - axis: Axis = ..., - ) -> Series[float]: ... - # Overrides and others from original pylance stubs - @property - def is_monotonic_increasing(self) -> bool: ... - @property - def is_monotonic_decreasing(self) -> bool: ... - def bfill(self, limit: int | None = ...) -> Series[S1]: ... - def cummax(self, axis: Axis = ..., **kwargs) -> Series[S1]: ... - def cummin(self, axis: Axis = ..., **kwargs) -> Series[S1]: ... - def cumprod(self, axis: Axis = ..., **kwargs) -> Series[S1]: ... - def cumsum(self, axis: Axis = ..., **kwargs) -> Series[S1]: ... - def ffill(self, limit: int | None = ...) -> Series[S1]: ... - def first(self, **kwargs) -> Series[S1]: ... - def head(self, n: int = ...) -> Series[S1]: ... - def last(self, **kwargs) -> Series[S1]: ... - def max(self, **kwargs) -> Series[S1]: ... - def mean(self, **kwargs) -> Series[S1]: ... - def median(self, **kwargs) -> Series[S1]: ... - def min(self, **kwargs) -> Series[S1]: ... - def nlargest(self, n: int = ..., keep: str = ...) -> Series[S1]: ... - def nsmallest(self, n: int = ..., keep: str = ...) -> Series[S1]: ... - def nth(self, n: int | Sequence[int], dropna: str | None = ...) -> Series[S1]: ... - def sum( + value: object | ArrayLike | None = None, + method: FillnaOptions | None = None, + axis: Axis | None | NoDefault = ..., + inplace: bool = False, + limit: int | None = None, + downcast: dict | None | NoDefault = ..., + ) -> Series[S1] | None: ... + def take( self, - numeric_only: bool = ..., - min_count: int = ..., - engine=..., - engine_kwargs=..., + indices: TakeIndexer, + axis: Axis | NoDefault = ..., + **kwargs, ) -> Series[S1]: ... - def prod(self, numeric_only: bool = ..., min_count: int = ...) -> Series[S1]: ... - def sem(self, ddof: int = ..., numeric_only: bool = ...) -> Series[float]: ... - def std(self, ddof: int = ..., numeric_only: bool = ...) -> Series[float]: ... - def var(self, ddof: int = ..., numeric_only: bool = ...) -> Series[float]: ... - def tail(self, n: int = ...) -> Series[S1]: ... - def unique(self) -> Series: ... + def skew( + self, + axis: Axis | NoDefault = ..., + skipna: bool = True, + numeric_only: bool = False, + **kwargs, + ) -> Series: ... + @property + def plot(self) -> GroupByPlot[Self]: ... + def nlargest( + self, n: int = 5, keep: Literal["first", "last", "all"] = "first" + ) -> Series[S1]: ... + def nsmallest( + self, n: int = 5, keep: Literal["first", "last", "all"] = "first" + ) -> Series[S1]: ... + def idxmin(self, axis: Axis | NoDefault = ..., skipna: bool = True) -> Series: ... + def idxmax(self, axis: Axis | NoDefault = ..., skipna: bool = True) -> Series: ... + def corr( + self, + other: Series, + method: CorrelationMethod = "pearson", + min_periods: int | None = None, + ) -> Series: ... + def cov( + self, other: Series, min_periods: int | None = None, ddof: int | None = 1 + ) -> Series: ... + @property + def is_monotonic_increasing(self) -> Series[bool]: ... + @property + def is_monotonic_decreasing(self) -> Series[bool]: ... def hist( self, - by=..., - ax: PlotAxes | None = ..., - grid: bool = ..., - xlabelsize: int | None = ..., - xrot: float | None = ..., - ylabelsize: int | None = ..., - yrot: float | None = ..., - figsize: tuple[float, float] | None = ..., - bins: int | Sequence = ..., - backend: str | None = ..., - legend: bool = ..., + by: IndexLabel | None = None, + ax: PlotAxes | None = None, + grid: bool = True, + xlabelsize: float | None = None, + xrot: float | None = None, + ylabelsize: float | None = None, + yrot: float | None = None, + figsize: tuple[float, float] | None = None, + bins: int | Sequence[int] = 10, + backend: str | None = None, + legend: bool = False, **kwargs, - ) -> AxesSubplot: ... - def idxmax(self, axis: Axis = ..., skipna: bool = ...) -> Series: ... - def idxmin(self, axis: Axis = ..., skipna: bool = ...) -> Series: ... - def __iter__(self) -> Iterator[tuple[ByT, Series[S1]]]: ... - def diff(self, periods: int = ..., axis: Axis = ...) -> Series: ... + ) -> Series: ... # Series[Axes] but this is not allowed + @property + def dtype(self) -> Series: ... + def unique(self) -> Series: ... + # Overrides that provide more precise return types over the GroupBy class + @final # type: ignore[misc] + def __iter__(self) -> Iterator[tuple[ByT, Series[S1]]]: ... # pyright: ignore -class DataFrameGroupBy(GroupBy, Generic[ByT]): - def any(self, skipna: bool = ...) -> DataFrame: ... - def all(self, skipna: bool = ...) -> DataFrame: ... +class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): # error: Overload 3 for "apply" will never be used because its parameters overlap overload 1 - @overload + @overload # type: ignore[override] def apply( # type: ignore[overload-overlap] self, func: Callable[[DataFrame], Scalar | list | dict], @@ -159,7 +200,7 @@ class DataFrameGroupBy(GroupBy, Generic[ByT]): **kwargs, ) -> DataFrame: ... @overload - def apply( # pyright: ignore[reportOverlappingOverload] + def apply( # pyright: ignore[reportOverlappingOverload,reportIncompatibleMethodOverride] self, func: Callable[[Iterable], float], *args, @@ -167,162 +208,50 @@ class DataFrameGroupBy(GroupBy, Generic[ByT]): ) -> DataFrame: ... # error: overload 1 overlaps overload 2 because of different return types @overload - def aggregate(self, arg: Literal["size"]) -> Series: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - @overload - def aggregate(self, arg: AggFuncTypeFrame = ..., *args, **kwargs) -> DataFrame: ... - agg = aggregate - def transform(self, func: Callable | str, *args, **kwargs) -> DataFrame: ... - def filter( - self, func: Callable, dropna: bool = ..., *args, **kwargs - ) -> DataFrame: ... - def nunique(self, dropna: bool = ...) -> DataFrame: ... - @overload - def __getitem__(self, item: str) -> SeriesGroupBy[Any, ByT]: ... + def aggregate(self, func: Literal["size"]) -> Series: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload - def __getitem__(self, item: list[str]) -> DataFrameGroupBy[ByT]: ... - def count(self) -> DataFrame: ... - def boxplot( + def aggregate( self, - grouped: DataFrame, - subplots: bool = ..., - column: str | Sequence | None = ..., - fontsize: float | str = ..., - rot: float = ..., - grid: bool = ..., - ax: PlotAxes | None = ..., - figsize: tuple[float, float] | None = ..., - layout: tuple[int, int] | None = ..., - sharex: bool = ..., - sharey: bool = ..., - bins: int | Sequence = ..., - backend: str | None = ..., + func: AggFuncTypeFrame | None = None, + *args, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, **kwargs, - ) -> AxesSubplot | Sequence[AxesSubplot]: ... - # Overrides and others from original pylance stubs - # These are "properties" but properties can't have all these arguments?! - def corr(self, method: str | Callable, min_periods: int = ...) -> DataFrame: ... - def cov(self, min_periods: int = ...) -> DataFrame: ... - def diff(self, periods: int = ..., axis: Axis = ...) -> DataFrame: ... - def bfill(self, limit: int | None = ...) -> DataFrame: ... - def corrwith( - self, - other: DataFrame, - axis: Axis = ..., - drop: bool = ..., - method: str = ..., - ) -> Series: ... - def cummax( - self, axis: Axis = ..., numeric_only: bool = ..., **kwargs ) -> DataFrame: ... - def cummin( - self, axis: Axis = ..., numeric_only: bool = ..., **kwargs - ) -> DataFrame: ... - def cumprod(self, axis: Axis = ..., **kwargs) -> DataFrame: ... - def cumsum(self, axis: Axis = ..., **kwargs) -> DataFrame: ... - def describe(self, **kwargs) -> DataFrame: ... - def ffill(self, limit: int | None = ...) -> DataFrame: ... - def fillna( - self, - value, - method: str | None = ..., - axis: Axis = ..., - inplace: Literal[False] = ..., - limit: int | None = ..., - downcast: dict | None = ..., - ) -> DataFrame: ... - def first(self, **kwargs) -> DataFrame: ... - def head(self, n: int = ...) -> DataFrame: ... - def hist( + agg = aggregate + def transform( self, - data: DataFrame, - column: str | Sequence | None = ..., - by=..., - grid: bool = ..., - xlabelsize: int | None = ..., - xrot: float | None = ..., - ylabelsize: int | None = ..., - yrot: float | None = ..., - ax: PlotAxes | None = ..., - sharex: bool = ..., - sharey: bool = ..., - figsize: tuple[float, float] | None = ..., - layout: tuple[int, int] | None = ..., - bins: int | Sequence = ..., - backend: str | None = ..., + func: Callable | str, + *args, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, **kwargs, - ) -> AxesSubplot | Sequence[AxesSubplot]: ... - def idxmax( - self, axis: Axis = ..., skipna: bool = ..., numeric_only: bool = ... - ) -> DataFrame: ... - def idxmin( - self, axis: Axis = ..., skipna: bool = ..., numeric_only: bool = ... - ) -> DataFrame: ... - def last(self, **kwargs) -> DataFrame: ... - def max(self, **kwargs) -> DataFrame: ... - def mean(self, **kwargs) -> DataFrame: ... - def median(self, **kwargs) -> DataFrame: ... - def min(self, **kwargs) -> DataFrame: ... - def nth(self, n: int | Sequence[int], dropna: str | None = ...) -> DataFrame: ... - def pct_change( - self, - periods: int = ..., - fill_method: str = ..., - limit=..., - freq=..., - axis: Axis = ..., - ) -> DataFrame: ... - def prod(self, numeric_only: bool = ..., min_count: int = ...) -> DataFrame: ... - def quantile( - self, q: float = ..., interpolation: str = ..., numeric_only: bool = ... - ) -> DataFrame: ... - def resample(self, rule, *args, **kwargs) -> Grouper: ... - def sample( - self, - n: int | None = ..., - frac: float | None = ..., - replace: bool = ..., - weights: ListLike | None = ..., - random_state: RandomState | None = ..., ) -> DataFrame: ... - def sem(self, ddof: int = ..., numeric_only: bool = ...) -> DataFrame: ... - def shift( - self, - periods: int = ..., - freq: str = ..., - axis: Axis = ..., - fill_value=..., + def filter( + self, func: Callable, dropna: bool = True, *args, **kwargs ) -> DataFrame: ... @overload - def skew( - self, - axis: Axis = ..., - skipna: bool = ..., - numeric_only: bool = ..., - *, - level: Level, - **kwargs, - ) -> DataFrame: ... + def __getitem__( # type: ignore[overload-overlap] + self, key: Scalar | Hashable | tuple[Hashable, ...] + ) -> SeriesGroupBy[Any, ByT]: ... @overload - def skew( + def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] + self, key: Iterable[Hashable] | slice + ) -> DataFrameGroupBy[ByT]: ... + def nunique(self, dropna: bool = True) -> DataFrame: ... + def idxmax( self, - axis: Axis = ..., - skipna: bool = ..., - level: None = ..., - numeric_only: bool = ..., - **kwargs, - ) -> Series: ... - def std(self, ddof: int = ..., numeric_only: bool = ...) -> DataFrame: ... - def sum( + axis: Axis | None | NoDefault = ..., + skipna: bool = True, + numeric_only: bool = False, + ) -> DataFrame: ... + def idxmin( self, - numeric_only: bool = ..., - min_count: int = ..., - engine=..., - engine_kwargs=..., + axis: Axis | None | NoDefault = ..., + skipna: bool = True, + numeric_only: bool = False, ) -> DataFrame: ... - def tail(self, n: int = ...) -> DataFrame: ... - def take(self, indices: Sequence, axis: Axis = ..., **kwargs) -> DataFrame: ... - def tshift(self, periods: int, freq=..., axis: Axis = ...) -> DataFrame: ... - def var(self, ddof: int = ..., numeric_only: bool = ...) -> DataFrame: ... + boxplot = boxplot_frame_groupby @overload def value_counts( self, @@ -341,5 +270,82 @@ class DataFrameGroupBy(GroupBy, Generic[ByT]): ascending: bool = ..., dropna: bool = ..., ) -> Series[float]: ... + def fillna( + self, + value: Hashable | Mapping | Series | DataFrame | None = None, + method: FillnaOptions | None = None, + axis: Axis | None | NoDefault = ..., + inplace: Literal[False] = False, + limit: int | None = None, + downcast: dict | None | NoDefault = ..., + ) -> DataFrame: ... + def take( + self, indices: TakeIndexer, axis: Axis | None | NoDefault = ..., **kwargs + ) -> DataFrame: ... + @overload + def skew( # type: ignore[overload-overlap] + self, + axis: Axis | None | NoDefault = ..., + skipna: bool = True, + numeric_only: bool = False, + *, + level: Level, + **kwargs, + ) -> DataFrame: ... + @overload + def skew( + self, + axis: Axis | None | NoDefault = ..., + skipna: bool = True, + numeric_only: bool = False, + *, + level: None = None, + **kwargs, + ) -> Series: ... + @property + def plot(self) -> GroupByPlot[Self]: ... + def corr( + self, + method: str | Callable[[np.ndarray, np.ndarray], float] = "pearson", + min_periods: int = 1, + numeric_only: bool = False, + ) -> DataFrame: ... + def cov( + self, + min_periods: int | None = None, + ddof: int | None = 1, + numeric_only: bool = False, + ) -> DataFrame: ... + def hist( + self, + column: IndexLabel | None = None, + by: IndexLabel | None = None, + grid: bool = True, + xlabelsize: float | None = None, + xrot: float | None = None, + ylabelsize: float | None = None, + yrot: float | None = None, + ax: PlotAxes | None = None, + sharex: bool = False, + sharey: bool = False, + figsize: tuple[float, float] | None = None, + layout: tuple[int, int] | None = None, + bins: int | Sequence[int] = 10, + backend: str | None = None, + legend: bool = False, + **kwargs, + ) -> Series: ... # Series[Axes] but this is not allowed + @property + def dtypes(self) -> Series: ... + def corrwith( + self, + other: DataFrame | Series, + axis: Axis | NoDefault = ..., + drop: bool = False, + method: CorrelationMethod = "pearson", + numeric_only: bool = False, + ) -> DataFrame: ... def __getattr__(self, name: str) -> SeriesGroupBy[Any, ByT]: ... - def __iter__(self) -> Iterator[tuple[ByT, DataFrame]]: ... + # Overrides that provide more precise return types over the GroupBy class + @final # type: ignore[misc] + def __iter__(self) -> Iterator[tuple[ByT, DataFrame]]: ... # pyright: ignore diff --git a/pandas-stubs/core/groupby/groupby.pyi b/pandas-stubs/core/groupby/groupby.pyi index 32942ab16..d59f59715 100644 --- a/pandas-stubs/core/groupby/groupby.pyi +++ b/pandas-stubs/core/groupby/groupby.pyi @@ -1,115 +1,436 @@ from collections.abc import ( Callable, Hashable, + Iterable, + Iterator, + Mapping, + Sequence, +) +import datetime as dt +from typing import ( + Any, + Generic, + Literal, + TypeVar, + final, + overload, ) import numpy as np -from pandas.core.base import SelectionMixin +from pandas.core.base import ( + PandasObject, + SelectionMixin, +) from pandas.core.frame import DataFrame -from pandas.core.generic import NDFrame -from pandas.core.groupby import ops +from pandas.core.groupby import ( + generic, + ops, +) +from pandas.core.groupby.indexing import ( + GroupByIndexingMixin, + GroupByNthSelector, +) +from pandas.core.indexers import BaseIndexer from pandas.core.indexes.api import Index +from pandas.core.resample import _ResamplerGroupBy from pandas.core.series import Series +from pandas.core.window import ( + ExpandingGroupby, + ExponentialMovingWindowGroupby, + RollingGroupby, +) +from typing_extensions import ( + Concatenate, + Self, + TypeAlias, +) +from pandas._libs.lib import NoDefault +from pandas._libs.tslibs import BaseOffset from pandas._typing import ( + S1, + AnyArrayLike, Axis, + AxisInt, + CalculationMethod, + Dtype, + FillnaOptions, + Frequency, + IndexLabel, + IntervalClosedType, KeysArgType, + MaskType, NDFrameT, + P, + RandomState, + Scalar, + T, + TimedeltaConvertibleTypes, + TimeGrouperOrigin, + TimestampConvention, + TimestampConvertibleTypes, + WindowingEngine, + WindowingEngineKwargs, npt, ) -class GroupByPlot: - def __init__(self, groupby) -> None: ... - def __call__(self, *args, **kwargs): ... - def __getattr__(self, name: str): ... +from pandas.plotting import PlotAccessor -class BaseGroupBy(SelectionMixin[NDFrameT]): - level = ... - as_index = ... - keys = ... - sort = ... - group_keys = ... - squeeze = ... - observed = ... - mutated = ... - @property - def obj(self) -> NDFrameT: ... - axis = ... - grouper = ... - exclusions = ... +_GroupByT = TypeVar("_GroupByT", bound=GroupBy) + +_KeysArgType: TypeAlias = ( + Hashable + | list[Hashable] + | Callable[[Hashable], Hashable] + | list[Callable[[Hashable], Hashable]] + | Mapping[Hashable, Hashable] +) + +# GroupByPlot does not really inherit from PlotAccessor but it delegates +# to it using __call__ and __getattr__. We lie here to avoid repeating the +# whole stub of PlotAccessor +@final +class GroupByPlot(PandasObject, PlotAccessor, Generic[_GroupByT]): + def __init__(self, groupby: _GroupByT) -> None: ... + # The following methods are inherited from the fake parent class PlotAccessor + # def __call__(self, *args, **kwargs): ... + # def __getattr__(self, name: str): ... + +class BaseGroupBy(PandasObject, SelectionMixin[NDFrameT], GroupByIndexingMixin): + axis: AxisInt + grouper: ops.BaseGrouper + keys: _KeysArgType | None + level: IndexLabel | None + group_keys: bool + @final def __len__(self) -> int: ... + @final + def __repr__(self) -> str: ... # noqa: PYI029 __repr__ here is final + @final @property - def groups(self) -> dict[Hashable, list[Hashable]]: ... + def groups(self) -> dict[Hashable, Index]: ... + @final @property def ngroups(self) -> int: ... + @final @property def indices(self) -> dict[Hashable, Index | npt.NDArray[np.int_] | list[int]]: ... - def pipe(self, func: Callable, *args, **kwargs): ... - plot = ... + @overload + def pipe( + self, + func: Callable[Concatenate[Self, P], T], + *args: P.args, + **kwargs: P.kwargs, + ) -> T: ... + @overload + def pipe( + self, + func: tuple[Callable[..., T], str], + *args: Any, + **kwargs: Any, + ) -> T: ... + @final def get_group(self, name, obj: NDFrameT | None = ...) -> NDFrameT: ... + @final + def __iter__(self) -> Iterator[tuple[Hashable, NDFrameT]]: ... + @overload + def __getitem__(self: BaseGroupBy[DataFrame], key: Scalar | Hashable | tuple[Hashable, ...]) -> generic.SeriesGroupBy: ... # type: ignore[overload-overlap] + @overload + def __getitem__( + self: BaseGroupBy[DataFrame], key: Iterable[Hashable] | slice + ) -> generic.DataFrameGroupBy: ... + @overload + def __getitem__( + self: BaseGroupBy[Series[S1]], + idx: ( + list[str] + | Index + | Series[S1] + | slice + | MaskType + | tuple[Hashable | slice, ...] + ), + ) -> generic.SeriesGroupBy: ... + @overload + def __getitem__(self: BaseGroupBy[Series[S1]], idx: Scalar) -> S1: ... class GroupBy(BaseGroupBy[NDFrameT]): - def count(self) -> DataFrame | Series: ... - def mean(self, **kwargs) -> DataFrame | Series: ... - def median(self, **kwargs) -> DataFrame | Series: ... - def std(self, ddof: int = ..., numeric_only: bool = ...) -> DataFrame | Series: ... - def var(self, ddof: int = ..., numeric_only: bool = ...) -> DataFrame | Series: ... - def sem(self, ddof: int = ..., numeric_only: bool = ...) -> DataFrame | Series: ... + as_index: bool + sort: bool + observed: bool + @final + def __init__( + self, + obj: NDFrameT, + keys: _KeysArgType | None = None, + axis: Axis = 0, + level: IndexLabel | None = None, + grouper: ops.BaseGrouper | None = None, + exclusions: frozenset[Hashable] | None = None, + selection: IndexLabel | None = None, + as_index: bool = True, + sort: bool = True, + group_keys: bool = True, + observed: bool | NoDefault = ..., + dropna: bool = True, + ) -> None: ... + def __getattr__(self, attr: str) -> Any: ... + def apply(self, func: Callable | str, *args, **kwargs) -> NDFrameT: ... + @final + @overload + def any(self: GroupBy[Series], skipna: bool = True) -> Series[bool]: ... + @overload + def any(self: GroupBy[DataFrame], skipna: bool = True) -> DataFrame: ... + @final + @overload + def all(self: GroupBy[Series], skipna: bool = True) -> Series[bool]: ... + @overload + def all(self: GroupBy[DataFrame], skipna: bool = True) -> DataFrame: ... + @final + def count(self) -> NDFrameT: ... + @final + def mean( + self, + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + ) -> NDFrameT: ... + @final + def median(self, numeric_only: bool = False) -> NDFrameT: ... + @final + @overload + def std( + self: GroupBy[Series], + ddof: int = 1, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = False, + ) -> Series[float]: ... + @overload + def std( + self: GroupBy[DataFrame], + ddof: int = 1, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = False, + ) -> DataFrame: ... + @final + @overload + def var( + self: GroupBy[Series], + ddof: int = 1, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = False, + ) -> Series[float]: ... + @overload + def var( + self: GroupBy[DataFrame], + ddof: int = 1, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = False, + ) -> DataFrame: ... + @final + @overload + def sem( + self: GroupBy[Series], ddof: int = 1, numeric_only: bool = False + ) -> Series[float]: ... + @overload + def sem( + self: GroupBy[DataFrame], ddof: int = 1, numeric_only: bool = False + ) -> DataFrame: ... + @final + @overload + def size(self: GroupBy[Series]) -> Series[int]: ... + @overload # return type depends on `as_index` for dataframe groupby + def size(self: GroupBy[DataFrame]) -> DataFrame | Series[int]: ... + @final + def sum( + self, + numeric_only: bool = False, + min_count: int = 0, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + ) -> NDFrameT: ... + @final + def prod(self, numeric_only: bool = False, min_count: int = 0) -> NDFrameT: ... + @final + def min( + self, + numeric_only: bool = False, + min_count: int = -1, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + ) -> NDFrameT: ... + @final + def max( + self, + numeric_only: bool = False, + min_count: int = -1, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + ) -> NDFrameT: ... + @final + def first(self, numeric_only: bool = False, min_count: int = -1) -> NDFrameT: ... + @final + def last(self, numeric_only: bool = False, min_count: int = -1) -> NDFrameT: ... + @final def ohlc(self) -> DataFrame: ... - def describe(self, **kwargs) -> DataFrame | Series: ... - def resample(self, rule, *args, **kwargs): ... - def rolling(self, *args, **kwargs): ... - def expanding(self, *args, **kwargs): ... - def ffill(self, limit: int | None = ...) -> DataFrame | Series: ... - def bfill(self, limit: int | None = ...) -> DataFrame | Series: ... - def nth( - self, n: int | list[int], dropna: str | None = ... - ) -> DataFrame | Series: ... - def quantile(self, q=..., interpolation: str = ...): ... - def ngroup(self, ascending: bool = ...) -> Series: ... - def cumcount(self, ascending: bool = ...) -> Series: ... - def rank( + def describe( self, - method: str = ..., - ascending: bool = ..., - na_option: str = ..., - pct: bool = ..., - axis: int = ..., + percentiles: Iterable[float] | None = None, + include: Literal["all"] | list[Dtype] | None = None, + exclude: list[Dtype] | None = None, ) -> DataFrame: ... - def cummax(self, axis: Axis = ..., **kwargs) -> DataFrame | Series: ... - def cummin(self, axis: Axis = ..., **kwargs) -> DataFrame | Series: ... - def cumprod(self, axis: Axis = ..., **kwargs) -> DataFrame | Series: ... - def cumsum(self, axis: Axis = ..., **kwargs) -> DataFrame | Series: ... - def shift(self, periods: int = ..., freq=..., axis: Axis = ..., fill_value=...): ... + @final + def resample( + self, + rule: Frequency, + # Arguments must be kept roughly inline with pandas.core.resample.get_resampler_for_grouping + how: str | None = None, + fill_method: str | None = None, + limit: int | None = None, + kind: str | None = None, + on: Hashable | None = None, + *, + closed: Literal["left", "right"] | None = None, + label: Literal["left", "right"] | None = None, + axis: Axis = 0, + convention: TimestampConvention | None = None, + origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", + offset: TimedeltaConvertibleTypes | None = None, + group_keys: bool = False, + **kwargs, + ) -> _ResamplerGroupBy[NDFrameT]: ... + @final + def rolling( + self, + # Arguments must be kept roughly inline with pandas.core.window.RollingGroupby + window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = None, + min_periods: int | None = None, + center: bool | None = False, + win_type: str | None = None, + axis: Axis = 0, + on: str | Index | None = None, + closed: IntervalClosedType | None = None, + step: int | None = None, + method: str = "single", + *, + selection: IndexLabel | None = None, + ) -> RollingGroupby[NDFrameT]: ... + @final + def expanding( + self, + # Arguments must be kept roughly inline with pandas.core.window.ExpandingGroupby + min_periods: int = 1, + axis: Axis = 0, + method: str = "single", + selection: IndexLabel | None = None, + ) -> ExpandingGroupby[NDFrameT]: ... + @final + def ewm( + self, + # Arguments must be kept roughly inline with pandas.core.window.ExponentialMovingWindowGroupby + com: float | None = None, + span: float | None = None, + halflife: TimedeltaConvertibleTypes | None = None, + alpha: float | None = None, + min_periods: int | None = 0, + adjust: bool = True, + ignore_na: bool = False, + axis: Axis = 0, + times: str | np.ndarray | Series | np.timedelta64 | None = None, + method: CalculationMethod = "single", + *, + selection: IndexLabel | None = None, + ) -> ExponentialMovingWindowGroupby[NDFrameT]: ... + @final + def ffill(self, limit: int | None = None) -> NDFrameT: ... + @final + def bfill(self, limit: int | None = None) -> NDFrameT: ... + @final + @property + def nth(self) -> GroupByNthSelector[Self]: ... + @final + def quantile( + self, + q: float | AnyArrayLike = 0.5, + interpolation: str = "linear", + numeric_only: bool = False, + ) -> NDFrameT: ... + @final + def ngroup(self, ascending: bool = True) -> Series[int]: ... + @final + def cumcount(self, ascending: bool = True) -> Series[int]: ... + @final + def rank( + self, + method: str = "average", + ascending: bool = True, + na_option: str = "keep", + pct: bool = False, + axis: AxisInt | NoDefault = ..., + ) -> NDFrameT: ... + @final + def cumprod(self, axis: Axis | NoDefault = ..., *args, **kwargs) -> NDFrameT: ... + @final + def cumsum(self, axis: Axis | NoDefault = ..., *args, **kwargs) -> NDFrameT: ... + @final + def cummin( + self, axis: AxisInt | NoDefault = ..., numeric_only: bool = False, **kwargs + ) -> NDFrameT: ... + @final + def cummax( + self, axis: AxisInt | NoDefault = ..., numeric_only: bool = False, **kwargs + ) -> NDFrameT: ... + @final + def shift( + self, + periods: int | Sequence[int] = 1, + freq: Frequency | None = None, + axis: Axis | NoDefault = ..., + fill_value=..., + suffix: str | None = None, + ) -> NDFrameT: ... + @final + def diff(self, periods: int = 1, axis: AxisInt | NoDefault = ...) -> NDFrameT: ... + @final def pct_change( self, - periods: int = ..., - fill_method: str = ..., - limit=..., - freq=..., - axis: Axis = ..., - ) -> DataFrame | Series: ... - def head(self, n: int = ...) -> DataFrame | Series: ... - def tail(self, n: int = ...) -> DataFrame | Series: ... - # Surplus methods from original pylance stubs; should they go away? - def first(self, **kwargs) -> DataFrame | Series: ... - def last(self, **kwargs) -> DataFrame | Series: ... - def max(self, **kwargs) -> DataFrame | Series: ... - def min(self, **kwargs) -> DataFrame | Series: ... - def size(self) -> Series[int]: ... + periods: int = 1, + fill_method: FillnaOptions | None | NoDefault = ..., + limit: int | None | NoDefault = ..., + freq=None, + axis: Axis | NoDefault = ..., + ) -> NDFrameT: ... + @final + def head(self, n: int = 5) -> NDFrameT: ... + @final + def tail(self, n: int = 5) -> NDFrameT: ... + @final + def sample( + self, + n: int | None = None, + frac: float | None = None, + replace: bool = False, + weights: Sequence | Series | None = None, + random_state: RandomState | None = None, + ) -> NDFrameT: ... +@overload +def get_groupby( + obj: Series, + by: KeysArgType | None = None, + axis: int = 0, + grouper: ops.BaseGrouper | None = None, + group_keys: bool = True, +) -> generic.SeriesGroupBy: ... +@overload def get_groupby( - obj: NDFrame, - by: KeysArgType | None = ..., - axis: int = ..., - level=..., - grouper: ops.BaseGrouper | None = ..., - exclusions=..., - selection=..., - as_index: bool = ..., - sort: bool = ..., - group_keys: bool = ..., - squeeze: bool = ..., - observed: bool = ..., - mutated: bool = ..., -) -> GroupBy: ... + obj: DataFrame, + by: KeysArgType | None = None, + axis: int = 0, + grouper: ops.BaseGrouper | None = None, + group_keys: bool = True, +) -> generic.DataFrameGroupBy: ... diff --git a/pandas-stubs/core/groupby/grouper.pyi b/pandas-stubs/core/groupby/grouper.pyi index 65d76109b..5f42d6ca6 100644 --- a/pandas-stubs/core/groupby/grouper.pyi +++ b/pandas-stubs/core/groupby/grouper.pyi @@ -1,4 +1,11 @@ -from collections.abc import Hashable +from collections.abc import ( + Hashable, + Iterator, +) +from typing import ( + final, + overload, +) import numpy as np from pandas import ( @@ -7,67 +14,115 @@ from pandas import ( Series, ) from pandas.core.groupby.ops import BaseGrouper +from pandas.core.resample import TimeGrouper +from typing_extensions import ( + Self, + deprecated, +) -from pandas._typing import NDFrameT +from pandas._libs.lib import NoDefault +from pandas._typing import ( + ArrayLike, + Axis, + Frequency, + Incomplete, + KeysArgType, + Level, + ListLikeHashable, + NDFrameT, + npt, +) +from pandas.util._decorators import cache_readonly class Grouper: - def __new__(cls, *args, **kwargs): ... - key = ... - level = ... - freq = ... - axis = ... - sort = ... - grouper = ... - obj = ... - indexer = ... - binner = ... + key: KeysArgType | None + level: Level | ListLikeHashable[Level] | None + freq: Frequency | None + axis: Axis + sort: bool + dropna: bool + binner: Incomplete + @overload + def __new__( + cls, + key: KeysArgType | None = None, + level: Level | ListLikeHashable[Level] | None = None, + axis: Axis | NoDefault = ..., + sort: bool = False, + dropna: bool = True, + ) -> Self: ... + @overload + def __new__(cls, *args, freq: Frequency, **kwargs) -> TimeGrouper: ... def __init__( - self, key=..., level=..., freq=..., axis: int = ..., sort: bool = ... + self, + key: KeysArgType | None = None, + level: Level | ListLikeHashable[Level] | None = None, + freq: Frequency | None = None, + axis: Axis | NoDefault = ..., + sort: bool = False, + dropna: bool = True, ) -> None: ... @property + @deprecated("Grouper.ax is deprecated. Use Resampler.ax instead.") def ax(self): ... @property + @deprecated("Grouper.indexer is deprecated. Use Resampler.indexer instead.") + def indexer(self): ... + @property + @deprecated("Grouper.obj is deprecated. Use GroupBy.obj instead.") + def obj(self): ... + @property + @deprecated("Grouper.grouper is deprecated. Use GroupBy.grouper instead.") + def grouper(self): ... + @property + @deprecated("Grouper.groups is deprecated. Use GroupBy.groups instead.") def groups(self): ... + @final + def __repr__(self) -> str: ... # noqa: PYI029 __repr__ here is final +@final class Grouping: - name = ... - level = ... - grouper = ... - all_grouper = ... - index = ... - sort = ... - obj = ... - observed = ... - in_axis = ... + level: Level | None + obj: DataFrame | Series | None + in_axis: bool + grouping_vector: Incomplete def __init__( self, index: Index, - grouper=..., - obj: DataFrame | Series | None = ..., - name=..., - level=..., - sort: bool = ..., - observed: bool = ..., - in_axis: bool = ..., + grouper=None, + obj: DataFrame | Series | None = None, + level: Level | None = None, + sort: bool = True, + observed: bool = False, + in_axis: bool = False, + dropna: bool = True, + uniques: ArrayLike | None = None, ) -> None: ... - def __iter__(self): ... - @property + def __iter__(self) -> Iterator[Hashable]: ... + @cache_readonly + def name(self) -> Hashable: ... + @cache_readonly def ngroups(self) -> int: ... - def indices(self): ... + @cache_readonly + def indices(self) -> dict[Hashable, npt.NDArray[np.intp]]: ... @property - def codes(self) -> np.ndarray: ... + def codes(self) -> npt.NDArray[np.signedinteger]: ... + @cache_readonly + def group_arraylike(self) -> ArrayLike: ... + @cache_readonly def result_index(self) -> Index: ... - @property + @cache_readonly def group_index(self) -> Index: ... + @cache_readonly def groups(self) -> dict[Hashable, np.ndarray]: ... def get_grouper( obj: NDFrameT, - key=..., - axis: int = ..., - level=..., - sort: bool = ..., - observed: bool = ..., - mutated: bool = ..., - validate: bool = ..., -) -> tuple[BaseGrouper, list[Hashable], NDFrameT]: ... + key: KeysArgType | None = None, + axis: Axis = 0, + level: Level | ListLikeHashable[Level] | None = None, + sort: bool = True, + observed: bool = False, + validate: bool = True, + dropna: bool = True, +) -> tuple[BaseGrouper, frozenset[Hashable], NDFrameT]: ... diff --git a/pandas-stubs/core/groupby/indexing.pyi b/pandas-stubs/core/groupby/indexing.pyi new file mode 100644 index 000000000..2532b3d4a --- /dev/null +++ b/pandas-stubs/core/groupby/indexing.pyi @@ -0,0 +1,34 @@ +from typing import ( + Any, + Generic, + Literal, + TypeVar, +) + +from pandas import ( + DataFrame, + Series, +) +from pandas.core.groupby import groupby + +from pandas._typing import PositionalIndexer + +_GroupByT = TypeVar("_GroupByT", bound=groupby.GroupBy[Any]) + +class GroupByIndexingMixin: ... + +class GroupByPositionalSelector: + groupby_object: groupby.GroupBy + def __init__(self, groupby_object: groupby.GroupBy) -> None: ... + def __getitem__(self, arg: PositionalIndexer | tuple) -> DataFrame | Series: ... + +class GroupByNthSelector(Generic[_GroupByT]): + groupby_object: _GroupByT + + def __init__(self, groupby_object: _GroupByT) -> None: ... + def __call__( + self, + n: PositionalIndexer | tuple, + dropna: Literal["any", "all", None] = None, + ) -> DataFrame | Series: ... + def __getitem__(self, n: PositionalIndexer | tuple) -> DataFrame | Series: ... diff --git a/pandas-stubs/core/groupby/ops.pyi b/pandas-stubs/core/groupby/ops.pyi index 2f67fb38e..38cd81034 100644 --- a/pandas-stubs/core/groupby/ops.pyi +++ b/pandas-stubs/core/groupby/ops.pyi @@ -1,4 +1,13 @@ -from collections.abc import Sequence +from collections.abc import ( + Callable, + Hashable, + Iterator, + Sequence, +) +from typing import ( + Generic, + final, +) import numpy as np from pandas import ( @@ -8,91 +17,141 @@ from pandas import ( ) from pandas.core.groupby import grouper +from pandas._typing import ( + AnyArrayLike, + ArrayLike, + Axes, + AxisInt, + Incomplete, + NDFrameT, + Shape, + T, + npt, +) +from pandas.util._decorators import cache_readonly + +def check_result_array(obj, dtype) -> None: ... +def extract_result(res): ... + +class WrappedCythonOp: + cast_blocklist: frozenset[str] + kind: str + how: str + has_dropped_na: bool + + def __init__(self, kind: str, how: str, has_dropped_na: bool) -> None: ... + @classmethod + def get_kind_from_how(cls, how: str) -> str: ... + @final + def cython_operation( + self, + *, + values: ArrayLike, + axis: AxisInt, + min_count: int = -1, + comp_ids: np.ndarray, + ngroups: int, + **kwargs, + ) -> ArrayLike: ... + class BaseGrouper: - axis = ... - sort = ... - group_keys = ... - mutated = ... - indexer = ... + axis: Index + dropna: bool def __init__( self, axis: Index, groupings: Sequence[grouper.Grouping], - sort: bool = ..., - group_keys: bool = ..., - mutated: bool = ..., - indexer: np.ndarray | None = ..., + sort: bool = True, + dropna: bool = True, ) -> None: ... @property def groupings(self) -> list[grouper.Grouping]: ... @property - def shape(self): ... - def __iter__(self): ... + def shape(self) -> Shape: ... + def __iter__(self) -> Iterator: ... @property def nkeys(self) -> int: ... - def get_iterator(self, data: DataFrame | Series, axis: int = ...): ... - def apply(self, f, data: DataFrame | Series, axis: int = ...): ... - def indices(self): ... + def get_iterator( + self, data: NDFrameT, axis: AxisInt = 0 + ) -> Iterator[tuple[Hashable, NDFrameT]]: ... + @final + @cache_readonly + def group_keys_seq(self): ... + @cache_readonly + def indices(self) -> dict[Hashable, npt.NDArray[np.intp]]: ... + @final + def result_ilocs(self) -> npt.NDArray[np.intp]: ... + @final @property - def codes(self) -> list[np.ndarray]: ... + def codes(self) -> list[npt.NDArray[np.signedinteger]]: ... @property def levels(self) -> list[Index]: ... @property - def names(self): ... + def names(self) -> list: ... + @final def size(self) -> Series: ... - def groups(self): ... + @cache_readonly + def groups(self) -> dict[Hashable, np.ndarray]: ... + @final + @cache_readonly def is_monotonic(self) -> bool: ... - def group_info(self): ... - def codes_info(self) -> np.ndarray: ... + @final + @cache_readonly + def has_dropped_na(self) -> bool: ... + @cache_readonly + def group_info(self) -> tuple[npt.NDArray[np.intp], npt.NDArray[np.intp], int]: ... + @cache_readonly + def codes_info(self) -> npt.NDArray[np.intp]: ... + @final + @cache_readonly def ngroups(self) -> int: ... @property - def reconstructed_codes(self) -> list[np.ndarray]: ... + def reconstructed_codes(self) -> list[npt.NDArray[np.intp]]: ... + @cache_readonly def result_index(self) -> Index: ... - def get_group_levels(self): ... - def agg_series(self, obj: Series, func): ... + @final + def get_group_levels(self) -> list[ArrayLike]: ... + @final + def agg_series( + self, + obj: Series, + func: Callable[[Series], object], + preserve_dtype: bool = False, + ) -> ArrayLike: ... + @final + def apply_groupwise( + self, f: Callable[[NDFrameT], T], data: NDFrameT, axis: AxisInt = 0 + ) -> tuple[list[T], bool]: ... class BinGrouper(BaseGrouper): - bins = ... - binlabels = ... - mutated = ... - indexer = ... + bins: npt.NDArray[np.int64] + binlabels: Index + indexer: npt.NDArray[np.intp] def __init__( self, - bins, - binlabels, - filter_empty: bool = ..., - mutated: bool = ..., - indexer=..., + bins: ArrayLike | AnyArrayLike | Sequence[int], + binlabels: Axes, + indexer: npt.NDArray[np.intp] | None = None, ) -> None: ... - def groups(self): ... - @property - def nkeys(self) -> int: ... - def get_iterator(self, data: DataFrame | Series, axis: int = ...): ... - def indices(self): ... - def group_info(self): ... - @property - def reconstructed_codes(self) -> list[np.ndarray]: ... - def result_index(self): ... - @property - def levels(self): ... - @property - def names(self): ... - @property - def groupings(self) -> list[grouper.Grouping]: ... - def agg_series(self, obj: Series, func): ... + @cache_readonly + def indices(self) -> dict[Incomplete, list[int]]: ... # type: ignore[override] # pyright: ignore -class DataSplitter: - data = ... - labels = ... - ngroups = ... - axis = ... +class DataSplitter(Generic[NDFrameT]): + data: NDFrameT + labels: npt.NDArray[np.intp] + ngroups: int + axis: AxisInt def __init__( - self, data: DataFrame | Series, labels, ngroups: int, axis: int = ... + self, + data: NDFrameT, + labels: npt.NDArray[np.intp], + ngroups: int, + *, + sort_idx: npt.NDArray[np.intp], + sorted_ids: npt.NDArray[np.intp], + axis: AxisInt = 0, ) -> None: ... - def slabels(self): ... - def __iter__(self): ... - -class SeriesSplitter(DataSplitter): ... -class FrameSplitter(DataSplitter): ... + def __iter__(self) -> Iterator[NDFrameT]: ... -def get_splitter(data: DataFrame | Series, *args, **kwargs) -> DataSplitter: ... +class SeriesSplitter(DataSplitter[Series]): ... +class FrameSplitter(DataSplitter[DataFrame]): ... diff --git a/pandas-stubs/core/indexes/base.pyi b/pandas-stubs/core/indexes/base.pyi index e045d476a..bbf518881 100644 --- a/pandas-stubs/core/indexes/base.pyi +++ b/pandas-stubs/core/indexes/base.pyi @@ -13,6 +13,7 @@ from typing import ( Any, ClassVar, Literal, + final, overload, ) @@ -400,6 +401,7 @@ class Index(IndexOpsMixin[S1]): def set_value(self, arr, key, value) -> None: ... def get_indexer_non_unique(self, target): ... def get_indexer_for(self, target, **kwargs): ... + @final def groupby(self, values) -> dict[Hashable, np.ndarray]: ... def map(self, mapper, na_action=...) -> Index: ... def isin(self, values, level=...) -> np_ndarray_bool: ... diff --git a/pandas-stubs/core/resample.pyi b/pandas-stubs/core/resample.pyi index a21b7dfcf..d79e6f166 100644 --- a/pandas-stubs/core/resample.pyi +++ b/pandas-stubs/core/resample.pyi @@ -1,11 +1,9 @@ from collections.abc import ( Callable, - Generator, Hashable, Mapping, ) from typing import ( - Generic, Literal, overload, ) @@ -13,18 +11,39 @@ from typing import ( import numpy as np from pandas import ( DataFrame, + DatetimeIndex, Index, + PeriodIndex, Series, + Timedelta, + TimedeltaIndex, ) from pandas.core.groupby.generic import SeriesGroupBy -from pandas.core.groupby.groupby import BaseGroupBy -from typing_extensions import TypeAlias +from pandas.core.groupby.groupby import ( + BaseGroupBy, + GroupBy, +) +from pandas.core.groupby.grouper import Grouper +from pandas.core.groupby.ops import BinGrouper +from typing_extensions import ( + Self, + TypeAlias, +) +from pandas._libs.lib import NoDefault from pandas._typing import ( + S1, Axis, + FillnaOptions, + Frequency, + IndexLabel, InterpolateOptions, NDFrameT, Scalar, + TimedeltaConvertibleTypes, + TimeGrouperOrigin, + TimestampConvention, + TimestampConvertibleTypes, npt, ) @@ -51,138 +70,238 @@ _SeriesGroupByFuncArgs: TypeAlias = ( _SeriesGroupByFuncTypes | Mapping[Hashable, _SeriesGroupByFunc | str] ) -class Resampler(BaseGroupBy, Generic[NDFrameT]): +class Resampler(BaseGroupBy[NDFrameT]): + grouper: BinGrouper # pyright: ignore[reportIncompatibleVariableOverride] # variance incompatibility + binner: DatetimeIndex | TimedeltaIndex | PeriodIndex + exclusions: frozenset[Hashable] + ax: Index + def __init__( + self, + obj: NDFrameT, + timegrouper: TimeGrouper, + axis: Axis = 0, + kind: str | None = None, + *, + gpr_index: Index, + group_keys: bool = False, + selection: IndexLabel | None = None, + ) -> None: ... def __getattr__(self, attr: str) -> SeriesGroupBy: ... - def __iter__(self) -> Generator[tuple[Hashable, NDFrameT], None, None]: ... - @property - def obj(self) -> NDFrameT: ... - @property - def ax(self) -> Index: ... - @overload - def pipe( - self: Resampler[DataFrame], - func: Callable[..., DataFrame] - | tuple[Callable[..., DataFrame], str] - | Callable[..., Series] - | tuple[Callable[..., Series], str], - *args, - **kwargs, - ) -> DataFrame: ... - @overload - def pipe( - self: Resampler[DataFrame], - func: Callable[..., Scalar] | tuple[Callable[..., Scalar], str], - *args, - **kwargs, - ) -> Series: ... - @overload - def pipe( - self: Resampler[Series], - func: Callable[..., Series] | tuple[Callable[..., Series], str], - *args, - **kwargs, - ) -> Series: ... - @overload - def pipe( - self: Resampler[Series], - func: Callable[..., Scalar] | tuple[Callable[..., Scalar], str], - *args, - **kwargs, - ) -> Scalar: ... - @overload - def pipe( - self: Resampler[Series], - func: Callable[..., DataFrame] | tuple[Callable[..., DataFrame], str], - *args, - **kwargs, - ) -> DataFrame: ... @overload def aggregate( self: Resampler[DataFrame], - func: _FrameGroupByFuncArgs | None = ..., + func: _FrameGroupByFuncArgs | None = None, *args, **kwargs, - ) -> Series | DataFrame: ... + ) -> DataFrame: ... @overload def aggregate( self: Resampler[Series], - func: _SeriesGroupByFuncArgs | None = ..., + func: _SeriesGroupByFuncArgs | None = None, *args, **kwargs, ) -> Series | DataFrame: ... agg = aggregate apply = aggregate + @overload def transform( - self, arg: Callable[[Series], Series], *args, **kwargs - ) -> NDFrameT: ... - def ffill(self, limit: int | None = ...) -> NDFrameT: ... - def nearest(self, limit: int | None = ...) -> NDFrameT: ... - def bfill(self, limit: int | None = ...) -> NDFrameT: ... + self: Resampler[Series], arg: Callable[[Series], Series[S1]], *args, **kwargs + ) -> Series[S1]: ... + @overload + def transform( + self: Resampler[DataFrame], arg: Callable[[Series], Series[S1]], *args, **kwargs + ) -> DataFrame: ... + def ffill(self, limit: int | None = None) -> NDFrameT: ... + def nearest(self, limit: int | None = None) -> NDFrameT: ... + def bfill(self, limit: int | None = None) -> NDFrameT: ... def fillna( - self, - method: Literal["pad", "backfill", "ffill", "bfill", "nearest"], - limit: int | None = ..., + self, method: Literal[FillnaOptions, "nearest"], limit: int | None = None ) -> NDFrameT: ... @overload def interpolate( self, - method: InterpolateOptions = ..., + method: InterpolateOptions = "linear", *, - axis: Axis = ..., - limit: int | None = ..., + axis: Axis = 0, + limit: int | None = None, inplace: Literal[True], - limit_direction: Literal["forward", "backward", "both"] = ..., - limit_area: Literal["inside", "outside"] | None = ..., - downcast: Literal["infer"] | None = ..., + limit_direction: Literal["forward", "backward", "both"] = "forward", + limit_area: Literal["inside", "outside"] | None = None, + downcast: Literal["infer"] | None | NoDefault = ..., **kwargs, ) -> None: ... @overload def interpolate( self, - method: InterpolateOptions = ..., + method: InterpolateOptions = "linear", *, - axis: Axis = ..., - limit: int | None = ..., - inplace: Literal[False] = ..., - limit_direction: Literal["forward", "backward", "both"] = ..., - limit_area: Literal["inside", "outside"] | None = ..., - downcast: Literal["infer"] | None = ..., - **kwargs, - ) -> NDFrameT: ... - def asfreq(self, fill_value: Scalar | None = ...) -> NDFrameT: ... - def std( - self, ddof: int = ..., numeric_only: bool = ..., *args, **kwargs - ) -> NDFrameT: ... - def var( - self, ddof: int = ..., numeric_only: bool = ..., *args, **kwargs - ) -> NDFrameT: ... - def size(self) -> Series: ... - def count(self) -> NDFrameT: ... - def quantile( - self, - q: float | list[float] | npt.NDArray[np.float_] | Series[float] = ..., + axis: Axis = 0, + limit: int | None = None, + inplace: Literal[False] = False, + limit_direction: Literal["forward", "backward", "both"] = "forward", + limit_area: Literal["inside", "outside"] | None = None, + downcast: Literal["infer"] | None | NoDefault = ..., **kwargs, ) -> NDFrameT: ... + def asfreq(self, fill_value: Scalar | None = None) -> NDFrameT: ... def sum( - self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs + self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs ) -> NDFrameT: ... def prod( - self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs + self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs ) -> NDFrameT: ... def min( - self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs + self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs ) -> NDFrameT: ... def max( - self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs + self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs ) -> NDFrameT: ... def first( - self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs + self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs ) -> NDFrameT: ... def last( - self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs + self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs + ) -> NDFrameT: ... + def median(self, numeric_only: bool = False, *args, **kwargs) -> NDFrameT: ... + def mean(self, numeric_only: bool = False, *args, **kwargs) -> NDFrameT: ... + def std( + self, ddof: int = 1, numeric_only: bool = False, *args, **kwargs + ) -> NDFrameT: ... + def var( + self, ddof: int = 1, numeric_only: bool = False, *args, **kwargs + ) -> NDFrameT: ... + def sem( + self, ddof: int = 1, numeric_only: bool = False, *args, **kwargs ) -> NDFrameT: ... - def mean(self, numeric_only: bool = ..., *args, **kwargs) -> NDFrameT: ... - def sem(self, numeric_only: bool = ..., *args, **kwargs) -> NDFrameT: ... - def median(self, numeric_only: bool = ..., *args, **kwargs) -> NDFrameT: ... def ohlc(self, *args, **kwargs) -> DataFrame: ... - def nunique(self, *args, **kwargs) -> NDFrameT: ... + @overload + def nunique(self: Resampler[Series], *args, **kwargs) -> Series[int]: ... + @overload + def nunique(self: Resampler[DataFrame], *args, **kwargs) -> DataFrame: ... + def size(self) -> Series[int]: ... + @overload + def count(self: Resampler[Series]) -> Series[int]: ... + @overload + def count(self: Resampler[DataFrame]) -> DataFrame: ... + def quantile( + self, + q: float | list[float] | npt.NDArray[np.float_] | Series[float] = 0.5, + **kwargs, + ) -> NDFrameT: ... + +# We lie about inheriting from Resampler because at runtime inherits all Resampler +# attributes via setattr +class _GroupByMixin(Resampler[NDFrameT]): + k: str | list[str] | None + def __init__( + self, + *, + parent: Resampler, + groupby: GroupBy, + key=None, + selection: IndexLabel | None = None, + ) -> None: ... + def __getitem__(self, key) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + +class DatetimeIndexResampler(Resampler[NDFrameT]): ... + +class DatetimeIndexResamplerGroupby( + _GroupByMixin[NDFrameT], DatetimeIndexResampler[NDFrameT] +): + def __getattr__(self, attr: str) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + +class PeriodIndexResampler(DatetimeIndexResampler[NDFrameT]): ... + +class PeriodIndexResamplerGroupby( + _GroupByMixin[NDFrameT], PeriodIndexResampler[NDFrameT] +): + def __getattr__(self, attr: str) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + +class TimedeltaIndexResampler(DatetimeIndexResampler[NDFrameT]): ... + +class TimedeltaIndexResamplerGroupby( + _GroupByMixin[NDFrameT], TimedeltaIndexResampler[NDFrameT] +): + def __getattr__(self, attr: str) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] + +_ResamplerGroupBy: TypeAlias = ( + DatetimeIndexResamplerGroupby[NDFrameT] + | PeriodIndexResamplerGroupby[NDFrameT] + | TimedeltaIndexResamplerGroupby[NDFrameT] +) + +def get_resampler( + obj: NDFrameT, + kind: Literal["period", "timestamp", "timedelta"] | None = None, + *, + # Keyword argumentsmust be kept roughly inline with TimeGrouper.__init__ below + freq: Frequency = "Min", + closed: Literal["left", "right"] | None = None, + label: Literal["left", "right"] | None = None, + how: str = "mean", + axis: Axis = 0, + fill_method: str | None = None, + limit: int | None = None, + convention: TimestampConvention | None = None, + origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", + offset: TimedeltaConvertibleTypes | None = None, + group_keys: bool = False, + **kwds, +) -> DatetimeIndexResampler[NDFrameT]: ... +def get_resampler_for_grouping( + groupby: GroupBy[NDFrameT], + rule: Frequency, + how: str | None = None, + fill_method: str | None = None, + limit: int | None = None, + kind: Literal["period", "timestamp", "timedelta"] | None = None, + on: Hashable | None = None, + *, + # Keyword argumentsmust be kept roughly inline with TimeGrouper.__init__ below + closed: Literal["left", "right"] | None = None, + label: Literal["left", "right"] | None = None, + axis: Axis = 0, + convention: TimestampConvention | None = None, + origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", + offset: TimedeltaConvertibleTypes | None = None, + group_keys: bool = False, + **kwargs, +) -> _ResamplerGroupBy[NDFrameT]: ... + +class TimeGrouper(Grouper): + closed: Literal["left", "right"] + label: Literal["left", "right"] + kind: str | None + convention: TimestampConvention + how: str + fill_method: str | None + limit: int | None + group_keys: bool + origin: TimeGrouperOrigin + offset: Timedelta | None + + def __init__( + self, + freq: Frequency = "Min", + closed: Literal["left", "right"] | None = None, + label: Literal["left", "right"] | None = None, + how: str = "mean", + axis: Axis = 0, + fill_method: str | None = None, + limit: int | None = None, + kind: Literal["period", "timestamp", "timedelta"] | None = None, + convention: TimestampConvention | None = None, + origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", + offset: TimedeltaConvertibleTypes | None = None, + group_keys: bool = False, + **kwargs, + ) -> None: ... + +def asfreq( + obj: NDFrameT, + freq: Frequency, + method: Literal[FillnaOptions, "nearest"] | None = None, + how: str | None = None, + normalize: bool = False, + fill_value: Scalar | None = None, +) -> NDFrameT: ... diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 3f16abefa..26b952a0e 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -45,6 +45,7 @@ from pandas.core.base import IndexOpsMixin from pandas.core.frame import DataFrame from pandas.core.generic import NDFrame from pandas.core.groupby.generic import SeriesGroupBy +from pandas.core.groupby.groupby import BaseGroupBy from pandas.core.indexers import BaseIndexer from pandas.core.indexes.accessors import ( CombinedDatetimelikeProperties, @@ -66,7 +67,6 @@ from pandas.core.indexing import ( _IndexSliceTuple, _LocIndexer, ) -from pandas.core.resample import Resampler from pandas.core.strings import StringMethods from pandas.core.window import ( Expanding, @@ -87,6 +87,7 @@ from pandas._libs.interval import ( Interval, _OrderableT, ) +from pandas._libs.lib import NoDefault from pandas._libs.missing import NAType from pandas._libs.tslibs import BaseOffset from pandas._typing import ( @@ -307,7 +308,7 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def __new__( cls, - data: Scalar | _ListLike | dict[HashableT1, Any] | None = ..., + data: Scalar | _ListLike | dict[HashableT1, Any] | BaseGroupBy | None = ..., index: Axes | None = ..., *, dtype: Dtype = ..., @@ -555,8 +556,7 @@ class Series(IndexOpsMixin[S1], NDFrame): as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> SeriesGroupBy[S1, Scalar]: ... @overload @@ -568,8 +568,7 @@ class Series(IndexOpsMixin[S1], NDFrame): as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> SeriesGroupBy[S1, Timestamp]: ... @overload @@ -581,8 +580,7 @@ class Series(IndexOpsMixin[S1], NDFrame): as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> SeriesGroupBy[S1, Timedelta]: ... @overload @@ -594,8 +592,7 @@ class Series(IndexOpsMixin[S1], NDFrame): as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> SeriesGroupBy[S1, Period]: ... @overload @@ -607,24 +604,47 @@ class Series(IndexOpsMixin[S1], NDFrame): as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> SeriesGroupBy[S1, IntervalT]: ... @overload def groupby( self, - by: MultiIndex | GroupByObjectNonScalar = ..., + by: MultiIndex | GroupByObjectNonScalar, axis: AxisIndex = ..., level: IndexLabel | None = ..., as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> SeriesGroupBy[S1, tuple]: ... @overload + def groupby( + self, + by: None, + axis: AxisIndex, + level: IndexLabel, # level is required when by=None (passed as positional) + as_index: _bool = ..., + sort: _bool = ..., + group_keys: _bool = ..., + observed: _bool | NoDefault = ..., + dropna: _bool = ..., + ) -> SeriesGroupBy[S1, Scalar]: ... + @overload + def groupby( + self, + by: None = None, + axis: AxisIndex = ..., + *, + level: IndexLabel, # level is required when by=None (passed as keyword) + as_index: _bool = ..., + sort: _bool = ..., + group_keys: _bool = ..., + observed: _bool | NoDefault = ..., + dropna: _bool = ..., + ) -> SeriesGroupBy[S1, Scalar]: ... + @overload def groupby( self, by: Series[SeriesByT], @@ -633,8 +653,7 @@ class Series(IndexOpsMixin[S1], NDFrame): as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> SeriesGroupBy[S1, SeriesByT]: ... @overload @@ -646,8 +665,7 @@ class Series(IndexOpsMixin[S1], NDFrame): as_index: _bool = ..., sort: _bool = ..., group_keys: _bool = ..., - squeeze: _bool = ..., - observed: _bool = ..., + observed: _bool | NoDefault = ..., dropna: _bool = ..., ) -> SeriesGroupBy[S1, Any]: ... # need the ignore because None is Hashable @@ -1343,23 +1361,6 @@ class Series(IndexOpsMixin[S1], NDFrame): end_time: _str | time, axis: AxisIndex | None = ..., ) -> Series[S1]: ... - def resample( - self, - rule, - axis: AxisIndex = ..., - closed: _str | None = ..., - label: _str | None = ..., - convention: TimestampConvention = ..., - kind: Literal["timestamp", "period"] | None = ..., - loffset=..., - base: int = ..., - on: _str | None = ..., - level: Level | None = ..., - origin: datetime - | Timestamp - | Literal["epoch", "start", "start_day", "end", "end_day"] = ..., - offset: timedelta | Timedelta | _str | None = ..., - ) -> Resampler[Series]: ... def first(self, offset) -> Series[S1]: ... def last(self, offset) -> Series[S1]: ... def rank( diff --git a/pandas-stubs/core/window/__init__.pyi b/pandas-stubs/core/window/__init__.pyi index b9504df8d..6a16d7b83 100644 --- a/pandas-stubs/core/window/__init__.pyi +++ b/pandas-stubs/core/window/__init__.pyi @@ -1,4 +1,7 @@ -from pandas.core.window.ewm import ExponentialMovingWindow as ExponentialMovingWindow +from pandas.core.window.ewm import ( + ExponentialMovingWindow as ExponentialMovingWindow, + ExponentialMovingWindowGroupby as ExponentialMovingWindowGroupby, +) from pandas.core.window.expanding import ( Expanding as Expanding, ExpandingGroupby as ExpandingGroupby, @@ -8,3 +11,13 @@ from pandas.core.window.rolling import ( RollingGroupby as RollingGroupby, Window as Window, ) + +__all__ = [ + "Expanding", + "ExpandingGroupby", + "ExponentialMovingWindow", + "ExponentialMovingWindowGroupby", + "Rolling", + "RollingGroupby", + "Window", +] diff --git a/pandas-stubs/core/window/ewm.pyi b/pandas-stubs/core/window/ewm.pyi index 548464021..b2cff4b89 100644 --- a/pandas-stubs/core/window/ewm.pyi +++ b/pandas-stubs/core/window/ewm.pyi @@ -1,62 +1,113 @@ -from typing import Generic - import numpy as np from pandas import ( DataFrame, Series, ) -from pandas.core.window.rolling import BaseWindow +from pandas.core.window.rolling import ( + BaseWindow, + BaseWindowGroupby, +) from pandas._typing import ( Axis, CalculationMethod, + IndexLabel, NDFrameT, TimedeltaConvertibleTypes, WindowingEngine, WindowingEngineKwargs, ) -class ExponentialMovingWindow(BaseWindow[NDFrameT], Generic[NDFrameT]): +class ExponentialMovingWindow(BaseWindow[NDFrameT]): def __init__( self, obj: NDFrameT, - com: float | None = ..., - span: float | None = ..., - halflife: TimedeltaConvertibleTypes | None = ..., - alpha: float | None = ..., - min_periods: int | None = ..., - adjust: bool = ..., - ignore_na: bool = ..., - axis: Axis = ..., - times: str | np.ndarray | Series | None | np.timedelta64 = ..., - method: CalculationMethod = ..., + com: float | None = None, + span: float | None = None, + halflife: TimedeltaConvertibleTypes | None = None, + alpha: float | None = None, + min_periods: int | None = 0, + adjust: bool = True, + ignore_na: bool = False, + axis: Axis = 0, + times: str | np.ndarray | Series | np.timedelta64 | None = None, + method: CalculationMethod = "single", + *, + selection: IndexLabel | None = None, ) -> None: ... + def online( + self, + engine: WindowingEngine = "numba", + engine_kwargs: WindowingEngineKwargs = None, + ) -> OnlineExponentialMovingWindow[NDFrameT]: ... def mean( self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, ) -> NDFrameT: ... def sum( self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, ) -> NDFrameT: ... - def std(self, bias: bool = ..., numeric_only: bool = ...) -> NDFrameT: ... - def var(self, bias: bool = ..., numeric_only: bool = ...) -> NDFrameT: ... + def std(self, bias: bool = False, numeric_only: bool = False) -> NDFrameT: ... + def var(self, bias: bool = False, numeric_only: bool = False) -> NDFrameT: ... def cov( self, - other: DataFrame | Series | None = ..., - pairwise: bool | None = ..., - bias: bool = ..., - numeric_only: bool = ..., + other: DataFrame | Series | None = None, + pairwise: bool | None = None, + bias: bool = False, + numeric_only: bool = False, ) -> NDFrameT: ... def corr( self, - other: DataFrame | Series | None = ..., - pairwise: bool | None = ..., - numeric_only: bool = ..., + other: DataFrame | Series | None = None, + pairwise: bool | None = None, + numeric_only: bool = False, + ) -> NDFrameT: ... + +class ExponentialMovingWindowGroupby( + BaseWindowGroupby[NDFrameT], ExponentialMovingWindow[NDFrameT] +): + def __init__(self, obj, *args, _grouper=None, **kwargs) -> None: ... + +class OnlineExponentialMovingWindow(ExponentialMovingWindow[NDFrameT]): + def __init__( + self, + obj: NDFrameT, + com: float | None = None, + span: float | None = None, + halflife: float | TimedeltaConvertibleTypes | None = None, + alpha: float | None = None, + min_periods: int | None = 0, + adjust: bool = True, + ignore_na: bool = False, + axis: Axis = 0, + times: np.ndarray | NDFrameT | None = None, + engine: WindowingEngine = "numba", + engine_kwargs: WindowingEngineKwargs = None, + *, + selection: IndexLabel | None = None, + ) -> None: ... + def reset(self) -> None: ... + def aggregate(self, func, *args, **kwargs): ... + def std(self, bias: bool = False, *args, **kwargs): ... + def corr( + self, + other: DataFrame | Series | None = None, + pairwise: bool | None = None, + numeric_only: bool = False, + ): ... + def cov( + self, + other: DataFrame | Series | None = None, + pairwise: bool | None = None, + bias: bool = False, + numeric_only: bool = False, + ): ... + def var(self, bias: bool = False, numeric_only: bool = False): ... + def mean( + self, *args, update: NDFrameT | None = None, update_times: None = None, **kwargs ) -> NDFrameT: ... diff --git a/pandas-stubs/core/window/expanding.pyi b/pandas-stubs/core/window/expanding.pyi index 9ac04cf4e..a8777a076 100644 --- a/pandas-stubs/core/window/expanding.pyi +++ b/pandas-stubs/core/window/expanding.pyi @@ -1,119 +1,22 @@ -from collections.abc import Callable -from typing import Any - -from pandas import ( - DataFrame, - Series, -) from pandas.core.window.rolling import ( BaseWindowGroupby, RollingAndExpandingMixin, ) from pandas._typing import ( + Axis, + IndexLabel, NDFrameT, - QuantileInterpolation, - WindowingEngine, - WindowingEngineKwargs, - WindowingRankType, ) class Expanding(RollingAndExpandingMixin[NDFrameT]): - def count(self) -> NDFrameT: ... - def apply( - self, - func: Callable[..., Any], - raw: bool = ..., - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - args: tuple[Any, ...] | None = ..., - kwargs: dict[str, Any] | None = ..., - ) -> NDFrameT: ... - def sum( - self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - ) -> NDFrameT: ... - def max( - self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - ) -> NDFrameT: ... - def min( - self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - ) -> NDFrameT: ... - def mean( - self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - ) -> NDFrameT: ... - def median( - self, - numeric_only: bool = ..., - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - ) -> NDFrameT: ... - def std( - self, - ddof: int = ..., - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - ) -> NDFrameT: ... - def var( - self, - ddof: int = ..., - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - ) -> NDFrameT: ... - def sem(self, ddof: int = ..., numeric_only: bool = ...) -> NDFrameT: ... - def skew( - self, - numeric_only: bool = ..., - ) -> NDFrameT: ... - def kurt( - self, - numeric_only: bool = ..., - ) -> NDFrameT: ... - def quantile( - self, - quantile: float, - interpolation: QuantileInterpolation = ..., - numeric_only: bool = ..., - ) -> NDFrameT: ... - def rank( - self, - method: WindowingRankType = ..., - ascending: bool = ..., - pct: bool = ..., - numeric_only: bool = ..., - ) -> NDFrameT: ... - def cov( - self, - other: DataFrame | Series | None = ..., - pairwise: bool | None = ..., - ddof: int = ..., - numeric_only: bool = ..., - ) -> NDFrameT: ... - def corr( - self, - other: DataFrame | Series | None = ..., - pairwise: bool | None = ..., - ddof: int = ..., - numeric_only: bool = ..., - ) -> NDFrameT: ... + def __init__( + self, + obj: NDFrameT, + min_periods: int = 1, + axis: Axis = 0, + method: str = "single", + selection: IndexLabel | None = None, + ) -> None: ... -class ExpandingGroupby(BaseWindowGroupby, Expanding): ... +class ExpandingGroupby(BaseWindowGroupby[NDFrameT], Expanding[NDFrameT]): ... diff --git a/pandas-stubs/core/window/rolling.pyi b/pandas-stubs/core/window/rolling.pyi index d1d3b675b..34c1e11e6 100644 --- a/pandas-stubs/core/window/rolling.pyi +++ b/pandas-stubs/core/window/rolling.pyi @@ -1,20 +1,33 @@ -from collections.abc import Callable +from collections.abc import ( + Callable, + Iterator, +) +import datetime as dt from typing import ( Any, - Generic, overload, ) from pandas import ( DataFrame, + Index, Series, ) from pandas.core.base import SelectionMixin +from pandas.core.groupby.ops import BaseGrouper +from pandas.core.indexers import BaseIndexer +from typing_extensions import Self +from pandas._libs.tslibs import BaseOffset from pandas._typing import ( AggFuncTypeBase, AggFuncTypeFrame, AggFuncTypeSeriesToFrame, + Axis, + AxisInt, + CalculationMethod, + IndexLabel, + IntervalClosedType, NDFrameT, QuantileInterpolation, WindowingEngine, @@ -22,9 +35,35 @@ from pandas._typing import ( WindowingRankType, ) -class BaseWindow(SelectionMixin[NDFrameT], Generic[NDFrameT]): - def __getattr__(self, attr: str): ... - def __iter__(self): ... +class BaseWindow(SelectionMixin[NDFrameT]): + on: str | Index | None + closed: IntervalClosedType | None + step: int | None + window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None + min_periods: int | None + center: bool | None + win_type: str | None + axis: AxisInt + method: CalculationMethod + + def __init__( + self, + obj: NDFrameT, + window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = None, + min_periods: int | None = None, + center: bool | None = False, + win_type: str | None = None, + axis: Axis = 0, + on: str | Index | None = None, + closed: IntervalClosedType | None = None, + step: int | None = None, + method: CalculationMethod = "single", + *, + selection: IndexLabel | None = None, + ) -> None: ... + def __getitem__(self, key) -> Self: ... + def __getattr__(self, attr: str) -> Self: ... + def __iter__(self) -> Iterator[NDFrameT]: ... @overload def aggregate( self: BaseWindow[Series], func: AggFuncTypeBase, *args: Any, **kwargs: Any @@ -45,123 +84,120 @@ class BaseWindow(SelectionMixin[NDFrameT], Generic[NDFrameT]): ) -> DataFrame: ... agg = aggregate -class BaseWindowGroupby(BaseWindow[NDFrameT]): ... +class BaseWindowGroupby(BaseWindow[NDFrameT]): + def __init__( + self, + obj: NDFrameT, + window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = None, + min_periods: int | None = None, + center: bool | None = False, + win_type: str | None = None, + axis: Axis = 0, + on: str | Index | None = None, + closed: IntervalClosedType | None = None, + step: int | None = None, + method: CalculationMethod = "single", + *, + selection: IndexLabel | None = None, + _grouper: BaseGrouper, + _as_index: bool = True, + ) -> None: ... class Window(BaseWindow[NDFrameT]): - def sum(self, numeric_only: bool = ..., **kwargs: Any) -> NDFrameT: ... - def mean(self, numeric_only: bool = ..., **kwargs: Any) -> NDFrameT: ... + def sum(self, numeric_only: bool = False, **kwargs: Any) -> NDFrameT: ... + def mean(self, numeric_only: bool = False, **kwargs: Any) -> NDFrameT: ... def var( - self, ddof: int = ..., numeric_only: bool = ..., *args: Any, **kwargs: Any + self, ddof: int = 1, numeric_only: bool = False, **kwargs: Any ) -> NDFrameT: ... def std( - self, ddof: int = ..., numeric_only: bool = ..., *args: Any, **kwargs: Any + self, ddof: int = 1, numeric_only: bool = False, **kwargs: Any ) -> NDFrameT: ... -class RollingAndExpandingMixin(BaseWindow[NDFrameT], Generic[NDFrameT]): - def count(self) -> NDFrameT: ... +class RollingAndExpandingMixin(BaseWindow[NDFrameT]): + def count(self, numeric_only: bool = False) -> NDFrameT: ... def apply( self, func: Callable[..., Any], - raw: bool = ..., - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - args: tuple[Any, ...] | None = ..., - kwargs: dict[str, Any] | None = ..., + raw: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + args: tuple[Any, ...] | None = None, + kwargs: dict[str, Any] | None = None, ) -> NDFrameT: ... def sum( self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, ) -> NDFrameT: ... def max( self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, ) -> NDFrameT: ... def min( self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, ) -> NDFrameT: ... def mean( self, - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, ) -> NDFrameT: ... def median( self, - numeric_only: bool = ..., - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, ) -> NDFrameT: ... def std( self, - ddof: int = ..., - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., + ddof: int = 1, + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, ) -> NDFrameT: ... def var( self, - ddof: int = ..., - numeric_only: bool = ..., - *, - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - ) -> NDFrameT: ... - def skew(self, numeric_only: bool = ...) -> NDFrameT: ... - def sem( - self, - ddof: int = ..., - numeric_only: bool = ..., - ) -> NDFrameT: ... - def kurt(self, numeric_only: bool = ...) -> NDFrameT: ... + ddof: int = 1, + numeric_only: bool = False, + engine: WindowingEngine = None, + engine_kwargs: WindowingEngineKwargs = None, + ) -> NDFrameT: ... + def skew(self, numeric_only: bool = False) -> NDFrameT: ... + def sem(self, ddof: int = 1, numeric_only: bool = False) -> NDFrameT: ... + def kurt(self, numeric_only: bool = False) -> NDFrameT: ... def quantile( self, - quantile: float, - interpolation: QuantileInterpolation = ..., - numeric_only: bool = ..., + q: float, + interpolation: QuantileInterpolation = "linear", + numeric_only: bool = False, ) -> NDFrameT: ... def rank( self, - method: WindowingRankType = ..., - ascending: bool = ..., - pct: bool = ..., - numeric_only: bool = ..., + method: WindowingRankType = "average", + ascending: bool = True, + pct: bool = False, + numeric_only: bool = False, ) -> NDFrameT: ... def cov( self, - other: DataFrame | Series | None = ..., - pairwise: bool | None = ..., - ddof: int = ..., - numeric_only: bool = ..., + other: DataFrame | Series | None = None, + pairwise: bool | None = None, + ddof: int = 1, + numeric_only: bool = False, ) -> NDFrameT: ... def corr( self, - other: DataFrame | Series | None = ..., - pairwise: bool | None = ..., - ddof: int = ..., - numeric_only: bool = ..., - ) -> NDFrameT: ... - -class Rolling(RollingAndExpandingMixin[NDFrameT]): - def apply( - self, - func: Callable[..., Any], - raw: bool = ..., - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs | None = ..., - args: tuple[Any, ...] | None = ..., - kwargs: dict[str, Any] | None = ..., + other: DataFrame | Series | None = None, + pairwise: bool | None = None, + ddof: int = 1, + numeric_only: bool = False, ) -> NDFrameT: ... -class RollingGroupby(BaseWindowGroupby[NDFrameT], Rolling): ... +class Rolling(RollingAndExpandingMixin[NDFrameT]): ... +class RollingGroupby(BaseWindowGroupby[NDFrameT], Rolling[NDFrameT]): ... diff --git a/pandas-stubs/plotting/__init__.pyi b/pandas-stubs/plotting/__init__.pyi index 6fd96626e..02e613ed8 100644 --- a/pandas-stubs/plotting/__init__.pyi +++ b/pandas-stubs/plotting/__init__.pyi @@ -1,6 +1,7 @@ from pandas.plotting._core import ( PlotAccessor as PlotAccessor, boxplot as boxplot, + boxplot_frame_groupby as boxplot_frame_groupby, ) from pandas.plotting._misc import ( andrews_curves as andrews_curves, diff --git a/pandas-stubs/plotting/_core.pyi b/pandas-stubs/plotting/_core.pyi index b51c0fd3c..7fb300cb5 100644 --- a/pandas-stubs/plotting/_core.pyi +++ b/pandas-stubs/plotting/_core.pyi @@ -27,6 +27,7 @@ from pandas._typing import ( HashableT1, HashableT2, HashableT3, + IndexLabel, npt, ) @@ -83,6 +84,54 @@ def boxplot( return_type: Literal["both"], **kwargs, ) -> _BoxPlotT: ... +@overload +def boxplot_frame_groupby( + grouped, + subplots: Literal[True] = True, + column: IndexLabel | None = None, + fontsize: float | str | None = None, + rot: float = 0, + grid: bool = True, + ax: Axes | None = None, + figsize: tuple[float, float] | None = None, + layout: tuple[int, int] | None = None, + sharex: bool = False, + sharey: bool = True, + backend: str | None = None, + **kwargs, +) -> Series: ... # Series[Axes] but this is not allowed +@overload +def boxplot_frame_groupby( + grouped, + subplots: Literal[False], + column: IndexLabel | None = None, + fontsize: float | str | None = None, + rot: float = 0, + grid: bool = True, + ax: Axes | None = None, + figsize: tuple[float, float] | None = None, + layout: tuple[int, int] | None = None, + sharex: bool = False, + sharey: bool = True, + backend: str | None = None, + **kwargs, +) -> Axes: ... +@overload +def boxplot_frame_groupby( + grouped, + subplots: bool, + column: IndexLabel | None = None, + fontsize: float | str | None = None, + rot: float = 0, + grid: bool = True, + ax: Axes | None = None, + figsize: tuple[float, float] | None = None, + layout: tuple[int, int] | None = None, + sharex: bool = False, + sharey: bool = True, + backend: str | None = None, + **kwargs, +) -> Axes | Series: ... # Series[Axes] class PlotAccessor: def __init__(self, data) -> None: ... diff --git a/pandas-stubs/util/_decorators.pyi b/pandas-stubs/util/_decorators.pyi index f6f50ee41..e06f16afc 100644 --- a/pandas-stubs/util/_decorators.pyi +++ b/pandas-stubs/util/_decorators.pyi @@ -4,22 +4,59 @@ from collections.abc import ( ) from typing import Any +from pandas._libs.properties import cache_readonly as cache_readonly +from pandas._typing import ( + F, + T, +) + +__all__ = [ + "Appender", + "cache_readonly", + "deprecate", + "deprecate_kwarg", + "deprecate_nonkeyword_arguments", + "doc", + "future_version_msg", + "Substitution", +] + def deprecate( name: str, alternative: Callable[..., Any], version: str, - alt_name: str | None = ..., - klass: type[Warning] | None = ..., - stacklevel: int = ..., - msg: str | None = ..., -) -> Callable[..., Any]: ... + alt_name: str | None = None, + klass: type[Warning] | None = None, + stacklevel: int = 2, + msg: str | None = None, +) -> Callable[[F], F]: ... def deprecate_kwarg( old_arg_name: str, new_arg_name: str | None, - mapping: Mapping[Any, Any] | Callable[[Any], Any] | None = ..., - stacklevel: int = ..., -) -> Callable[..., Any]: ... -def rewrite_axis_style_signature( - name: str, extra_params: list[tuple[str, Any]] -) -> Callable[..., Any]: ... + mapping: Mapping[Any, Any] | Callable[[Any], Any] | None = None, + stacklevel: int = 2, +) -> Callable[[F], F]: ... +def future_version_msg(version: str | None) -> str: ... +def deprecate_nonkeyword_arguments( + version: str | None, + allowed_args: list[str] | None = None, + name: str | None = None, +) -> Callable[[F], F]: ... +def doc(*docstrings: str | Callable | None, **params) -> Callable[[F], F]: ... + +class Substitution: + params: Any + def __init__(self, *args, **kwargs) -> None: ... + def __call__(self, func: F) -> F: ... + def update(self, *args, **kwargs) -> None: ... + +class Appender: + addendum: str | None + join: str + + def __init__( + self, addendum: str | None, join: str = "", indents: int = 0 + ) -> None: ... + def __call__(self, func: T) -> T: ... + def indent(text: str | None, indents: int = ...) -> str: ... diff --git a/tests/__init__.py b/tests/__init__.py index 847f7f52a..166b5a3e5 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -13,6 +13,7 @@ ) import pandas as pd +from pandas.core.groupby.groupby import BaseGroupBy from pandas.util.version import Version import pytest @@ -33,6 +34,8 @@ def check(actual: T, klass: type, dtype: type | None = None, attr: str = "left") value = actual.iloc[0] elif isinstance(actual, pd.Index): value = actual[0] # type: ignore[assignment] + elif isinstance(actual, BaseGroupBy): + value = actual.obj elif hasattr(actual, "__iter__"): value = next(iter(actual)) # pyright: ignore[reportGeneralTypeIssues] else: diff --git a/tests/test_frame.py b/tests/test_frame.py index 8056e2835..78c0ae550 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -30,7 +30,10 @@ import numpy.typing as npt import pandas as pd from pandas._testing import ensure_clean -from pandas.core.resample import Resampler # noqa: F401 +from pandas.core.resample import ( + DatetimeIndexResampler, + Resampler, +) from pandas.core.series import Series import pytest from typing_extensions import ( @@ -1420,8 +1423,9 @@ def test_types_from_dict() -> None: def test_pipe() -> None: - def foo(df: pd.DataFrame) -> pd.DataFrame: - return pd.DataFrame(df) + def resampler_foo(resampler: Resampler[pd.DataFrame]) -> pd.DataFrame: + assert isinstance(resampler, Resampler) + return pd.DataFrame(resampler) with pytest_warns_bounded(FutureWarning, "'M' is deprecated", lower="2.1.99"): val = ( @@ -1433,9 +1437,12 @@ def foo(df: pd.DataFrame) -> pd.DataFrame: ) .assign(week_starting=pd.date_range("01/01/2018", periods=8, freq="W")) .resample("M", on="week_starting") - .pipe(foo) + .pipe(resampler_foo) ) + def foo(df: pd.DataFrame) -> pd.DataFrame: + return pd.DataFrame(df) + df = pd.DataFrame({"a": [1], "b": [2]}) check(assert_type(val, pd.DataFrame), pd.DataFrame) @@ -2685,12 +2692,13 @@ def test_resample_150_changes() -> None: frame = pd.DataFrame(np.random.standard_normal((700, 1)), index=idx, columns=["a"]) with pytest_warns_bounded(FutureWarning, "'M' is deprecated", lower="2.1.99"): resampler = frame.resample("M", group_keys=True) - assert_type(resampler, "Resampler[pd.DataFrame]") + assert_type(resampler, "DatetimeIndexResampler[pd.DataFrame]") + assert isinstance(resampler, DatetimeIndexResampler) def f(s: pd.DataFrame) -> pd.Series: return s.mean() - check(assert_type(resampler.apply(f), Union[pd.Series, pd.DataFrame]), pd.DataFrame) + check(assert_type(resampler.apply(f), pd.DataFrame), pd.DataFrame) def test_df_accepting_dicts_iterator() -> None: diff --git a/tests/test_groupby.py b/tests/test_groupby.py new file mode 100644 index 000000000..916b93330 --- /dev/null +++ b/tests/test_groupby.py @@ -0,0 +1,947 @@ +from __future__ import annotations + +from collections.abc import Iterator +from typing import ( + TYPE_CHECKING, + Literal, + Union, + cast, +) + +import numpy as np +from pandas import ( + DataFrame, + DatetimeIndex, + Index, + Series, + date_range, +) +from pandas.core.groupby.generic import SeriesGroupBy +from pandas.core.resample import ( + DatetimeIndexResamplerGroupby, + Resampler, +) +from pandas.core.window import ( + ExpandingGroupby, + ExponentialMovingWindowGroupby, + RollingGroupby, +) +from typing_extensions import assert_type + +from tests import ( + PD_LTE_21, + check, + pytest_warns_bounded, +) + +if TYPE_CHECKING: + from pandas.core.resample import _ResamplerGroupBy # noqa: F401 + +DR = date_range("1999-1-1", periods=365, freq="D") +DF_ = DataFrame(np.random.standard_normal((365, 1)), index=DR) +BY = Series(np.random.choice([1, 2], 365), index=DR) +S = DF_.iloc[:, 0] +DF = DataFrame({"col1": S, "col2": S, "col3": BY}) +GB_DF = DF.groupby("col3") +GB_S = cast("SeriesGroupBy[float, int]", GB_DF.col1) + +M = "M" if PD_LTE_21 else "ME" + + +def test_frame_groupby_resample() -> None: + # basic + check( + assert_type(GB_DF.resample(M), "_ResamplerGroupBy[DataFrame]"), + DatetimeIndexResamplerGroupby, + DataFrame, + ) + + # props + check(assert_type(GB_DF.resample(M).obj, DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).ax, Index), DatetimeIndex) + + # agg funcs + check(assert_type(GB_DF.resample(M).sum(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).prod(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).min(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).max(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).first(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).last(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).mean(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).sum(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).median(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).ohlc(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).nunique(), DataFrame), DataFrame) + + # quantile + check(assert_type(GB_DF.resample(M).quantile(0.5), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).quantile([0.5, 0.7]), DataFrame), DataFrame) + check( + assert_type(GB_DF.resample(M).quantile(np.array([0.5, 0.7])), DataFrame), + DataFrame, + ) + + # std / var + check(assert_type(GB_DF.resample(M).std(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).var(2), DataFrame), DataFrame) + + # size / count + check(assert_type(GB_DF.resample(M).size(), "Series[int]"), Series, np.int64) + check(assert_type(GB_DF.resample(M).count(), DataFrame), DataFrame) + + # filling + check(assert_type(GB_DF.resample(M).ffill(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).nearest(), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).bfill(), DataFrame), DataFrame) + + # fillna + with pytest_warns_bounded( + FutureWarning, + "DatetimeIndexResamplerGroupby.fillna is deprecated ", + lower="2.0.99", + ): + check(assert_type(GB_DF.resample(M).fillna("ffill"), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).fillna("bfill"), DataFrame), DataFrame) + check( + assert_type(GB_DF.resample(M).fillna("nearest", limit=2), DataFrame), + DataFrame, + ) + + # aggregate / apply + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(assert_type(GB_DF.resample(M).aggregate(np.sum), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).agg(np.sum), DataFrame), DataFrame) + check(assert_type(GB_DF.resample(M).apply(np.sum), DataFrame), DataFrame) + check( + assert_type(GB_DF.resample(M).aggregate([np.sum, np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type(GB_DF.resample(M).aggregate(["sum", np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type( + GB_DF.resample(M).aggregate({"col1": "sum", "col2": np.mean}), + DataFrame, + ), + DataFrame, + ) + check( + assert_type( + GB_DF.resample(M).aggregate( + {"col1": ["sum", np.mean], "col2": np.mean} + ), + DataFrame, + ), + DataFrame, + ) + + def f(val: DataFrame) -> Series: + return val.mean() + + check(assert_type(GB_DF.resample(M).aggregate(f), DataFrame), DataFrame) + + # aggregate combinations + def df2frame(val: DataFrame) -> DataFrame: + return DataFrame(val) + + def df2series(val: DataFrame) -> Series: + return val.mean() + + def df2scalar(val: DataFrame) -> float: + return float(val.mean().mean()) + + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(GB_DF.resample(M).aggregate(np.sum), DataFrame) + check(GB_DF.resample(M).aggregate([np.mean]), DataFrame) + check(GB_DF.resample(M).aggregate(["sum", np.mean]), DataFrame) + check(GB_DF.resample(M).aggregate({"col1": np.sum}), DataFrame) + check( + GB_DF.resample(M).aggregate({"col1": np.sum, "col2": np.mean}), + DataFrame, + ) + check( + GB_DF.resample(M).aggregate({"col1": [np.sum], "col2": ["sum", np.mean]}), + DataFrame, + ) + check( + GB_DF.resample(M).aggregate({"col1": np.sum, "col2": ["sum", np.mean]}), + DataFrame, + ) + check( + GB_DF.resample(M).aggregate({"col1": "sum", "col2": [np.mean]}), + DataFrame, + ) + check(GB_DF.resample(M).aggregate("sum"), DataFrame) + check(GB_DF.resample(M).aggregate(df2frame), DataFrame) + check(GB_DF.resample(M).aggregate(df2series), DataFrame) + check(GB_DF.resample(M).aggregate(df2scalar), DataFrame) + + # asfreq + check(assert_type(GB_DF.resample(M).asfreq(-1.0), DataFrame), DataFrame) + + # getattr + check( + assert_type(GB_DF.resample(M).col1, "_ResamplerGroupBy[DataFrame]"), + DatetimeIndexResamplerGroupby, + ) + + # getitem + check( + assert_type(GB_DF.resample(M)["col1"], "_ResamplerGroupBy[DataFrame]"), + DatetimeIndexResamplerGroupby, + ) + check( + assert_type( + GB_DF.resample(M)[["col1", "col2"]], "_ResamplerGroupBy[DataFrame]" + ), + DatetimeIndexResamplerGroupby, + ) + + # interpolate + check(assert_type(GB_DF.resample(M).interpolate(), DataFrame), DataFrame) + check( + assert_type(GB_DF.resample(M).interpolate(method="linear"), DataFrame), + DataFrame, + ) + check(assert_type(GB_DF.resample(M).interpolate(inplace=True), None), type(None)) + + # pipe + def g(val: Resampler[DataFrame]) -> DataFrame: + assert isinstance(val, Resampler) + return val.mean() + + check(assert_type(GB_DF.resample(M).pipe(g), DataFrame), DataFrame) + + def h(val: Resampler[DataFrame]) -> Series: + assert isinstance(val, Resampler) + return val.mean().mean() + + check(assert_type(GB_DF.resample(M).pipe(h), Series), Series) + + def i(val: Resampler[DataFrame]) -> float: + assert isinstance(val, Resampler) + return float(val.mean().mean().mean()) + + check(assert_type(GB_DF.resample(M).pipe(i), float), float) + + # transform + def j(val: Series) -> Series: + return -1 * val + + check(assert_type(GB_DF.resample(M).transform(j), DataFrame), DataFrame) + + +def test_series_groupby_resample() -> None: + # basic + check( + assert_type(GB_S.resample(M), "_ResamplerGroupBy[Series[float]]"), + DatetimeIndexResamplerGroupby, + Series, + ) + + # props + check(assert_type(GB_S.resample(M).obj, "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).ax, Index), DatetimeIndex) + + # agg funcs + check(assert_type(GB_S.resample(M).sum(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).prod(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).min(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).max(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).first(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).last(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).mean(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).sum(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).median(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).ohlc(), DataFrame), DataFrame) + check(assert_type(GB_S.resample(M).nunique(), "Series[int]"), Series, np.int64) + + # quantile + check(assert_type(GB_S.resample(M).quantile(0.5), "Series[float]"), Series, float) + check( + assert_type(GB_S.resample(M).quantile([0.5, 0.7]), "Series[float]"), + Series, + float, + ) + check( + assert_type(GB_S.resample(M).quantile(np.array([0.5, 0.7])), "Series[float]"), + Series, + ) + + # std / var + check(assert_type(GB_S.resample(M).std(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).var(2), "Series[float]"), Series, float) + + # size / count + check(assert_type(GB_S.resample(M).size(), "Series[int]"), Series, np.int64) + check(assert_type(GB_S.resample(M).count(), "Series[int]"), Series, np.int64) + + # filling + check(assert_type(GB_S.resample(M).ffill(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).nearest(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).bfill(), "Series[float]"), Series, float) + + # fillna + with pytest_warns_bounded( + FutureWarning, + "DatetimeIndexResamplerGroupby.fillna is deprecated ", + lower="2.0.99", + ): + check( + assert_type(GB_S.resample(M).fillna("ffill"), "Series[float]"), + Series, + float, + ) + check( + assert_type(GB_S.resample(M).fillna("bfill"), "Series[float]"), + Series, + float, + ) + check( + assert_type(GB_S.resample(M).fillna("nearest", limit=2), "Series[float]"), + Series, + float, + ) + + # aggregate + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check( + assert_type(GB_S.resample(M).aggregate(np.sum), Union[DataFrame, Series]), + Series, + ) + check( + assert_type(GB_S.resample(M).agg(np.sum), Union[DataFrame, Series]), Series + ) + check( + assert_type(GB_S.resample(M).apply(np.sum), Union[DataFrame, Series]), + Series, + ) + check( + assert_type( + GB_S.resample(M).aggregate([np.sum, np.mean]), Union[DataFrame, Series] + ), + DataFrame, + ) + check( + assert_type( + GB_S.resample(M).aggregate(["sum", np.mean]), Union[DataFrame, Series] + ), + DataFrame, + ) + check( + assert_type( + GB_S.resample(M).aggregate({"col1": "sum", "col2": np.mean}), + Union[DataFrame, Series], + ), + DataFrame, + ) + + def f(val: Series) -> float: + return val.mean() + + check(assert_type(GB_S.resample(M).aggregate(f), Union[DataFrame, Series]), Series) + + # asfreq + check(assert_type(GB_S.resample(M).asfreq(-1.0), "Series[float]"), Series, float) + + # interpolate + check(assert_type(GB_S.resample(M).interpolate(), "Series[float]"), Series, float) + check(assert_type(GB_S.resample(M).interpolate(inplace=True), None), type(None)) + + # pipe + def g(val: Resampler[Series]) -> float: + assert isinstance(val, Resampler) + return float(val.mean().mean()) + + check(assert_type(GB_S.resample(M).pipe(g), float), float) + + # transform + def h(val: Series) -> Series: + return -1 * val + + check(assert_type(GB_S.resample(M).transform(h), Series), Series) + + # aggregate combinations + def s2series(val: Series) -> Series: + return Series(val) + + def s2scalar(val: Series) -> float: + return float(val.mean()) + + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(GB_S.resample(M).aggregate(np.sum), Series) + check(GB_S.resample(M).aggregate([np.mean]), DataFrame) + check(GB_S.resample(M).aggregate(["sum", np.mean]), DataFrame) + check(GB_S.resample(M).aggregate({"sum": np.sum}), DataFrame) + check(GB_S.resample(M).aggregate({"sum": np.sum, "mean": np.mean}), DataFrame) + check(GB_S.resample(M).aggregate("sum"), Series) + check(GB_S.resample(M).aggregate(s2series), Series) + check(GB_S.resample(M).aggregate(s2scalar), Series) + + +def test_frame_groupby_rolling() -> None: + # basic + check( + assert_type(GB_DF.rolling(1), "RollingGroupby[DataFrame]"), + RollingGroupby, + DataFrame, + ) + + # props + check(assert_type(GB_DF.rolling(1).obj, DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).on, Union[str, Index, None]), type(None)) + check(assert_type(GB_DF.rolling(1).method, Literal["single", "table"]), str) + check(assert_type(GB_DF.rolling(1).axis, int), int) + + # agg funcs + check(assert_type(GB_DF.rolling(1).sum(), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).min(), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).max(), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).mean(), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).sum(), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).median(), DataFrame), DataFrame) + + # quantile / std / var / count + check(assert_type(GB_DF.rolling(1).quantile(0.5), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).std(), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).var(2), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).count(), DataFrame), DataFrame) + + # aggregate / apply + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(assert_type(GB_DF.rolling(1).aggregate(np.sum), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).agg(np.sum), DataFrame), DataFrame) + check(assert_type(GB_DF.rolling(1).apply(np.sum), DataFrame), DataFrame) + check( + assert_type(GB_DF.rolling(1).aggregate([np.sum, np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type(GB_DF.rolling(1).aggregate(["sum", np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type( + GB_DF.rolling(1).aggregate({"col1": "sum", "col2": np.mean}), + DataFrame, + ), + DataFrame, + ) + check( + assert_type( + GB_DF.rolling(1).aggregate({"col1": ["sum", np.mean], "col2": np.mean}), + DataFrame, + ), + DataFrame, + ) + + def f(val: DataFrame) -> Series: + return val.mean() + + check(assert_type(GB_DF.rolling(1).aggregate(f), DataFrame), DataFrame) + + # aggregate combinations + def df2series(val: DataFrame) -> Series: + assert isinstance(val, Series) + return val.mean() + + def df2scalar(val: DataFrame) -> float: + return float(val.mean().mean()) + + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(GB_DF.rolling(1).aggregate(np.sum), DataFrame) + check(GB_DF.rolling(1).aggregate([np.mean]), DataFrame) + check(GB_DF.rolling(1).aggregate(["sum", np.mean]), DataFrame) + check(GB_DF.rolling(1).aggregate({"col1": np.sum}), DataFrame) + check( + GB_DF.rolling(1).aggregate({"col1": np.sum, "col2": np.mean}), + DataFrame, + ) + check( + GB_DF.rolling(1).aggregate({"col1": [np.sum], "col2": ["sum", np.mean]}), + DataFrame, + ) + check( + GB_DF.rolling(1).aggregate({"col1": np.sum, "col2": ["sum", np.mean]}), + DataFrame, + ) + check( + GB_DF.rolling(1).aggregate({"col1": "sum", "col2": [np.mean]}), + DataFrame, + ) + check(GB_DF.rolling(1).aggregate("sum"), DataFrame) + check(GB_DF.rolling(1).aggregate(df2series), DataFrame) + check(GB_DF.rolling(1).aggregate(df2scalar), DataFrame) + + # getattr + check( + assert_type(GB_DF.rolling(1).col1, "RollingGroupby[DataFrame]"), + RollingGroupby, + ) + + # getitem + check( + assert_type(GB_DF.rolling(1)["col1"], "RollingGroupby[DataFrame]"), + RollingGroupby, + ) + check( + assert_type(GB_DF.rolling(1)[["col1", "col2"]], "RollingGroupby[DataFrame]"), + RollingGroupby, + ) + + # iter + iterator = iter(GB_DF.rolling(1)) + check(assert_type(iterator, Iterator[DataFrame]), Iterator) + check(assert_type(next(iterator), DataFrame), DataFrame) + check(assert_type(list(GB_DF.rolling(1)), list[DataFrame]), list, DataFrame) + + +def test_series_groupby_rolling() -> None: + # basic + check( + assert_type(GB_S.rolling(1), "RollingGroupby[Series[float]]"), + RollingGroupby, + Series, + ) + + # props + check(assert_type(GB_S.rolling(1).obj, "Series[float]"), Series, float) + + # agg funcs + check(assert_type(GB_S.rolling(1).sum(), "Series[float]"), Series, float) + check(assert_type(GB_S.rolling(1).min(), "Series[float]"), Series, float) + check(assert_type(GB_S.rolling(1).max(), "Series[float]"), Series, float) + check(assert_type(GB_S.rolling(1).mean(), "Series[float]"), Series, float) + check(assert_type(GB_S.rolling(1).sum(), "Series[float]"), Series, float) + check(assert_type(GB_S.rolling(1).median(), "Series[float]"), Series, float) + + # quantile / std / var / count + check(assert_type(GB_S.rolling(1).quantile(0.5), "Series[float]"), Series, float) + check(assert_type(GB_S.rolling(1).std(), "Series[float]"), Series, float) + check(assert_type(GB_S.rolling(1).var(2), "Series[float]"), Series, float) + check(assert_type(GB_S.rolling(1).count(), "Series[float]"), Series, float) + + # aggregate + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(assert_type(GB_S.rolling(1).aggregate("sum"), Series), Series) + check(assert_type(GB_S.rolling(1).aggregate(np.sum), Series), Series) + check(assert_type(GB_S.rolling(1).agg(np.sum), Series), Series) + check( + assert_type(GB_S.rolling(1).apply(np.sum), "Series[float]"), Series, float + ) + check( + assert_type(GB_S.rolling(1).aggregate([np.sum, np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type(GB_S.rolling(1).aggregate(["sum", np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type( + GB_S.rolling(1).aggregate({"col1": "sum", "col2": np.mean}), DataFrame + ), + DataFrame, + ) + + def f(val: Series) -> float: + return val.mean() + + check(assert_type(GB_S.rolling(1).aggregate(f), Series), Series) + + def s2scalar(val: Series) -> float: + return float(val.mean()) + + check(assert_type(GB_S.rolling(1).aggregate(s2scalar), Series), Series) + + # iter + iterator = iter(GB_S.rolling(1)) + check(assert_type(iterator, "Iterator[Series[float]]"), Iterator) + check(assert_type(next(iterator), "Series[float]"), Series, float) + check(assert_type(list(GB_S.rolling(1)), list[Series[float]]), list, Series) + + +def test_frame_groupby_expanding() -> None: + # basic + check( + assert_type(GB_DF.expanding(1), "ExpandingGroupby[DataFrame]"), + ExpandingGroupby, + DataFrame, + ) + + # props + check(assert_type(GB_DF.expanding(1).obj, DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).on, Union[str, Index, None]), type(None)) + check(assert_type(GB_DF.expanding(1).method, Literal["single", "table"]), str) + check(assert_type(GB_DF.expanding(1).axis, int), int) + + # agg funcs + check(assert_type(GB_DF.expanding(1).sum(), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).min(), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).max(), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).mean(), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).sum(), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).median(), DataFrame), DataFrame) + + # quantile / std / var / count + check(assert_type(GB_DF.expanding(1).quantile(0.5), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).std(), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).var(2), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).count(), DataFrame), DataFrame) + + # aggregate / apply + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(assert_type(GB_DF.expanding(1).aggregate(np.sum), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).agg(np.sum), DataFrame), DataFrame) + check(assert_type(GB_DF.expanding(1).apply(np.sum), DataFrame), DataFrame) + check( + assert_type(GB_DF.expanding(1).aggregate([np.sum, np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type(GB_DF.expanding(1).aggregate(["sum", np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type( + GB_DF.expanding(1).aggregate({"col1": "sum", "col2": np.mean}), + DataFrame, + ), + DataFrame, + ) + check( + assert_type( + GB_DF.expanding(1).aggregate( + {"col1": ["sum", np.mean], "col2": np.mean} + ), + DataFrame, + ), + DataFrame, + ) + + def f(val: DataFrame) -> Series: + return val.mean() + + check(assert_type(GB_DF.expanding(1).aggregate(f), DataFrame), DataFrame) + + # aggregate combinations + def df2series(val: DataFrame) -> Series: + assert isinstance(val, Series) + return val.mean() + + def df2scalar(val: DataFrame) -> float: + return float(val.mean().mean()) + + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(GB_DF.expanding(1).aggregate(np.sum), DataFrame) + check(GB_DF.expanding(1).aggregate([np.mean]), DataFrame) + check(GB_DF.expanding(1).aggregate(["sum", np.mean]), DataFrame) + check(GB_DF.expanding(1).aggregate({"col1": np.sum}), DataFrame) + check( + GB_DF.expanding(1).aggregate({"col1": np.sum, "col2": np.mean}), + DataFrame, + ) + check( + GB_DF.expanding(1).aggregate({"col1": [np.sum], "col2": ["sum", np.mean]}), + DataFrame, + ) + check( + GB_DF.expanding(1).aggregate({"col1": np.sum, "col2": ["sum", np.mean]}), + DataFrame, + ) + check( + GB_DF.expanding(1).aggregate({"col1": "sum", "col2": [np.mean]}), + DataFrame, + ) + check(GB_DF.expanding(1).aggregate("sum"), DataFrame) + check(GB_DF.expanding(1).aggregate(df2series), DataFrame) + check(GB_DF.expanding(1).aggregate(df2scalar), DataFrame) + + # getattr + check( + assert_type(GB_DF.expanding(1).col1, "ExpandingGroupby[DataFrame]"), + ExpandingGroupby, + ) + + # getitem + check( + assert_type(GB_DF.expanding(1)["col1"], "ExpandingGroupby[DataFrame]"), + ExpandingGroupby, + ) + check( + assert_type( + GB_DF.expanding(1)[["col1", "col2"]], "ExpandingGroupby[DataFrame]" + ), + ExpandingGroupby, + ) + + # iter + iterator = iter(GB_DF.expanding(1)) + check(assert_type(iterator, Iterator[DataFrame]), Iterator) + check(assert_type(next(iterator), DataFrame), DataFrame) + check(assert_type(list(GB_DF.expanding(1)), list[DataFrame]), list, DataFrame) + + +def test_series_groupby_expanding() -> None: + # basic + check( + assert_type(GB_S.expanding(1), "ExpandingGroupby[Series[float]]"), + ExpandingGroupby, + Series, + ) + + # props + check(assert_type(GB_S.expanding(1).obj, "Series[float]"), Series, float) + + # agg funcs + check(assert_type(GB_S.expanding(1).sum(), "Series[float]"), Series, float) + check(assert_type(GB_S.expanding(1).min(), "Series[float]"), Series, float) + check(assert_type(GB_S.expanding(1).max(), "Series[float]"), Series, float) + check(assert_type(GB_S.expanding(1).mean(), "Series[float]"), Series, float) + check(assert_type(GB_S.expanding(1).sum(), "Series[float]"), Series, float) + check(assert_type(GB_S.expanding(1).median(), "Series[float]"), Series, float) + + # quantile / std / var / count + check(assert_type(GB_S.expanding(1).quantile(0.5), "Series[float]"), Series, float) + check(assert_type(GB_S.expanding(1).std(), "Series[float]"), Series, float) + check(assert_type(GB_S.expanding(1).var(2), "Series[float]"), Series, float) + check(assert_type(GB_S.expanding(1).count(), "Series[float]"), Series, float) + + # aggregate + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(assert_type(GB_S.expanding(1).aggregate("sum"), Series), Series) + check(assert_type(GB_S.expanding(1).aggregate(np.sum), Series), Series) + check(assert_type(GB_S.expanding(1).agg(np.sum), Series), Series) + check( + assert_type(GB_S.expanding(1).apply(np.sum), "Series[float]"), Series, float + ) + check( + assert_type(GB_S.expanding(1).aggregate([np.sum, np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type(GB_S.expanding(1).aggregate(["sum", np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type( + GB_S.expanding(1).aggregate({"col1": "sum", "col2": np.mean}), DataFrame + ), + DataFrame, + ) + + def f(val: Series) -> float: + return val.mean() + + check(assert_type(GB_S.expanding(1).aggregate(f), Series), Series) + + def s2scalar(val: Series) -> float: + return float(val.mean()) + + check(assert_type(GB_S.expanding(1).aggregate(s2scalar), Series), Series) + + # iter + iterator = iter(GB_S.expanding(1)) + check(assert_type(iterator, "Iterator[Series[float]]"), Iterator) + check(assert_type(next(iterator), "Series[float]"), Series, float) + check(assert_type(list(GB_S.expanding(1)), list[Series[float]]), list, Series) + + +def test_frame_groupby_ewm() -> None: + # basic + check( + assert_type(GB_DF.ewm(1), "ExponentialMovingWindowGroupby[DataFrame]"), + ExponentialMovingWindowGroupby, + DataFrame, + ) + + # props + check(assert_type(GB_DF.ewm(1).obj, DataFrame), DataFrame) + check(assert_type(GB_DF.ewm(1).on, Union[str, Index, None]), type(None)) + check(assert_type(GB_DF.ewm(1).method, Literal["single", "table"]), str) + check(assert_type(GB_DF.ewm(1).axis, int), int) + + # agg funcs + check(assert_type(GB_DF.ewm(1).sum(), DataFrame), DataFrame) + check(assert_type(GB_DF.ewm(1).mean(), DataFrame), DataFrame) + check(assert_type(GB_DF.ewm(1).sum(), DataFrame), DataFrame) + + # std / var + check(assert_type(GB_DF.ewm(1).std(), DataFrame), DataFrame) + check(assert_type(GB_DF.ewm(1).var(), DataFrame), DataFrame) + + # aggregate + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(assert_type(GB_DF.ewm(1).aggregate(np.sum), DataFrame), DataFrame) + check(assert_type(GB_DF.ewm(1).agg(np.sum), DataFrame), DataFrame) + check( + assert_type(GB_DF.ewm(1).aggregate([np.sum, np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type(GB_DF.ewm(1).aggregate(["sum", np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type( + GB_DF.ewm(1).aggregate({"col1": "sum", "col2": np.mean}), + DataFrame, + ), + DataFrame, + ) + check( + assert_type( + GB_DF.ewm(1).aggregate({"col1": ["sum", np.mean], "col2": np.mean}), + DataFrame, + ), + DataFrame, + ) + + # aggregate combinations + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(GB_DF.ewm(1).aggregate(np.sum), DataFrame) + check(GB_DF.ewm(1).aggregate([np.mean]), DataFrame) + check(GB_DF.ewm(1).aggregate(["sum", np.mean]), DataFrame) + check(GB_DF.ewm(1).aggregate({"col1": np.sum}), DataFrame) + check( + GB_DF.ewm(1).aggregate({"col1": np.sum, "col2": np.mean}), + DataFrame, + ) + check( + GB_DF.ewm(1).aggregate({"col1": [np.sum], "col2": ["sum", np.mean]}), + DataFrame, + ) + check( + GB_DF.ewm(1).aggregate({"col1": np.sum, "col2": ["sum", np.mean]}), + DataFrame, + ) + check( + GB_DF.ewm(1).aggregate({"col1": "sum", "col2": [np.mean]}), + DataFrame, + ) + check(GB_DF.ewm(1).aggregate("sum"), DataFrame) + + # getattr + check( + assert_type(GB_DF.ewm(1).col1, "ExponentialMovingWindowGroupby[DataFrame]"), + ExponentialMovingWindowGroupby, + ) + + # getitem + check( + assert_type(GB_DF.ewm(1)["col1"], "ExponentialMovingWindowGroupby[DataFrame]"), + ExponentialMovingWindowGroupby, + ) + check( + assert_type( + GB_DF.ewm(1)[["col1", "col2"]], "ExponentialMovingWindowGroupby[DataFrame]" + ), + ExponentialMovingWindowGroupby, + ) + + # iter + iterator = iter(GB_DF.ewm(1)) + check(assert_type(iterator, Iterator[DataFrame]), Iterator) + check(assert_type(next(iterator), DataFrame), DataFrame) + check(assert_type(list(GB_DF.ewm(1)), list[DataFrame]), list, DataFrame) + + +def test_series_groupby_ewm() -> None: + # basic + check( + assert_type(GB_S.ewm(1), "ExponentialMovingWindowGroupby[Series[float]]"), + ExponentialMovingWindowGroupby, + Series, + ) + + # props + check(assert_type(GB_S.ewm(1).obj, "Series[float]"), Series, float) + + # agg funcs + check(assert_type(GB_S.ewm(1).sum(), "Series[float]"), Series, float) + check(assert_type(GB_S.ewm(1).mean(), "Series[float]"), Series, float) + check(assert_type(GB_S.ewm(1).sum(), "Series[float]"), Series, float) + + # std / var + check(assert_type(GB_S.ewm(1).std(), "Series[float]"), Series, float) + check(assert_type(GB_S.ewm(1).var(), "Series[float]"), Series, float) + + # aggregate + with pytest_warns_bounded( + FutureWarning, + r"The provided callable is currently using ", + lower="2.0.99", + ): + check(assert_type(GB_S.ewm(1).aggregate("sum"), Series), Series) + check(assert_type(GB_S.ewm(1).aggregate(np.sum), Series), Series) + check(assert_type(GB_S.ewm(1).agg(np.sum), Series), Series) + check( + assert_type(GB_S.ewm(1).aggregate([np.sum, np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type(GB_S.ewm(1).aggregate(["sum", np.mean]), DataFrame), + DataFrame, + ) + check( + assert_type( + GB_S.ewm(1).aggregate({"col1": "sum", "col2": np.mean}), DataFrame + ), + DataFrame, + ) + + # iter + iterator = iter(GB_S.ewm(1)) + check(assert_type(iterator, "Iterator[Series[float]]"), Iterator) + check(assert_type(next(iterator), "Series[float]"), Series, float) + check(assert_type(list(GB_S.ewm(1)), list[Series[float]]), list, Series) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 53b213732..36214d8db 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -1,5 +1,9 @@ import io -from typing import Any +import itertools +from typing import ( + Any, + Union, +) from matplotlib.axes import Axes from matplotlib.figure import Figure @@ -8,6 +12,7 @@ import numpy as np import numpy.typing as npt import pandas as pd +from pandas import Series import pytest from typing_extensions import assert_type @@ -578,3 +583,78 @@ def test_plot_subplot_changes_150() -> None: ), np.ndarray, ) + + +def test_grouped_dataframe_boxplot(close_figures): + tuples = [t for t in itertools.product(range(10), range(2))] + index = pd.MultiIndex.from_tuples(tuples, names=["lvl0", "lvl1"]) + df = pd.DataFrame( + data=np.random.randn(len(index), 2), columns=["A", "B"], index=index + ) + grouped = df.groupby(level="lvl1") + + # subplots (default is subplots=True) + check(assert_type(grouped.boxplot(), Series), Series) + check(assert_type(grouped.boxplot(subplots=True), Series), Series) + + # a single plot + check( + assert_type( + grouped.boxplot( + subplots=False, rot=45, fontsize=12, figsize=(8, 10), vert=False + ), + Axes, + ), + Axes, + ) + + # not a literal bool + check(assert_type(grouped.boxplot(subplots=bool(0.5)), Union[Axes, Series]), Series) + + +def test_grouped_dataframe_hist(close_figures): + df = IRIS_DF.iloc[:50] + grouped = df.groupby("Name") + check(assert_type(grouped.hist(), Series), Series) + check( + assert_type( + grouped.hist( + column="PetalWidth", + by="PetalLength", + grid=False, + xlabelsize=1.5, + ylabelsize=0.5, + yrot=10.0, + sharex=True, + sharey=False, + figsize=(1.5, 1.5), + bins=4, + ), + Series, + ), + Series, + ) + + +def test_grouped_series_hist(close_figures): + 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) + grouped = s.groupby(level=0) + check(assert_type(grouped.hist(), Series), Series) + check(assert_type(grouped.hist(by="a", grid=False), Series), Series) + check( + assert_type( + grouped.hist( + by=["a", "b"], + grid=False, + xlabelsize=1.5, + ylabelsize=0.5, + yrot=10.0, + figsize=(1.5, 1.5), + bins=4, + legend=True, + ), + Series, + ), + Series, + ) diff --git a/tests/test_resampler.py b/tests/test_resampler.py index 3129a247e..f5681adfa 100644 --- a/tests/test_resampler.py +++ b/tests/test_resampler.py @@ -1,6 +1,6 @@ from collections.abc import ( - Generator, Hashable, + Iterator, ) from typing import Union @@ -13,14 +13,16 @@ Series, date_range, ) -from pandas.core.groupby.generic import SeriesGroupBy -from pandas.core.resample import Resampler +from pandas.core.groupby.generic import ( + DataFrameGroupBy, + SeriesGroupBy, +) +from pandas.core.resample import DatetimeIndexResampler from typing_extensions import assert_type -from pandas._typing import Scalar - from tests import ( PD_LTE_21, + TYPE_CHECKING_INVALID_USAGE, check, pytest_warns_bounded, ) @@ -30,6 +32,7 @@ S = DF_.iloc[:, 0] DF = DataFrame({"col1": S, "col2": S}) + _AggRetType = Union[DataFrame, Series] if PD_LTE_21: @@ -44,9 +47,7 @@ def test_props() -> None: def test_iter() -> None: - assert_type( - iter(DF.resample(MonthFreq)), Generator[tuple[Hashable, DataFrame], None, None] - ) + assert_type(iter(DF.resample(MonthFreq)), Iterator[tuple[Hashable, DataFrame]]) for v in DF.resample(MonthFreq): check(assert_type(v, tuple[Hashable, DataFrame]), tuple) @@ -82,7 +83,7 @@ def test_std_var() -> None: def test_size_count() -> None: - check(assert_type(DF.resample(MonthFreq).size(), Series), Series) + check(assert_type(DF.resample(MonthFreq).size(), "Series[int]"), Series, np.int64) check(assert_type(DF.resample(MonthFreq).count(), DataFrame), DataFrame) @@ -117,27 +118,22 @@ def test_aggregate() -> None: lower="2.0.99", ): check( - assert_type(DF.resample(MonthFreq).aggregate(np.sum), _AggRetType), - DataFrame, + assert_type(DF.resample(MonthFreq).aggregate(np.sum), DataFrame), DataFrame ) - check(assert_type(DF.resample(MonthFreq).agg(np.sum), _AggRetType), DataFrame) - check(assert_type(DF.resample(MonthFreq).apply(np.sum), _AggRetType), DataFrame) + check(assert_type(DF.resample(MonthFreq).agg(np.sum), DataFrame), DataFrame) + check(assert_type(DF.resample(MonthFreq).apply(np.sum), DataFrame), DataFrame) check( - assert_type( - DF.resample(MonthFreq).aggregate([np.sum, np.mean]), _AggRetType - ), + assert_type(DF.resample(MonthFreq).aggregate([np.sum, np.mean]), DataFrame), DataFrame, ) check( - assert_type( - DF.resample(MonthFreq).aggregate(["sum", np.mean]), _AggRetType - ), + assert_type(DF.resample(MonthFreq).aggregate(["sum", np.mean]), DataFrame), DataFrame, ) check( assert_type( DF.resample(MonthFreq).aggregate({"col1": "sum", "col2": np.mean}), - _AggRetType, + DataFrame, ), DataFrame, ) @@ -146,7 +142,7 @@ def test_aggregate() -> None: DF.resample(MonthFreq).aggregate( {"col1": ["sum", np.mean], "col2": np.mean} ), - _AggRetType, + DataFrame, ), DataFrame, ) @@ -154,7 +150,7 @@ def test_aggregate() -> None: def f(val: DataFrame) -> Series: return val.mean() - check(assert_type(DF.resample(MonthFreq).aggregate(f), _AggRetType), DataFrame) + check(assert_type(DF.resample(MonthFreq).aggregate(f), DataFrame), DataFrame) def test_asfreq() -> None: @@ -180,21 +176,112 @@ def test_interpolate_inplace() -> None: def test_pipe() -> None: - def f(val: DataFrame) -> DataFrame: + def f(val: "DatetimeIndexResampler[DataFrame]") -> DataFrame: + assert isinstance(val, DatetimeIndexResampler) return DataFrame(val) check(assert_type(DF.resample(MonthFreq).pipe(f), DataFrame), DataFrame) - def g(val: DataFrame) -> Series: + def g(val: "DatetimeIndexResampler[DataFrame]") -> DataFrame: + assert isinstance(val, DatetimeIndexResampler) return val.mean() check(assert_type(DF.resample(MonthFreq).pipe(g), DataFrame), DataFrame) - def h(val: DataFrame) -> float: + def h(val: "DatetimeIndexResampler[DataFrame]") -> Series: + assert isinstance(val, DatetimeIndexResampler) return val.mean().mean() check(assert_type(DF.resample(MonthFreq).pipe(h), Series), Series) + def i(val: "DatetimeIndexResampler[DataFrame]") -> float: + assert isinstance(val, DatetimeIndexResampler) + return float(val.mean().mean().mean()) + + check(assert_type(DF.resample(MonthFreq).pipe(i), float), float) + + def j( + res: "DatetimeIndexResampler[DataFrame]", + pos: int, + /, + arg1: list[float], + arg2: str, + *, + kw: tuple[int], + ) -> DataFrame: + assert isinstance(res, DatetimeIndexResampler) + return res.obj + + check( + assert_type( + DF.resample(MonthFreq).pipe(j, 1, [1.0], arg2="hi", kw=(1,)), DataFrame + ), + DataFrame, + ) + + if TYPE_CHECKING_INVALID_USAGE: + DF.resample(MonthFreq).pipe( + j, + "a", # type: ignore[arg-type] # pyright: ignore[reportGeneralTypeIssues] + [1.0, 2.0], + arg2="hi", + kw=(1,), + ) + DF.resample(MonthFreq).pipe( + j, + 1, + [1.0, "b"], # type: ignore[list-item] # pyright: ignore[reportGeneralTypeIssues] + arg2="hi", + kw=(1,), + ) + DF.resample(MonthFreq).pipe( + j, + 1, + [1.0], + arg2=11, # type: ignore[arg-type] # pyright: ignore[reportGeneralTypeIssues] + kw=(1,), + ) + DF.resample(MonthFreq).pipe( + j, + 1, + [1.0], + arg2="hi", + kw=(1, 2), # type: ignore[arg-type] # pyright: ignore[reportGeneralTypeIssues] + ) + DF.resample(MonthFreq).pipe( # type: ignore[call-arg] + j, + 1, + [1.0], + arg3="hi", # pyright: ignore[reportGeneralTypeIssues] + kw=(1,), + ) + DF.resample(MonthFreq).pipe( # type: ignore[misc] + j, + 1, + [1.0], + 11, # type: ignore[arg-type] + (1,), # pyright: ignore[reportGeneralTypeIssues] + ) + DF.resample(MonthFreq).pipe( # type: ignore[call-arg] + j, + pos=1, # pyright: ignore[reportGeneralTypeIssues] + arg1=[1.0], + arg2=11, # type: ignore[arg-type] + kw=(1,), + ) + + def k(x: int, t: "DatetimeIndexResampler[DataFrame]") -> DataFrame: + assert isinstance(x, int) + return t.obj + + check(assert_type(DF.resample(MonthFreq).pipe((k, "t"), 1), DataFrame), DataFrame) + + if TYPE_CHECKING_INVALID_USAGE: + DF.resample(MonthFreq).pipe( + (k, 1), # type: ignore[arg-type] # pyright: ignore[reportGeneralTypeIssues] + 1, + ) + def test_transform() -> None: def f(val: Series) -> Series: @@ -224,7 +311,7 @@ def test_agg_funcs_series() -> None: check(assert_type(S.resample(MonthFreq).sum(), Series), Series) check(assert_type(S.resample(MonthFreq).median(), Series), Series) check(assert_type(S.resample(MonthFreq).ohlc(), DataFrame), DataFrame) - check(assert_type(S.resample(MonthFreq).nunique(), Series), Series) + check(assert_type(S.resample(MonthFreq).nunique(), "Series[int]"), Series, np.int64) def test_quantile_series() -> None: @@ -242,8 +329,8 @@ def test_std_var_series() -> None: def test_size_count_series() -> None: - check(assert_type(S.resample(MonthFreq).size(), Series), Series) - check(assert_type(S.resample(MonthFreq).count(), Series), Series) + check(assert_type(S.resample(MonthFreq).size(), "Series[int]"), Series, np.int64) + check(assert_type(S.resample(MonthFreq).count(), "Series[int]"), Series, np.int64) def test_filling_series() -> None: @@ -317,17 +404,20 @@ def test_interpolate_inplace_series() -> None: def test_pipe_series() -> None: - def f(val: Series) -> Series: + def f(val: "DatetimeIndexResampler[Series]") -> Series: + assert isinstance(val, DatetimeIndexResampler) return Series(val) check(assert_type(S.resample(MonthFreq).pipe(f), Series), Series) - def g(val: Resampler) -> float: + def g(val: "DatetimeIndexResampler[Series]") -> float: + assert isinstance(val, DatetimeIndexResampler) return float(val.mean().mean()) - check(assert_type(S.resample(MonthFreq).pipe(g), Scalar), float) + check(assert_type(S.resample(MonthFreq).pipe(g), float), float) - def h(val: Series) -> DataFrame: + def h(val: "DatetimeIndexResampler[Series]") -> DataFrame: + assert isinstance(val, DatetimeIndexResampler) return DataFrame({0: val, 1: val}) check(assert_type(S.resample(MonthFreq).pipe(h), DataFrame), DataFrame) @@ -408,3 +498,11 @@ def df2scalar(val: DataFrame) -> float: check(DF.resample(MonthFreq).aggregate(df2frame), DataFrame) check(DF.resample(MonthFreq).aggregate(df2series), DataFrame) check(DF.resample(MonthFreq).aggregate(df2scalar), DataFrame) + + +def test_getitem() -> None: + check(assert_type(DF.resample(MonthFreq)["col1"], SeriesGroupBy), SeriesGroupBy) + check( + assert_type(DF.resample(MonthFreq)[["col1", "col2"]], DataFrameGroupBy), + DataFrameGroupBy, + ) diff --git a/tests/test_series.py b/tests/test_series.py index 673e4623d..27d1b94a8 100644 --- a/tests/test_series.py +++ b/tests/test_series.py @@ -93,6 +93,11 @@ def test_types_init() -> None: pd.Series(data=[1, 2, 3, 4], index=None) pd.Series(data={"row1": [1, 2], "row2": [3, 4]}, index=None) + groupby = pd.Series(np.array([1, 2])).groupby(level=0) + resampler = pd.Series(np.array([1, 2]), index=dt).resample("1D") + pd.Series(data=groupby) + pd.Series(data=resampler) + def test_types_any() -> None: check(assert_type(pd.Series([False, False]).any(), bool), np.bool_) @@ -671,6 +676,15 @@ def test_groupby_result() -> None: check(assert_type(index3, tuple), tuple, int) check(assert_type(value3, "pd.Series[int]"), pd.Series, np.integer) + # Explicit by=None + iterator4 = s.groupby(None, level=0).__iter__() + assert_type(iterator4, Iterator[tuple[Scalar, "pd.Series[int]"]]) + index4, value4 = next(iterator4) + assert_type((index4, value4), tuple[Scalar, "pd.Series[int]"]) + + check(assert_type(index4, Scalar), int) + check(assert_type(value4, "pd.Series[int]"), pd.Series, np.integer) + # Want to make sure these cases are differentiated for (k1, k2), g in s.groupby(["a", "b"]): pass @@ -1573,20 +1587,24 @@ def test_resample() -> None: N = 10 index = pd.date_range("1/1/2000", periods=N, freq="min") x = [x for x in range(N)] - df = pd.Series(x, index=index) - check(assert_type(df.resample("2min").std(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").var(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").quantile(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").sum(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").prod(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").min(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").max(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").first(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").last(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").mean(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").sem(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").median(), pd.Series), pd.Series) - check(assert_type(df.resample("2min").ohlc(), pd.DataFrame), pd.DataFrame) + s = pd.Series(x, index=index, dtype=float) + check(assert_type(s.resample("2min").std(), "pd.Series[float]"), pd.Series, float) + check(assert_type(s.resample("2min").var(), "pd.Series[float]"), pd.Series, float) + check( + assert_type(s.resample("2min").quantile(), "pd.Series[float]"), pd.Series, float + ) + check(assert_type(s.resample("2min").sum(), "pd.Series[float]"), pd.Series, float) + check(assert_type(s.resample("2min").prod(), "pd.Series[float]"), pd.Series, float) + check(assert_type(s.resample("2min").min(), "pd.Series[float]"), pd.Series, float) + check(assert_type(s.resample("2min").max(), "pd.Series[float]"), pd.Series, float) + check(assert_type(s.resample("2min").first(), "pd.Series[float]"), pd.Series, float) + check(assert_type(s.resample("2min").last(), "pd.Series[float]"), pd.Series, float) + check(assert_type(s.resample("2min").mean(), "pd.Series[float]"), pd.Series, float) + check(assert_type(s.resample("2min").sem(), "pd.Series[float]"), pd.Series, float) + check( + assert_type(s.resample("2min").median(), "pd.Series[float]"), pd.Series, float + ) + check(assert_type(s.resample("2min").ohlc(), pd.DataFrame), pd.DataFrame) def test_to_xarray(): @@ -2755,8 +2773,12 @@ def test_to_json_mode() -> None: def test_groupby_diff() -> None: # GH 658 - s = pd.Series([1, 2, 3, np.nan]) - check(assert_type(s.groupby(level=0).diff(), pd.Series), pd.Series) + s = pd.Series([1.0, 2.0, 3.0, np.nan]) + check( + assert_type(s.groupby(level=0).diff(), "pd.Series[float]"), + pd.Series, + float, + ) def test_to_string() -> None: From 0ec4cbc65cf6bda1f180defcd39a615900efbb51 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 6 Jan 2024 21:29:10 +0100 Subject: [PATCH 02/23] Runtime Series is not generic --- tests/test_groupby.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_groupby.py b/tests/test_groupby.py index 916b93330..cea05d5df 100644 --- a/tests/test_groupby.py +++ b/tests/test_groupby.py @@ -588,7 +588,7 @@ def s2scalar(val: Series) -> float: iterator = iter(GB_S.rolling(1)) check(assert_type(iterator, "Iterator[Series[float]]"), Iterator) check(assert_type(next(iterator), "Series[float]"), Series, float) - check(assert_type(list(GB_S.rolling(1)), list[Series[float]]), list, Series) + check(assert_type(list(GB_S.rolling(1)), "list[Series[float]]"), list, Series) def test_frame_groupby_expanding() -> None: @@ -786,7 +786,7 @@ def s2scalar(val: Series) -> float: iterator = iter(GB_S.expanding(1)) check(assert_type(iterator, "Iterator[Series[float]]"), Iterator) check(assert_type(next(iterator), "Series[float]"), Series, float) - check(assert_type(list(GB_S.expanding(1)), list[Series[float]]), list, Series) + check(assert_type(list(GB_S.expanding(1)), "list[Series[float]]"), list, Series) def test_frame_groupby_ewm() -> None: @@ -944,4 +944,4 @@ def test_series_groupby_ewm() -> None: iterator = iter(GB_S.ewm(1)) check(assert_type(iterator, "Iterator[Series[float]]"), Iterator) check(assert_type(next(iterator), "Series[float]"), Series, float) - check(assert_type(list(GB_S.ewm(1)), list[Series[float]]), list, Series) + check(assert_type(list(GB_S.ewm(1)), "list[Series[float]]"), list, Series) From fce36b647407788ffea5c0923718555949442eb9 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 09:26:40 +0100 Subject: [PATCH 03/23] Remove default values and deprecated --- .pre-commit-config.yaml | 2 +- pandas-stubs/core/apply.pyi | 18 +- pandas-stubs/core/generic.pyi | 18 +- pandas-stubs/core/groupby/generic.pyi | 178 +++++++++--------- pandas-stubs/core/groupby/groupby.pyi | 250 ++++++++++++------------- pandas-stubs/core/groupby/grouper.pyi | 68 +++---- pandas-stubs/core/groupby/indexing.pyi | 2 +- pandas-stubs/core/groupby/ops.pyi | 16 +- pandas-stubs/core/resample.pyi | 152 +++++++-------- pandas-stubs/core/series.pyi | 2 +- pandas-stubs/core/window/ewm.pyi | 102 +++++----- pandas-stubs/core/window/expanding.pyi | 8 +- pandas-stubs/core/window/rolling.pyi | 142 +++++++------- pandas-stubs/plotting/_core.pyi | 62 +++--- pandas-stubs/util/_decorators.pyi | 18 +- 15 files changed, 510 insertions(+), 528 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 054d20aca..35165128e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: --exit-non-zero-on-fix, --target-version, py39, --extend-select, "PYI,UP,RUF100", - --ignore, "E501,E731,F841,PYI042,PYI053", + --ignore, "E501,E731,F841,PYI042", --per-file-ignores, "_*.pyi:PYI001", --fix ] diff --git a/pandas-stubs/core/apply.pyi b/pandas-stubs/core/apply.pyi index 12f2c176c..5cc66600c 100644 --- a/pandas-stubs/core/apply.pyi +++ b/pandas-stubs/core/apply.pyi @@ -48,12 +48,12 @@ ResType = dict[int, Any] # noqa: PYI026 def frame_apply( obj: DataFrame, func: AggFuncType, - axis: Axis = 0, - raw: bool = False, - result_type: str | None = None, - by_row: Literal[False, "compat"] = "compat", - args=None, - kwargs=None, + axis: Axis = ..., + raw: bool = ..., + result_type: str | None = ..., + by_row: Literal[False, "compat"] = ..., + args=..., + kwargs=..., ) -> FrameApply: ... class Apply(Generic[_AggObjT], metaclass=abc.ABCMeta): @@ -72,7 +72,7 @@ class Apply(Generic[_AggObjT], metaclass=abc.ABCMeta): raw: bool, result_type: Literal["reduce", "broadcast", "expand"] | None, *, - by_row: Literal[False, "compat", "_compat"] = "compat", + by_row: Literal[False, "compat", "_compat"] = ..., args, kwargs, ) -> None: ... @@ -132,7 +132,7 @@ class FrameApply(NDFrameApply[DataFrame]): raw: bool, result_type: Literal["reduce", "broadcast", "expand"] | None, *, - by_row: Literal[False, "compat"] = False, + by_row: Literal[False, "compat"] = ..., args, kwargs, ) -> None: ... @@ -192,7 +192,7 @@ class SeriesApply(NDFrameApply[Series]): func: AggFuncType, *, convert_dtype: bool | NoDefault = ..., - by_row: Literal[False, "compat", "_compat"] = "compat", + by_row: Literal[False, "compat", "_compat"] = ..., args, kwargs, ) -> None: ... diff --git a/pandas-stubs/core/generic.pyi b/pandas-stubs/core/generic.pyi index 75fb8c106..1167df9fc 100644 --- a/pandas-stubs/core/generic.pyi +++ b/pandas-stubs/core/generic.pyi @@ -444,15 +444,15 @@ class NDFrame(indexing.IndexingMixin): self, rule: Frequency, axis: Axis | NoDefault = ..., - closed: Literal["right", "left"] | None = None, - label: Literal["right", "left"] | None = None, - convention: TimestampConvention = "start", - kind: Literal["period", "timestamp", "timedelta"] | None = None, - on: Level | None = None, - level: Level | None = None, - origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", - offset: TimedeltaConvertibleTypes | None = None, - group_keys: _bool = False, + closed: Literal["right", "left"] | None = ..., + label: Literal["right", "left"] | None = ..., + convention: TimestampConvention = ..., + kind: Literal["period", "timestamp", "timedelta"] | None = ..., + on: Level | None = ..., + level: Level | None = ..., + origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., + offset: TimedeltaConvertibleTypes | None = ..., + group_keys: _bool = ..., ) -> DatetimeIndexResampler[Self]: ... def first(self, offset) -> Self: ... def last(self, offset) -> Self: ... diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 008357932..802df6d91 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -64,17 +64,17 @@ class SeriesGroupBy(GroupBy[Series[S1]], Generic[S1, ByT]): self, func: list[AggFuncTypeBase], *args, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., **kwargs, ) -> DataFrame: ... @overload def aggregate( self, - func: AggFuncTypeBase | None = None, + func: AggFuncTypeBase | None = ..., *args, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., **kwargs, ) -> Series: ... agg = aggregate @@ -82,47 +82,47 @@ class SeriesGroupBy(GroupBy[Series[S1]], Generic[S1, ByT]): self, func: Callable | str, *args, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., **kwargs, ) -> Series: ... def filter( - self, func: Callable | str, dropna: bool = True, *args, **kwargs + self, func: Callable | str, dropna: bool = ..., *args, **kwargs ) -> Series: ... - def nunique(self, dropna: bool = True) -> Series[int]: ... + def nunique(self, dropna: bool = ...) -> Series[int]: ... # describe delegates to super() method but here it has keyword-only parameters def describe( # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] self, *, - percentiles: Iterable[float] | None = None, - include: Literal["all"] | list[Dtype] | None = None, - exclude: list[Dtype] | None = None, + percentiles: Iterable[float] | None = ..., + include: Literal["all"] | list[Dtype] | None = ..., + exclude: list[Dtype] | None = ..., ) -> DataFrame: ... @overload def value_counts( self, - normalize: Literal[False] = False, - sort: bool = True, - ascending: bool = False, - bins=None, - dropna: bool = True, + normalize: Literal[False] = ..., + sort: bool = ..., + ascending: bool = ..., + bins=..., + dropna: bool = ..., ) -> Series[int]: ... @overload def value_counts( self, normalize: Literal[True], - sort: bool = True, - ascending: bool = False, - bins=None, - dropna: bool = True, + sort: bool = ..., + ascending: bool = ..., + bins=..., + dropna: bool = ..., ) -> Series[float]: ... def fillna( self, - value: object | ArrayLike | None = None, - method: FillnaOptions | None = None, + value: object | ArrayLike | None = ..., + method: FillnaOptions | None = ..., axis: Axis | None | NoDefault = ..., - inplace: bool = False, - limit: int | None = None, + inplace: bool = ..., + limit: int | None = ..., downcast: dict | None | NoDefault = ..., ) -> Series[S1] | None: ... def take( @@ -134,28 +134,28 @@ class SeriesGroupBy(GroupBy[Series[S1]], Generic[S1, ByT]): def skew( self, axis: Axis | NoDefault = ..., - skipna: bool = True, - numeric_only: bool = False, + skipna: bool = ..., + numeric_only: bool = ..., **kwargs, ) -> Series: ... @property def plot(self) -> GroupByPlot[Self]: ... def nlargest( - self, n: int = 5, keep: Literal["first", "last", "all"] = "first" + self, n: int = ..., keep: Literal["first", "last", "all"] = ... ) -> Series[S1]: ... def nsmallest( - self, n: int = 5, keep: Literal["first", "last", "all"] = "first" + self, n: int = ..., keep: Literal["first", "last", "all"] = ... ) -> Series[S1]: ... - def idxmin(self, axis: Axis | NoDefault = ..., skipna: bool = True) -> Series: ... - def idxmax(self, axis: Axis | NoDefault = ..., skipna: bool = True) -> Series: ... + def idxmin(self, axis: Axis | NoDefault = ..., skipna: bool = ...) -> Series: ... + def idxmax(self, axis: Axis | NoDefault = ..., skipna: bool = ...) -> Series: ... def corr( self, other: Series, - method: CorrelationMethod = "pearson", - min_periods: int | None = None, + method: CorrelationMethod = ..., + min_periods: int | None = ..., ) -> Series: ... def cov( - self, other: Series, min_periods: int | None = None, ddof: int | None = 1 + self, other: Series, min_periods: int | None = ..., ddof: int | None = ... ) -> Series: ... @property def is_monotonic_increasing(self) -> Series[bool]: ... @@ -163,17 +163,17 @@ class SeriesGroupBy(GroupBy[Series[S1]], Generic[S1, ByT]): def is_monotonic_decreasing(self) -> Series[bool]: ... def hist( self, - by: IndexLabel | None = None, - ax: PlotAxes | None = None, - grid: bool = True, - xlabelsize: float | None = None, - xrot: float | None = None, - ylabelsize: float | None = None, - yrot: float | None = None, - figsize: tuple[float, float] | None = None, - bins: int | Sequence[int] = 10, - backend: str | None = None, - legend: bool = False, + by: IndexLabel | None = ..., + ax: PlotAxes | None = ..., + grid: bool = ..., + xlabelsize: float | None = ..., + xrot: float | None = ..., + ylabelsize: float | None = ..., + yrot: float | None = ..., + figsize: tuple[float, float] | None = ..., + bins: int | Sequence[int] = ..., + backend: str | None = ..., + legend: bool = ..., **kwargs, ) -> Series: ... # Series[Axes] but this is not allowed @property @@ -212,10 +212,10 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): @overload def aggregate( self, - func: AggFuncTypeFrame | None = None, + func: AggFuncTypeFrame | None = ..., *args, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., **kwargs, ) -> DataFrame: ... agg = aggregate @@ -223,12 +223,12 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): self, func: Callable | str, *args, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., **kwargs, ) -> DataFrame: ... def filter( - self, func: Callable, dropna: bool = True, *args, **kwargs + self, func: Callable, dropna: bool = ..., *args, **kwargs ) -> DataFrame: ... @overload def __getitem__( # type: ignore[overload-overlap] @@ -238,18 +238,18 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): def __getitem__( # pyright: ignore[reportIncompatibleMethodOverride] self, key: Iterable[Hashable] | slice ) -> DataFrameGroupBy[ByT]: ... - def nunique(self, dropna: bool = True) -> DataFrame: ... + def nunique(self, dropna: bool = ...) -> DataFrame: ... def idxmax( self, axis: Axis | None | NoDefault = ..., - skipna: bool = True, - numeric_only: bool = False, + skipna: bool = ..., + numeric_only: bool = ..., ) -> DataFrame: ... def idxmin( self, axis: Axis | None | NoDefault = ..., - skipna: bool = True, - numeric_only: bool = False, + skipna: bool = ..., + numeric_only: bool = ..., ) -> DataFrame: ... boxplot = boxplot_frame_groupby @overload @@ -272,11 +272,11 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): ) -> Series[float]: ... def fillna( self, - value: Hashable | Mapping | Series | DataFrame | None = None, - method: FillnaOptions | None = None, + value: Hashable | Mapping | Series | DataFrame | None = ..., + method: FillnaOptions | None = ..., axis: Axis | None | NoDefault = ..., - inplace: Literal[False] = False, - limit: int | None = None, + inplace: Literal[False] = ..., + limit: int | None = ..., downcast: dict | None | NoDefault = ..., ) -> DataFrame: ... def take( @@ -286,8 +286,8 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): def skew( # type: ignore[overload-overlap] self, axis: Axis | None | NoDefault = ..., - skipna: bool = True, - numeric_only: bool = False, + skipna: bool = ..., + numeric_only: bool = ..., *, level: Level, **kwargs, @@ -296,43 +296,43 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): def skew( self, axis: Axis | None | NoDefault = ..., - skipna: bool = True, - numeric_only: bool = False, + skipna: bool = ..., + numeric_only: bool = ..., *, - level: None = None, + level: None = ..., **kwargs, ) -> Series: ... @property def plot(self) -> GroupByPlot[Self]: ... def corr( self, - method: str | Callable[[np.ndarray, np.ndarray], float] = "pearson", - min_periods: int = 1, - numeric_only: bool = False, + method: str | Callable[[np.ndarray, np.ndarray], float] = ..., + min_periods: int = ..., + numeric_only: bool = ..., ) -> DataFrame: ... def cov( self, - min_periods: int | None = None, - ddof: int | None = 1, - numeric_only: bool = False, + min_periods: int | None = ..., + ddof: int | None = ..., + numeric_only: bool = ..., ) -> DataFrame: ... def hist( self, - column: IndexLabel | None = None, - by: IndexLabel | None = None, - grid: bool = True, - xlabelsize: float | None = None, - xrot: float | None = None, - ylabelsize: float | None = None, - yrot: float | None = None, - ax: PlotAxes | None = None, - sharex: bool = False, - sharey: bool = False, - figsize: tuple[float, float] | None = None, - layout: tuple[int, int] | None = None, - bins: int | Sequence[int] = 10, - backend: str | None = None, - legend: bool = False, + column: IndexLabel | None = ..., + by: IndexLabel | None = ..., + grid: bool = ..., + xlabelsize: float | None = ..., + xrot: float | None = ..., + ylabelsize: float | None = ..., + yrot: float | None = ..., + ax: PlotAxes | None = ..., + sharex: bool = ..., + sharey: bool = ..., + figsize: tuple[float, float] | None = ..., + layout: tuple[int, int] | None = ..., + bins: int | Sequence[int] = ..., + backend: str | None = ..., + legend: bool = ..., **kwargs, ) -> Series: ... # Series[Axes] but this is not allowed @property @@ -341,9 +341,9 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): self, other: DataFrame | Series, axis: Axis | NoDefault = ..., - drop: bool = False, - method: CorrelationMethod = "pearson", - numeric_only: bool = False, + drop: bool = ..., + method: CorrelationMethod = ..., + numeric_only: bool = ..., ) -> DataFrame: ... def __getattr__(self, name: str) -> SeriesGroupBy[Any, ByT]: ... # Overrides that provide more precise return types over the GroupBy class diff --git a/pandas-stubs/core/groupby/groupby.pyi b/pandas-stubs/core/groupby/groupby.pyi index d59f59715..df28de8be 100644 --- a/pandas-stubs/core/groupby/groupby.pyi +++ b/pandas-stubs/core/groupby/groupby.pyi @@ -162,83 +162,83 @@ class GroupBy(BaseGroupBy[NDFrameT]): def __init__( self, obj: NDFrameT, - keys: _KeysArgType | None = None, - axis: Axis = 0, - level: IndexLabel | None = None, - grouper: ops.BaseGrouper | None = None, - exclusions: frozenset[Hashable] | None = None, - selection: IndexLabel | None = None, - as_index: bool = True, - sort: bool = True, - group_keys: bool = True, + keys: _KeysArgType | None = ..., + axis: Axis = ..., + level: IndexLabel | None = ..., + grouper: ops.BaseGrouper | None = ..., + exclusions: frozenset[Hashable] | None = ..., + selection: IndexLabel | None = ..., + as_index: bool = ..., + sort: bool = ..., + group_keys: bool = ..., observed: bool | NoDefault = ..., - dropna: bool = True, + dropna: bool = ..., ) -> None: ... def __getattr__(self, attr: str) -> Any: ... def apply(self, func: Callable | str, *args, **kwargs) -> NDFrameT: ... @final @overload - def any(self: GroupBy[Series], skipna: bool = True) -> Series[bool]: ... + def any(self: GroupBy[Series], skipna: bool = ...) -> Series[bool]: ... @overload - def any(self: GroupBy[DataFrame], skipna: bool = True) -> DataFrame: ... + def any(self: GroupBy[DataFrame], skipna: bool = ...) -> DataFrame: ... @final @overload - def all(self: GroupBy[Series], skipna: bool = True) -> Series[bool]: ... + def all(self: GroupBy[Series], skipna: bool = ...) -> Series[bool]: ... @overload - def all(self: GroupBy[DataFrame], skipna: bool = True) -> DataFrame: ... + def all(self: GroupBy[DataFrame], skipna: bool = ...) -> DataFrame: ... @final def count(self) -> NDFrameT: ... @final def mean( self, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... @final - def median(self, numeric_only: bool = False) -> NDFrameT: ... + def median(self, numeric_only: bool = ...) -> NDFrameT: ... @final @overload def std( self: GroupBy[Series], - ddof: int = 1, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, - numeric_only: bool = False, + ddof: int = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = ..., ) -> Series[float]: ... @overload def std( self: GroupBy[DataFrame], - ddof: int = 1, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, - numeric_only: bool = False, + ddof: int = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = ..., ) -> DataFrame: ... @final @overload def var( self: GroupBy[Series], - ddof: int = 1, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, - numeric_only: bool = False, + ddof: int = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = ..., ) -> Series[float]: ... @overload def var( self: GroupBy[DataFrame], - ddof: int = 1, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, - numeric_only: bool = False, + ddof: int = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., + numeric_only: bool = ..., ) -> DataFrame: ... @final @overload def sem( - self: GroupBy[Series], ddof: int = 1, numeric_only: bool = False + self: GroupBy[Series], ddof: int = ..., numeric_only: bool = ... ) -> Series[float]: ... @overload def sem( - self: GroupBy[DataFrame], ddof: int = 1, numeric_only: bool = False + self: GroupBy[DataFrame], ddof: int = ..., numeric_only: bool = ... ) -> DataFrame: ... @final @overload @@ -248,128 +248,128 @@ class GroupBy(BaseGroupBy[NDFrameT]): @final def sum( self, - numeric_only: bool = False, - min_count: int = 0, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + min_count: int = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... @final - def prod(self, numeric_only: bool = False, min_count: int = 0) -> NDFrameT: ... + def prod(self, numeric_only: bool = ..., min_count: int = ...) -> NDFrameT: ... @final def min( self, - numeric_only: bool = False, - min_count: int = -1, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + min_count: int = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... @final def max( self, - numeric_only: bool = False, - min_count: int = -1, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + min_count: int = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... @final - def first(self, numeric_only: bool = False, min_count: int = -1) -> NDFrameT: ... + def first(self, numeric_only: bool = ..., min_count: int = ...) -> NDFrameT: ... @final - def last(self, numeric_only: bool = False, min_count: int = -1) -> NDFrameT: ... + def last(self, numeric_only: bool = ..., min_count: int = ...) -> NDFrameT: ... @final def ohlc(self) -> DataFrame: ... def describe( self, - percentiles: Iterable[float] | None = None, - include: Literal["all"] | list[Dtype] | None = None, - exclude: list[Dtype] | None = None, + percentiles: Iterable[float] | None = ..., + include: Literal["all"] | list[Dtype] | None = ..., + exclude: list[Dtype] | None = ..., ) -> DataFrame: ... @final def resample( self, rule: Frequency, # Arguments must be kept roughly inline with pandas.core.resample.get_resampler_for_grouping - how: str | None = None, - fill_method: str | None = None, - limit: int | None = None, - kind: str | None = None, - on: Hashable | None = None, + how: str | None = ..., + fill_method: str | None = ..., + limit: int | None = ..., + kind: str | None = ..., + on: Hashable | None = ..., *, - closed: Literal["left", "right"] | None = None, - label: Literal["left", "right"] | None = None, - axis: Axis = 0, - convention: TimestampConvention | None = None, - origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", - offset: TimedeltaConvertibleTypes | None = None, - group_keys: bool = False, + closed: Literal["left", "right"] | None = ..., + label: Literal["left", "right"] | None = ..., + axis: Axis = ..., + convention: TimestampConvention | None = ..., + origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., + offset: TimedeltaConvertibleTypes | None = ..., + group_keys: bool = ..., **kwargs, ) -> _ResamplerGroupBy[NDFrameT]: ... @final def rolling( self, # Arguments must be kept roughly inline with pandas.core.window.RollingGroupby - window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = None, - min_periods: int | None = None, - center: bool | None = False, - win_type: str | None = None, - axis: Axis = 0, - on: str | Index | None = None, - closed: IntervalClosedType | None = None, - step: int | None = None, - method: str = "single", + window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = ..., + min_periods: int | None = ..., + center: bool | None = ..., + win_type: str | None = ..., + axis: Axis = ..., + on: str | Index | None = ..., + closed: IntervalClosedType | None = ..., + step: int | None = ..., + method: str = ..., *, - selection: IndexLabel | None = None, + selection: IndexLabel | None = ..., ) -> RollingGroupby[NDFrameT]: ... @final def expanding( self, # Arguments must be kept roughly inline with pandas.core.window.ExpandingGroupby - min_periods: int = 1, - axis: Axis = 0, - method: str = "single", - selection: IndexLabel | None = None, + min_periods: int = ..., + axis: Axis = ..., + method: str = ..., + selection: IndexLabel | None = ..., ) -> ExpandingGroupby[NDFrameT]: ... @final def ewm( self, # Arguments must be kept roughly inline with pandas.core.window.ExponentialMovingWindowGroupby - com: float | None = None, - span: float | None = None, - halflife: TimedeltaConvertibleTypes | None = None, - alpha: float | None = None, - min_periods: int | None = 0, - adjust: bool = True, - ignore_na: bool = False, - axis: Axis = 0, - times: str | np.ndarray | Series | np.timedelta64 | None = None, - method: CalculationMethod = "single", + com: float | None = ..., + span: float | None = ..., + halflife: TimedeltaConvertibleTypes | None = ..., + alpha: float | None = ..., + min_periods: int | None = ..., + adjust: bool = ..., + ignore_na: bool = ..., + axis: Axis = ..., + times: str | np.ndarray | Series | np.timedelta64 | None = ..., + method: CalculationMethod = ..., *, - selection: IndexLabel | None = None, + selection: IndexLabel | None = ..., ) -> ExponentialMovingWindowGroupby[NDFrameT]: ... @final - def ffill(self, limit: int | None = None) -> NDFrameT: ... + def ffill(self, limit: int | None = ...) -> NDFrameT: ... @final - def bfill(self, limit: int | None = None) -> NDFrameT: ... + def bfill(self, limit: int | None = ...) -> NDFrameT: ... @final @property def nth(self) -> GroupByNthSelector[Self]: ... @final def quantile( self, - q: float | AnyArrayLike = 0.5, - interpolation: str = "linear", - numeric_only: bool = False, + q: float | AnyArrayLike = ..., + interpolation: str = ..., + numeric_only: bool = ..., ) -> NDFrameT: ... @final - def ngroup(self, ascending: bool = True) -> Series[int]: ... + def ngroup(self, ascending: bool = ...) -> Series[int]: ... @final - def cumcount(self, ascending: bool = True) -> Series[int]: ... + def cumcount(self, ascending: bool = ...) -> Series[int]: ... @final def rank( self, - method: str = "average", - ascending: bool = True, - na_option: str = "keep", - pct: bool = False, + method: str = ..., + ascending: bool = ..., + na_option: str = ..., + pct: bool = ..., axis: AxisInt | NoDefault = ..., ) -> NDFrameT: ... @final @@ -378,59 +378,59 @@ class GroupBy(BaseGroupBy[NDFrameT]): def cumsum(self, axis: Axis | NoDefault = ..., *args, **kwargs) -> NDFrameT: ... @final def cummin( - self, axis: AxisInt | NoDefault = ..., numeric_only: bool = False, **kwargs + self, axis: AxisInt | NoDefault = ..., numeric_only: bool = ..., **kwargs ) -> NDFrameT: ... @final def cummax( - self, axis: AxisInt | NoDefault = ..., numeric_only: bool = False, **kwargs + self, axis: AxisInt | NoDefault = ..., numeric_only: bool = ..., **kwargs ) -> NDFrameT: ... @final def shift( self, - periods: int | Sequence[int] = 1, - freq: Frequency | None = None, + periods: int | Sequence[int] = ..., + freq: Frequency | None = ..., axis: Axis | NoDefault = ..., fill_value=..., - suffix: str | None = None, + suffix: str | None = ..., ) -> NDFrameT: ... @final - def diff(self, periods: int = 1, axis: AxisInt | NoDefault = ...) -> NDFrameT: ... + def diff(self, periods: int = ..., axis: AxisInt | NoDefault = ...) -> NDFrameT: ... @final def pct_change( self, - periods: int = 1, + periods: int = ..., fill_method: FillnaOptions | None | NoDefault = ..., limit: int | None | NoDefault = ..., - freq=None, + freq=..., axis: Axis | NoDefault = ..., ) -> NDFrameT: ... @final - def head(self, n: int = 5) -> NDFrameT: ... + def head(self, n: int = ...) -> NDFrameT: ... @final - def tail(self, n: int = 5) -> NDFrameT: ... + def tail(self, n: int = ...) -> NDFrameT: ... @final def sample( self, - n: int | None = None, - frac: float | None = None, - replace: bool = False, - weights: Sequence | Series | None = None, - random_state: RandomState | None = None, + n: int | None = ..., + frac: float | None = ..., + replace: bool = ..., + weights: Sequence | Series | None = ..., + random_state: RandomState | None = ..., ) -> NDFrameT: ... @overload def get_groupby( obj: Series, - by: KeysArgType | None = None, - axis: int = 0, - grouper: ops.BaseGrouper | None = None, - group_keys: bool = True, + by: KeysArgType | None = ..., + axis: int = ..., + grouper: ops.BaseGrouper | None = ..., + group_keys: bool = ..., ) -> generic.SeriesGroupBy: ... @overload def get_groupby( obj: DataFrame, - by: KeysArgType | None = None, - axis: int = 0, - grouper: ops.BaseGrouper | None = None, - group_keys: bool = True, + by: KeysArgType | None = ..., + axis: int = ..., + grouper: ops.BaseGrouper | None = ..., + group_keys: bool = ..., ) -> generic.DataFrameGroupBy: ... diff --git a/pandas-stubs/core/groupby/grouper.pyi b/pandas-stubs/core/groupby/grouper.pyi index 5f42d6ca6..b3ebb9d0c 100644 --- a/pandas-stubs/core/groupby/grouper.pyi +++ b/pandas-stubs/core/groupby/grouper.pyi @@ -15,10 +15,7 @@ from pandas import ( ) from pandas.core.groupby.ops import BaseGrouper from pandas.core.resample import TimeGrouper -from typing_extensions import ( - Self, - deprecated, -) +from typing_extensions import Self from pandas._libs.lib import NoDefault from pandas._typing import ( @@ -45,38 +42,23 @@ class Grouper: @overload def __new__( cls, - key: KeysArgType | None = None, - level: Level | ListLikeHashable[Level] | None = None, + key: KeysArgType | None = ..., + level: Level | ListLikeHashable[Level] | None = ..., axis: Axis | NoDefault = ..., - sort: bool = False, - dropna: bool = True, + sort: bool = ..., + dropna: bool = ..., ) -> Self: ... @overload def __new__(cls, *args, freq: Frequency, **kwargs) -> TimeGrouper: ... def __init__( self, - key: KeysArgType | None = None, - level: Level | ListLikeHashable[Level] | None = None, - freq: Frequency | None = None, + key: KeysArgType | None = ..., + level: Level | ListLikeHashable[Level] | None = ..., + freq: Frequency | None = ..., axis: Axis | NoDefault = ..., - sort: bool = False, - dropna: bool = True, + sort: bool = ..., + dropna: bool = ..., ) -> None: ... - @property - @deprecated("Grouper.ax is deprecated. Use Resampler.ax instead.") - def ax(self): ... - @property - @deprecated("Grouper.indexer is deprecated. Use Resampler.indexer instead.") - def indexer(self): ... - @property - @deprecated("Grouper.obj is deprecated. Use GroupBy.obj instead.") - def obj(self): ... - @property - @deprecated("Grouper.grouper is deprecated. Use GroupBy.grouper instead.") - def grouper(self): ... - @property - @deprecated("Grouper.groups is deprecated. Use GroupBy.groups instead.") - def groups(self): ... @final def __repr__(self) -> str: ... # noqa: PYI029 __repr__ here is final @@ -89,14 +71,14 @@ class Grouping: def __init__( self, index: Index, - grouper=None, - obj: DataFrame | Series | None = None, - level: Level | None = None, - sort: bool = True, - observed: bool = False, - in_axis: bool = False, - dropna: bool = True, - uniques: ArrayLike | None = None, + grouper=..., + obj: DataFrame | Series | None = ..., + level: Level | None = ..., + sort: bool = ..., + observed: bool = ..., + in_axis: bool = ..., + dropna: bool = ..., + uniques: ArrayLike | None = ..., ) -> None: ... def __iter__(self) -> Iterator[Hashable]: ... @cache_readonly @@ -118,11 +100,11 @@ class Grouping: def get_grouper( obj: NDFrameT, - key: KeysArgType | None = None, - axis: Axis = 0, - level: Level | ListLikeHashable[Level] | None = None, - sort: bool = True, - observed: bool = False, - validate: bool = True, - dropna: bool = True, + key: KeysArgType | None = ..., + axis: Axis = ..., + level: Level | ListLikeHashable[Level] | None = ..., + sort: bool = ..., + observed: bool = ..., + validate: bool = ..., + dropna: bool = ..., ) -> tuple[BaseGrouper, frozenset[Hashable], NDFrameT]: ... diff --git a/pandas-stubs/core/groupby/indexing.pyi b/pandas-stubs/core/groupby/indexing.pyi index 2532b3d4a..b50ca7085 100644 --- a/pandas-stubs/core/groupby/indexing.pyi +++ b/pandas-stubs/core/groupby/indexing.pyi @@ -29,6 +29,6 @@ class GroupByNthSelector(Generic[_GroupByT]): def __call__( self, n: PositionalIndexer | tuple, - dropna: Literal["any", "all", None] = None, + dropna: Literal["any", "all", None] = ..., ) -> DataFrame | Series: ... def __getitem__(self, n: PositionalIndexer | tuple) -> DataFrame | Series: ... diff --git a/pandas-stubs/core/groupby/ops.pyi b/pandas-stubs/core/groupby/ops.pyi index 38cd81034..b5ac25cfd 100644 --- a/pandas-stubs/core/groupby/ops.pyi +++ b/pandas-stubs/core/groupby/ops.pyi @@ -48,7 +48,7 @@ class WrappedCythonOp: *, values: ArrayLike, axis: AxisInt, - min_count: int = -1, + min_count: int = ..., comp_ids: np.ndarray, ngroups: int, **kwargs, @@ -61,8 +61,8 @@ class BaseGrouper: self, axis: Index, groupings: Sequence[grouper.Grouping], - sort: bool = True, - dropna: bool = True, + sort: bool = ..., + dropna: bool = ..., ) -> None: ... @property def groupings(self) -> list[grouper.Grouping]: ... @@ -72,7 +72,7 @@ class BaseGrouper: @property def nkeys(self) -> int: ... def get_iterator( - self, data: NDFrameT, axis: AxisInt = 0 + self, data: NDFrameT, axis: AxisInt = ... ) -> Iterator[tuple[Hashable, NDFrameT]]: ... @final @cache_readonly @@ -116,11 +116,11 @@ class BaseGrouper: self, obj: Series, func: Callable[[Series], object], - preserve_dtype: bool = False, + preserve_dtype: bool = ..., ) -> ArrayLike: ... @final def apply_groupwise( - self, f: Callable[[NDFrameT], T], data: NDFrameT, axis: AxisInt = 0 + self, f: Callable[[NDFrameT], T], data: NDFrameT, axis: AxisInt = ... ) -> tuple[list[T], bool]: ... class BinGrouper(BaseGrouper): @@ -131,7 +131,7 @@ class BinGrouper(BaseGrouper): self, bins: ArrayLike | AnyArrayLike | Sequence[int], binlabels: Axes, - indexer: npt.NDArray[np.intp] | None = None, + indexer: npt.NDArray[np.intp] | None = ..., ) -> None: ... @cache_readonly def indices(self) -> dict[Incomplete, list[int]]: ... # type: ignore[override] # pyright: ignore @@ -149,7 +149,7 @@ class DataSplitter(Generic[NDFrameT]): *, sort_idx: npt.NDArray[np.intp], sorted_ids: npt.NDArray[np.intp], - axis: AxisInt = 0, + axis: AxisInt = ..., ) -> None: ... def __iter__(self) -> Iterator[NDFrameT]: ... diff --git a/pandas-stubs/core/resample.pyi b/pandas-stubs/core/resample.pyi index d79e6f166..849275ce1 100644 --- a/pandas-stubs/core/resample.pyi +++ b/pandas-stubs/core/resample.pyi @@ -79,25 +79,25 @@ class Resampler(BaseGroupBy[NDFrameT]): self, obj: NDFrameT, timegrouper: TimeGrouper, - axis: Axis = 0, - kind: str | None = None, + axis: Axis = ..., + kind: str | None = ..., *, gpr_index: Index, - group_keys: bool = False, - selection: IndexLabel | None = None, + group_keys: bool = ..., + selection: IndexLabel | None = ..., ) -> None: ... def __getattr__(self, attr: str) -> SeriesGroupBy: ... @overload def aggregate( self: Resampler[DataFrame], - func: _FrameGroupByFuncArgs | None = None, + func: _FrameGroupByFuncArgs | None = ..., *args, **kwargs, ) -> DataFrame: ... @overload def aggregate( self: Resampler[Series], - func: _SeriesGroupByFuncArgs | None = None, + func: _SeriesGroupByFuncArgs | None = ..., *args, **kwargs, ) -> Series | DataFrame: ... @@ -111,67 +111,67 @@ class Resampler(BaseGroupBy[NDFrameT]): def transform( self: Resampler[DataFrame], arg: Callable[[Series], Series[S1]], *args, **kwargs ) -> DataFrame: ... - def ffill(self, limit: int | None = None) -> NDFrameT: ... - def nearest(self, limit: int | None = None) -> NDFrameT: ... - def bfill(self, limit: int | None = None) -> NDFrameT: ... + def ffill(self, limit: int | None = ...) -> NDFrameT: ... + def nearest(self, limit: int | None = ...) -> NDFrameT: ... + def bfill(self, limit: int | None = ...) -> NDFrameT: ... def fillna( - self, method: Literal[FillnaOptions, "nearest"], limit: int | None = None + self, method: Literal[FillnaOptions, "nearest"], limit: int | None = ... ) -> NDFrameT: ... @overload def interpolate( self, - method: InterpolateOptions = "linear", + method: InterpolateOptions = ..., *, - axis: Axis = 0, - limit: int | None = None, + axis: Axis = ..., + limit: int | None = ..., inplace: Literal[True], - limit_direction: Literal["forward", "backward", "both"] = "forward", - limit_area: Literal["inside", "outside"] | None = None, + limit_direction: Literal["forward", "backward", "both"] = ..., + limit_area: Literal["inside", "outside"] | None = ..., downcast: Literal["infer"] | None | NoDefault = ..., **kwargs, ) -> None: ... @overload def interpolate( self, - method: InterpolateOptions = "linear", + method: InterpolateOptions = ..., *, - axis: Axis = 0, - limit: int | None = None, - inplace: Literal[False] = False, - limit_direction: Literal["forward", "backward", "both"] = "forward", - limit_area: Literal["inside", "outside"] | None = None, + axis: Axis = ..., + limit: int | None = ..., + inplace: Literal[False] = ..., + limit_direction: Literal["forward", "backward", "both"] = ..., + limit_area: Literal["inside", "outside"] | None = ..., downcast: Literal["infer"] | None | NoDefault = ..., **kwargs, ) -> NDFrameT: ... - def asfreq(self, fill_value: Scalar | None = None) -> NDFrameT: ... + def asfreq(self, fill_value: Scalar | None = ...) -> NDFrameT: ... def sum( - self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs + self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs ) -> NDFrameT: ... def prod( - self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs + self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs ) -> NDFrameT: ... def min( - self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs + self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs ) -> NDFrameT: ... def max( - self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs + self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs ) -> NDFrameT: ... def first( - self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs + self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs ) -> NDFrameT: ... def last( - self, numeric_only: bool = False, min_count: int = 0, *args, **kwargs + self, numeric_only: bool = ..., min_count: int = ..., *args, **kwargs ) -> NDFrameT: ... - def median(self, numeric_only: bool = False, *args, **kwargs) -> NDFrameT: ... - def mean(self, numeric_only: bool = False, *args, **kwargs) -> NDFrameT: ... + def median(self, numeric_only: bool = ..., *args, **kwargs) -> NDFrameT: ... + def mean(self, numeric_only: bool = ..., *args, **kwargs) -> NDFrameT: ... def std( - self, ddof: int = 1, numeric_only: bool = False, *args, **kwargs + self, ddof: int = ..., numeric_only: bool = ..., *args, **kwargs ) -> NDFrameT: ... def var( - self, ddof: int = 1, numeric_only: bool = False, *args, **kwargs + self, ddof: int = ..., numeric_only: bool = ..., *args, **kwargs ) -> NDFrameT: ... def sem( - self, ddof: int = 1, numeric_only: bool = False, *args, **kwargs + self, ddof: int = ..., numeric_only: bool = ..., *args, **kwargs ) -> NDFrameT: ... def ohlc(self, *args, **kwargs) -> DataFrame: ... @overload @@ -185,7 +185,7 @@ class Resampler(BaseGroupBy[NDFrameT]): def count(self: Resampler[DataFrame]) -> DataFrame: ... def quantile( self, - q: float | list[float] | npt.NDArray[np.float_] | Series[float] = 0.5, + q: float | list[float] | npt.NDArray[np.float_] | Series[float] = ..., **kwargs, ) -> NDFrameT: ... @@ -198,8 +198,8 @@ class _GroupByMixin(Resampler[NDFrameT]): *, parent: Resampler, groupby: GroupBy, - key=None, - selection: IndexLabel | None = None, + key=..., + selection: IndexLabel | None = ..., ) -> None: ... def __getitem__(self, key) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] @@ -232,39 +232,39 @@ _ResamplerGroupBy: TypeAlias = ( def get_resampler( obj: NDFrameT, - kind: Literal["period", "timestamp", "timedelta"] | None = None, + kind: Literal["period", "timestamp", "timedelta"] | None = ..., *, # Keyword argumentsmust be kept roughly inline with TimeGrouper.__init__ below - freq: Frequency = "Min", - closed: Literal["left", "right"] | None = None, - label: Literal["left", "right"] | None = None, - how: str = "mean", - axis: Axis = 0, - fill_method: str | None = None, - limit: int | None = None, - convention: TimestampConvention | None = None, - origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", - offset: TimedeltaConvertibleTypes | None = None, - group_keys: bool = False, + freq: Frequency = ..., + closed: Literal["left", "right"] | None = ..., + label: Literal["left", "right"] | None = ..., + how: str = ..., + axis: Axis = ..., + fill_method: str | None = ..., + limit: int | None = ..., + convention: TimestampConvention | None = ..., + origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., + offset: TimedeltaConvertibleTypes | None = ..., + group_keys: bool = ..., **kwds, ) -> DatetimeIndexResampler[NDFrameT]: ... def get_resampler_for_grouping( groupby: GroupBy[NDFrameT], rule: Frequency, - how: str | None = None, - fill_method: str | None = None, - limit: int | None = None, - kind: Literal["period", "timestamp", "timedelta"] | None = None, - on: Hashable | None = None, + how: str | None = ..., + fill_method: str | None = ..., + limit: int | None = ..., + kind: Literal["period", "timestamp", "timedelta"] | None = ..., + on: Hashable | None = ..., *, # Keyword argumentsmust be kept roughly inline with TimeGrouper.__init__ below - closed: Literal["left", "right"] | None = None, - label: Literal["left", "right"] | None = None, - axis: Axis = 0, - convention: TimestampConvention | None = None, - origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", - offset: TimedeltaConvertibleTypes | None = None, - group_keys: bool = False, + closed: Literal["left", "right"] | None = ..., + label: Literal["left", "right"] | None = ..., + axis: Axis = ..., + convention: TimestampConvention | None = ..., + origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., + offset: TimedeltaConvertibleTypes | None = ..., + group_keys: bool = ..., **kwargs, ) -> _ResamplerGroupBy[NDFrameT]: ... @@ -282,26 +282,26 @@ class TimeGrouper(Grouper): def __init__( self, - freq: Frequency = "Min", - closed: Literal["left", "right"] | None = None, - label: Literal["left", "right"] | None = None, - how: str = "mean", - axis: Axis = 0, - fill_method: str | None = None, - limit: int | None = None, - kind: Literal["period", "timestamp", "timedelta"] | None = None, - convention: TimestampConvention | None = None, - origin: TimeGrouperOrigin | TimestampConvertibleTypes = "start_day", - offset: TimedeltaConvertibleTypes | None = None, - group_keys: bool = False, + freq: Frequency = ..., + closed: Literal["left", "right"] | None = ..., + label: Literal["left", "right"] | None = ..., + how: str = ..., + axis: Axis = ..., + fill_method: str | None = ..., + limit: int | None = ..., + kind: Literal["period", "timestamp", "timedelta"] | None = ..., + convention: TimestampConvention | None = ..., + origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., + offset: TimedeltaConvertibleTypes | None = ..., + group_keys: bool = ..., **kwargs, ) -> None: ... def asfreq( obj: NDFrameT, freq: Frequency, - method: Literal[FillnaOptions, "nearest"] | None = None, - how: str | None = None, - normalize: bool = False, - fill_value: Scalar | None = None, + method: Literal[FillnaOptions, "nearest"] | None = ..., + how: str | None = ..., + normalize: bool = ..., + fill_value: Scalar | None = ..., ) -> NDFrameT: ... diff --git a/pandas-stubs/core/series.pyi b/pandas-stubs/core/series.pyi index 26b952a0e..ab963e52a 100644 --- a/pandas-stubs/core/series.pyi +++ b/pandas-stubs/core/series.pyi @@ -634,7 +634,7 @@ class Series(IndexOpsMixin[S1], NDFrame): @overload def groupby( self, - by: None = None, + by: None = ..., axis: AxisIndex = ..., *, level: IndexLabel, # level is required when by=None (passed as keyword) diff --git a/pandas-stubs/core/window/ewm.pyi b/pandas-stubs/core/window/ewm.pyi index b2cff4b89..14401a2e6 100644 --- a/pandas-stubs/core/window/ewm.pyi +++ b/pandas-stubs/core/window/ewm.pyi @@ -22,92 +22,92 @@ class ExponentialMovingWindow(BaseWindow[NDFrameT]): def __init__( self, obj: NDFrameT, - com: float | None = None, - span: float | None = None, - halflife: TimedeltaConvertibleTypes | None = None, - alpha: float | None = None, - min_periods: int | None = 0, - adjust: bool = True, - ignore_na: bool = False, - axis: Axis = 0, - times: str | np.ndarray | Series | np.timedelta64 | None = None, - method: CalculationMethod = "single", + com: float | None = ..., + span: float | None = ..., + halflife: TimedeltaConvertibleTypes | None = ..., + alpha: float | None = ..., + min_periods: int | None = ..., + adjust: bool = ..., + ignore_na: bool = ..., + axis: Axis = ..., + times: str | np.ndarray | Series | None | np.timedelta64 = ..., + method: CalculationMethod = ..., *, - selection: IndexLabel | None = None, + selection: IndexLabel | None = ..., ) -> None: ... def online( self, - engine: WindowingEngine = "numba", - engine_kwargs: WindowingEngineKwargs = None, + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> OnlineExponentialMovingWindow[NDFrameT]: ... def mean( self, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... def sum( self, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... - def std(self, bias: bool = False, numeric_only: bool = False) -> NDFrameT: ... - def var(self, bias: bool = False, numeric_only: bool = False) -> NDFrameT: ... + def std(self, bias: bool = ..., numeric_only: bool = ...) -> NDFrameT: ... + def var(self, bias: bool = ..., numeric_only: bool = ...) -> NDFrameT: ... def cov( self, - other: DataFrame | Series | None = None, - pairwise: bool | None = None, - bias: bool = False, - numeric_only: bool = False, + other: DataFrame | Series | None = ..., + pairwise: bool | None = ..., + bias: bool = ..., + numeric_only: bool = ..., ) -> NDFrameT: ... def corr( self, - other: DataFrame | Series | None = None, - pairwise: bool | None = None, - numeric_only: bool = False, + other: DataFrame | Series | None = ..., + pairwise: bool | None = ..., + numeric_only: bool = ..., ) -> NDFrameT: ... class ExponentialMovingWindowGroupby( BaseWindowGroupby[NDFrameT], ExponentialMovingWindow[NDFrameT] ): - def __init__(self, obj, *args, _grouper=None, **kwargs) -> None: ... + def __init__(self, obj, *args, _grouper=..., **kwargs) -> None: ... class OnlineExponentialMovingWindow(ExponentialMovingWindow[NDFrameT]): def __init__( self, obj: NDFrameT, - com: float | None = None, - span: float | None = None, - halflife: float | TimedeltaConvertibleTypes | None = None, - alpha: float | None = None, - min_periods: int | None = 0, - adjust: bool = True, - ignore_na: bool = False, - axis: Axis = 0, - times: np.ndarray | NDFrameT | None = None, - engine: WindowingEngine = "numba", - engine_kwargs: WindowingEngineKwargs = None, + com: float | None = ..., + span: float | None = ..., + halflife: float | TimedeltaConvertibleTypes | None = ..., + alpha: float | None = ..., + min_periods: int | None = ..., + adjust: bool = ..., + ignore_na: bool = ..., + axis: Axis = ..., + times: np.ndarray | NDFrameT | None = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., *, - selection: IndexLabel | None = None, + selection: IndexLabel | None = ..., ) -> None: ... def reset(self) -> None: ... def aggregate(self, func, *args, **kwargs): ... - def std(self, bias: bool = False, *args, **kwargs): ... + def std(self, bias: bool = ..., *args, **kwargs): ... def corr( self, - other: DataFrame | Series | None = None, - pairwise: bool | None = None, - numeric_only: bool = False, + other: DataFrame | Series | None = ..., + pairwise: bool | None = ..., + numeric_only: bool = ..., ): ... def cov( self, - other: DataFrame | Series | None = None, - pairwise: bool | None = None, - bias: bool = False, - numeric_only: bool = False, + other: DataFrame | Series | None = ..., + pairwise: bool | None = ..., + bias: bool = ..., + numeric_only: bool = ..., ): ... - def var(self, bias: bool = False, numeric_only: bool = False): ... + def var(self, bias: bool = ..., numeric_only: bool = ...): ... def mean( - self, *args, update: NDFrameT | None = None, update_times: None = None, **kwargs + self, *args, update: NDFrameT | None = ..., update_times: None = ..., **kwargs ) -> NDFrameT: ... diff --git a/pandas-stubs/core/window/expanding.pyi b/pandas-stubs/core/window/expanding.pyi index a8777a076..60ebfd4f0 100644 --- a/pandas-stubs/core/window/expanding.pyi +++ b/pandas-stubs/core/window/expanding.pyi @@ -13,10 +13,10 @@ class Expanding(RollingAndExpandingMixin[NDFrameT]): def __init__( self, obj: NDFrameT, - min_periods: int = 1, - axis: Axis = 0, - method: str = "single", - selection: IndexLabel | None = None, + min_periods: int = ..., + axis: Axis = ..., + method: str = ..., + selection: IndexLabel | None = ..., ) -> None: ... class ExpandingGroupby(BaseWindowGroupby[NDFrameT], Expanding[NDFrameT]): ... diff --git a/pandas-stubs/core/window/rolling.pyi b/pandas-stubs/core/window/rolling.pyi index 34c1e11e6..a0ebcdcc5 100644 --- a/pandas-stubs/core/window/rolling.pyi +++ b/pandas-stubs/core/window/rolling.pyi @@ -49,17 +49,17 @@ class BaseWindow(SelectionMixin[NDFrameT]): def __init__( self, obj: NDFrameT, - window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = None, - min_periods: int | None = None, - center: bool | None = False, - win_type: str | None = None, - axis: Axis = 0, - on: str | Index | None = None, - closed: IntervalClosedType | None = None, - step: int | None = None, - method: CalculationMethod = "single", + window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = ..., + min_periods: int | None = ..., + center: bool | None = ..., + win_type: str | None = ..., + axis: Axis = ..., + on: str | Index | None = ..., + closed: IntervalClosedType | None = ..., + step: int | None = ..., + method: CalculationMethod = ..., *, - selection: IndexLabel | None = None, + selection: IndexLabel | None = ..., ) -> None: ... def __getitem__(self, key) -> Self: ... def __getattr__(self, attr: str) -> Self: ... @@ -88,115 +88,115 @@ class BaseWindowGroupby(BaseWindow[NDFrameT]): def __init__( self, obj: NDFrameT, - window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = None, - min_periods: int | None = None, - center: bool | None = False, - win_type: str | None = None, - axis: Axis = 0, - on: str | Index | None = None, - closed: IntervalClosedType | None = None, - step: int | None = None, - method: CalculationMethod = "single", + window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = ..., + min_periods: int | None = ..., + center: bool | None = ..., + win_type: str | None = ..., + axis: Axis = ..., + on: str | Index | None = ..., + closed: IntervalClosedType | None = ..., + step: int | None = ..., + method: CalculationMethod = ..., *, - selection: IndexLabel | None = None, + selection: IndexLabel | None = ..., _grouper: BaseGrouper, - _as_index: bool = True, + _as_index: bool = ..., ) -> None: ... class Window(BaseWindow[NDFrameT]): - def sum(self, numeric_only: bool = False, **kwargs: Any) -> NDFrameT: ... - def mean(self, numeric_only: bool = False, **kwargs: Any) -> NDFrameT: ... + def sum(self, numeric_only: bool = ..., **kwargs: Any) -> NDFrameT: ... + def mean(self, numeric_only: bool = ..., **kwargs: Any) -> NDFrameT: ... def var( - self, ddof: int = 1, numeric_only: bool = False, **kwargs: Any + self, ddof: int = ..., numeric_only: bool = ..., **kwargs: Any ) -> NDFrameT: ... def std( - self, ddof: int = 1, numeric_only: bool = False, **kwargs: Any + self, ddof: int = ..., numeric_only: bool = ..., **kwargs: Any ) -> NDFrameT: ... class RollingAndExpandingMixin(BaseWindow[NDFrameT]): - def count(self, numeric_only: bool = False) -> NDFrameT: ... + def count(self, numeric_only: bool = ...) -> NDFrameT: ... def apply( self, func: Callable[..., Any], - raw: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, - args: tuple[Any, ...] | None = None, - kwargs: dict[str, Any] | None = None, + raw: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., + args: tuple[Any, ...] | None = ..., + kwargs: dict[str, Any] | None = ..., ) -> NDFrameT: ... def sum( self, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... def max( self, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... def min( self, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... def mean( self, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... def median( self, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... def std( self, - ddof: int = 1, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + ddof: int = ..., + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... def var( self, - ddof: int = 1, - numeric_only: bool = False, - engine: WindowingEngine = None, - engine_kwargs: WindowingEngineKwargs = None, + ddof: int = ..., + numeric_only: bool = ..., + engine: WindowingEngine = ..., + engine_kwargs: WindowingEngineKwargs = ..., ) -> NDFrameT: ... - def skew(self, numeric_only: bool = False) -> NDFrameT: ... - def sem(self, ddof: int = 1, numeric_only: bool = False) -> NDFrameT: ... - def kurt(self, numeric_only: bool = False) -> NDFrameT: ... + def skew(self, numeric_only: bool = ...) -> NDFrameT: ... + def sem(self, ddof: int = ..., numeric_only: bool = ...) -> NDFrameT: ... + def kurt(self, numeric_only: bool = ...) -> NDFrameT: ... def quantile( self, q: float, - interpolation: QuantileInterpolation = "linear", - numeric_only: bool = False, + interpolation: QuantileInterpolation = ..., + numeric_only: bool = ..., ) -> NDFrameT: ... def rank( self, - method: WindowingRankType = "average", - ascending: bool = True, - pct: bool = False, - numeric_only: bool = False, + method: WindowingRankType = ..., + ascending: bool = ..., + pct: bool = ..., + numeric_only: bool = ..., ) -> NDFrameT: ... def cov( self, - other: DataFrame | Series | None = None, - pairwise: bool | None = None, - ddof: int = 1, - numeric_only: bool = False, + other: DataFrame | Series | None = ..., + pairwise: bool | None = ..., + ddof: int = ..., + numeric_only: bool = ..., ) -> NDFrameT: ... def corr( self, - other: DataFrame | Series | None = None, - pairwise: bool | None = None, - ddof: int = 1, - numeric_only: bool = False, + other: DataFrame | Series | None = ..., + pairwise: bool | None = ..., + ddof: int = ..., + numeric_only: bool = ..., ) -> NDFrameT: ... class Rolling(RollingAndExpandingMixin[NDFrameT]): ... diff --git a/pandas-stubs/plotting/_core.pyi b/pandas-stubs/plotting/_core.pyi index 7fb300cb5..a79e74523 100644 --- a/pandas-stubs/plotting/_core.pyi +++ b/pandas-stubs/plotting/_core.pyi @@ -87,49 +87,49 @@ def boxplot( @overload def boxplot_frame_groupby( grouped, - subplots: Literal[True] = True, - column: IndexLabel | None = None, - fontsize: float | str | None = None, - rot: float = 0, - grid: bool = True, - ax: Axes | None = None, - figsize: tuple[float, float] | None = None, - layout: tuple[int, int] | None = None, - sharex: bool = False, - sharey: bool = True, - backend: str | None = None, + subplots: Literal[True] = ..., + column: IndexLabel | None = ..., + fontsize: float | str | None = ..., + rot: float = ..., + grid: bool = ..., + ax: Axes | None = ..., + figsize: tuple[float, float] | None = ..., + layout: tuple[int, int] | None = ..., + sharex: bool = ..., + sharey: bool = ..., + backend: str | None = ..., **kwargs, ) -> Series: ... # Series[Axes] but this is not allowed @overload def boxplot_frame_groupby( grouped, subplots: Literal[False], - column: IndexLabel | None = None, - fontsize: float | str | None = None, - rot: float = 0, - grid: bool = True, - ax: Axes | None = None, - figsize: tuple[float, float] | None = None, - layout: tuple[int, int] | None = None, - sharex: bool = False, - sharey: bool = True, - backend: str | None = None, + column: IndexLabel | None = ..., + fontsize: float | str | None = ..., + rot: float = ..., + grid: bool = ..., + ax: Axes | None = ..., + figsize: tuple[float, float] | None = ..., + layout: tuple[int, int] | None = ..., + sharex: bool = ..., + sharey: bool = ..., + backend: str | None = ..., **kwargs, ) -> Axes: ... @overload def boxplot_frame_groupby( grouped, subplots: bool, - column: IndexLabel | None = None, - fontsize: float | str | None = None, - rot: float = 0, - grid: bool = True, - ax: Axes | None = None, - figsize: tuple[float, float] | None = None, - layout: tuple[int, int] | None = None, - sharex: bool = False, - sharey: bool = True, - backend: str | None = None, + column: IndexLabel | None = ..., + fontsize: float | str | None = ..., + rot: float = ..., + grid: bool = ..., + ax: Axes | None = ..., + figsize: tuple[float, float] | None = ..., + layout: tuple[int, int] | None = ..., + sharex: bool = ..., + sharey: bool = ..., + backend: str | None = ..., **kwargs, ) -> Axes | Series: ... # Series[Axes] diff --git a/pandas-stubs/util/_decorators.pyi b/pandas-stubs/util/_decorators.pyi index e06f16afc..0e1a1f1ff 100644 --- a/pandas-stubs/util/_decorators.pyi +++ b/pandas-stubs/util/_decorators.pyi @@ -25,22 +25,22 @@ def deprecate( name: str, alternative: Callable[..., Any], version: str, - alt_name: str | None = None, - klass: type[Warning] | None = None, - stacklevel: int = 2, - msg: str | None = None, + alt_name: str | None = ..., + klass: type[Warning] | None = ..., + stacklevel: int = ..., + msg: str | None = ..., ) -> Callable[[F], F]: ... def deprecate_kwarg( old_arg_name: str, new_arg_name: str | None, - mapping: Mapping[Any, Any] | Callable[[Any], Any] | None = None, - stacklevel: int = 2, + mapping: Mapping[Any, Any] | Callable[[Any], Any] | None = ..., + stacklevel: int = ..., ) -> Callable[[F], F]: ... def future_version_msg(version: str | None) -> str: ... def deprecate_nonkeyword_arguments( version: str | None, - allowed_args: list[str] | None = None, - name: str | None = None, + allowed_args: list[str] | None = ..., + name: str | None = ..., ) -> Callable[[F], F]: ... def doc(*docstrings: str | Callable | None, **params) -> Callable[[F], F]: ... @@ -55,7 +55,7 @@ class Appender: join: str def __init__( - self, addendum: str | None, join: str = "", indents: int = 0 + self, addendum: str | None, join: str = ..., indents: int = ... ) -> None: ... def __call__(self, func: T) -> T: ... From 50a2477e0d925db16cc647a2675c1ad774000d16 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 09:34:46 +0100 Subject: [PATCH 04/23] Use np.integer in tests --- tests/test_groupby.py | 8 ++++---- tests/test_resampler.py | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/test_groupby.py b/tests/test_groupby.py index cea05d5df..b2fa84f02 100644 --- a/tests/test_groupby.py +++ b/tests/test_groupby.py @@ -86,7 +86,7 @@ def test_frame_groupby_resample() -> None: check(assert_type(GB_DF.resample(M).var(2), DataFrame), DataFrame) # size / count - check(assert_type(GB_DF.resample(M).size(), "Series[int]"), Series, np.int64) + check(assert_type(GB_DF.resample(M).size(), "Series[int]"), Series, np.integer) check(assert_type(GB_DF.resample(M).count(), DataFrame), DataFrame) # filling @@ -264,7 +264,7 @@ def test_series_groupby_resample() -> None: check(assert_type(GB_S.resample(M).sum(), "Series[float]"), Series, float) check(assert_type(GB_S.resample(M).median(), "Series[float]"), Series, float) check(assert_type(GB_S.resample(M).ohlc(), DataFrame), DataFrame) - check(assert_type(GB_S.resample(M).nunique(), "Series[int]"), Series, np.int64) + check(assert_type(GB_S.resample(M).nunique(), "Series[int]"), Series, np.integer) # quantile check(assert_type(GB_S.resample(M).quantile(0.5), "Series[float]"), Series, float) @@ -283,8 +283,8 @@ def test_series_groupby_resample() -> None: check(assert_type(GB_S.resample(M).var(2), "Series[float]"), Series, float) # size / count - check(assert_type(GB_S.resample(M).size(), "Series[int]"), Series, np.int64) - check(assert_type(GB_S.resample(M).count(), "Series[int]"), Series, np.int64) + check(assert_type(GB_S.resample(M).size(), "Series[int]"), Series, np.integer) + check(assert_type(GB_S.resample(M).count(), "Series[int]"), Series, np.integer) # filling check(assert_type(GB_S.resample(M).ffill(), "Series[float]"), Series, float) diff --git a/tests/test_resampler.py b/tests/test_resampler.py index f5681adfa..62eda2b84 100644 --- a/tests/test_resampler.py +++ b/tests/test_resampler.py @@ -83,7 +83,7 @@ def test_std_var() -> None: def test_size_count() -> None: - check(assert_type(DF.resample(MonthFreq).size(), "Series[int]"), Series, np.int64) + check(assert_type(DF.resample(MonthFreq).size(), "Series[int]"), Series, np.integer) check(assert_type(DF.resample(MonthFreq).count(), DataFrame), DataFrame) @@ -311,7 +311,9 @@ def test_agg_funcs_series() -> None: check(assert_type(S.resample(MonthFreq).sum(), Series), Series) check(assert_type(S.resample(MonthFreq).median(), Series), Series) check(assert_type(S.resample(MonthFreq).ohlc(), DataFrame), DataFrame) - check(assert_type(S.resample(MonthFreq).nunique(), "Series[int]"), Series, np.int64) + check( + assert_type(S.resample(MonthFreq).nunique(), "Series[int]"), Series, np.integer + ) def test_quantile_series() -> None: @@ -329,8 +331,8 @@ def test_std_var_series() -> None: def test_size_count_series() -> None: - check(assert_type(S.resample(MonthFreq).size(), "Series[int]"), Series, np.int64) - check(assert_type(S.resample(MonthFreq).count(), "Series[int]"), Series, np.int64) + check(assert_type(S.resample(MonthFreq).size(), "Series[int]"), Series, np.integer) + check(assert_type(S.resample(MonthFreq).count(), "Series[int]"), Series, np.integer) def test_filling_series() -> None: From b9271da8c71d9b9d4db8f64675ea856b197ae59a Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 09:39:15 +0100 Subject: [PATCH 05/23] Add a comment for Incomplete --- pandas-stubs/_typing.pyi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pandas-stubs/_typing.pyi b/pandas-stubs/_typing.pyi index 26781e941..89a7cbe72 100644 --- a/pandas-stubs/_typing.pyi +++ b/pandas-stubs/_typing.pyi @@ -48,6 +48,9 @@ from pandas.core.dtypes.dtypes import ( from pandas.io.formats.format import EngFormatter +# `Incomplete` is equivalent to `Any`. Use it to annotate symbols that you don't +# know the type of yet and that should be changed in the future. Use `Any` only +# where it is the only acceptable type. Incomplete: TypeAlias = Any ArrayLike: TypeAlias = ExtensionArray | np.ndarray From a8a71c1689a98c6872c0a72fc3c8aa166195803c Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 09:46:18 +0100 Subject: [PATCH 06/23] Remove private objects --- pandas-stubs/core/apply.pyi | 16 +++--- pandas-stubs/core/base.pyi | 2 - pandas-stubs/core/groupby/base.pyi | 7 --- pandas-stubs/core/groupby/categorical.pyi | 5 -- pandas-stubs/core/groupby/generic.pyi | 2 - pandas-stubs/core/groupby/groupby.pyi | 39 ++++++--------- pandas-stubs/core/groupby/grouper.pyi | 13 ----- pandas-stubs/core/groupby/ops.pyi | 28 ----------- pandas-stubs/core/resample.pyi | 44 ---------------- pandas-stubs/util/_decorators.pyi | 61 ----------------------- tests/test_groupby.py | 2 +- 11 files changed, 23 insertions(+), 196 deletions(-) diff --git a/pandas-stubs/core/apply.pyi b/pandas-stubs/core/apply.pyi index 5cc66600c..c080f12f5 100644 --- a/pandas-stubs/core/apply.pyi +++ b/pandas-stubs/core/apply.pyi @@ -43,8 +43,6 @@ _AggResamplerWindowObjT = TypeVar( "_AggResamplerWindowObjT", bound=BaseWindow | Resampler ) -ResType = dict[int, Any] # noqa: PYI026 - def frame_apply( obj: DataFrame, func: AggFuncType, @@ -146,7 +144,7 @@ class FrameApply(NDFrameApply[DataFrame]): @abstractmethod def series_generator(self) -> Iterator[Series]: ... @abstractmethod - def wrap_results_for_axis(self, results: ResType, res_index: Index): ... + def wrap_results_for_axis(self, results: dict[int, Any], res_index: Index): ... @property def res_columns(self) -> Index: ... @property @@ -159,8 +157,8 @@ class FrameApply(NDFrameApply[DataFrame]): def apply_raw(self): ... def apply_broadcast(self, target: DataFrame) -> DataFrame: ... def apply_standard(self): ... - def apply_series_generator(self) -> tuple[ResType, Index]: ... - def wrap_results(self, results: ResType, res_index: Index): ... + def apply_series_generator(self) -> tuple[dict[int, Any], Index]: ... + def wrap_results(self, results: dict[int, Any], res_index: Index): ... def apply_str(self): ... class FrameRowApply(FrameApply): @@ -170,7 +168,7 @@ class FrameRowApply(FrameApply): def result_index(self) -> Index: ... @property def result_columns(self) -> Index: ... - def wrap_results_for_axis(self, results: ResType, res_index: Index): ... + def wrap_results_for_axis(self, results: dict[int, Any], res_index: Index): ... class FrameColumnApply(FrameApply): def apply_broadcast(self, target: DataFrame) -> DataFrame: ... @@ -180,8 +178,10 @@ class FrameColumnApply(FrameApply): def result_index(self) -> Index: ... @property def result_columns(self) -> Index: ... - def wrap_results_for_axis(self, results: ResType, res_index: Index): ... - def infer_to_same_shape(self, results: ResType, res_index: Index) -> DataFrame: ... + def wrap_results_for_axis(self, results: dict[int, Any], res_index: Index): ... + def infer_to_same_shape( + self, results: dict[int, Any], res_index: Index + ) -> DataFrame: ... class SeriesApply(NDFrameApply[Series]): by_row: Literal[False, "compat", "_compat"] diff --git a/pandas-stubs/core/base.pyi b/pandas-stubs/core/base.pyi index c1f36fcfa..5b30bd13d 100644 --- a/pandas-stubs/core/base.pyi +++ b/pandas-stubs/core/base.pyi @@ -26,8 +26,6 @@ from pandas._typing import ( ) from pandas.util._decorators import cache_readonly -class PandasObject: ... - class NoNewAttributesMixin: def __setattr__(self, key: str, value: Any) -> None: ... diff --git a/pandas-stubs/core/groupby/base.pyi b/pandas-stubs/core/groupby/base.pyi index 7de0b07b9..f56b6a324 100644 --- a/pandas-stubs/core/groupby/base.pyi +++ b/pandas-stubs/core/groupby/base.pyi @@ -5,10 +5,3 @@ import dataclasses class OutputKey: label: Hashable position: int - -plotting_methods: frozenset[str] -cythonized_kernels: frozenset[str] -reduction_kernels: frozenset[str] -transformation_kernels: frozenset[str] -groupby_other_methods: frozenset[str] -transform_kernel_allowlist: frozenset[str] diff --git a/pandas-stubs/core/groupby/categorical.pyi b/pandas-stubs/core/groupby/categorical.pyi index bb0fd51a7..e69de29bb 100644 --- a/pandas-stubs/core/groupby/categorical.pyi +++ b/pandas-stubs/core/groupby/categorical.pyi @@ -1,5 +0,0 @@ -from pandas.core.arrays.categorical import Categorical - -def recode_for_groupby( - c: Categorical, sort: bool, observed: bool -) -> tuple[Categorical, Categorical | None]: ... diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 802df6d91..e73c9e69f 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -11,7 +11,6 @@ from typing import ( Generic, Literal, NamedTuple, - TypeVar, final, overload, ) @@ -52,7 +51,6 @@ from pandas._typing import ( from pandas.plotting import boxplot_frame_groupby AggScalar: TypeAlias = str | Callable[..., Any] -ScalarResult = TypeVar("ScalarResult") # noqa: PYI001 class NamedAgg(NamedTuple): column: str diff --git a/pandas-stubs/core/groupby/groupby.pyi b/pandas-stubs/core/groupby/groupby.pyi index df28de8be..527a8673b 100644 --- a/pandas-stubs/core/groupby/groupby.pyi +++ b/pandas-stubs/core/groupby/groupby.pyi @@ -17,10 +17,7 @@ from typing import ( ) import numpy as np -from pandas.core.base import ( - PandasObject, - SelectionMixin, -) +from pandas.core.base import SelectionMixin from pandas.core.frame import DataFrame from pandas.core.groupby import ( generic, @@ -32,7 +29,11 @@ from pandas.core.groupby.indexing import ( ) from pandas.core.indexers import BaseIndexer from pandas.core.indexes.api import Index -from pandas.core.resample import _ResamplerGroupBy +from pandas.core.resample import ( + DatetimeIndexResamplerGroupby, + PeriodIndexResamplerGroupby, + TimedeltaIndexResamplerGroupby, +) from pandas.core.series import Series from pandas.core.window import ( ExpandingGroupby, @@ -58,7 +59,6 @@ from pandas._typing import ( Frequency, IndexLabel, IntervalClosedType, - KeysArgType, MaskType, NDFrameT, P, @@ -86,17 +86,23 @@ _KeysArgType: TypeAlias = ( | Mapping[Hashable, Hashable] ) +_ResamplerGroupBy: TypeAlias = ( + DatetimeIndexResamplerGroupby[NDFrameT] + | PeriodIndexResamplerGroupby[NDFrameT] + | TimedeltaIndexResamplerGroupby[NDFrameT] +) + # GroupByPlot does not really inherit from PlotAccessor but it delegates # to it using __call__ and __getattr__. We lie here to avoid repeating the # whole stub of PlotAccessor @final -class GroupByPlot(PandasObject, PlotAccessor, Generic[_GroupByT]): +class GroupByPlot(PlotAccessor, Generic[_GroupByT]): def __init__(self, groupby: _GroupByT) -> None: ... # The following methods are inherited from the fake parent class PlotAccessor # def __call__(self, *args, **kwargs): ... # def __getattr__(self, name: str): ... -class BaseGroupBy(PandasObject, SelectionMixin[NDFrameT], GroupByIndexingMixin): +class BaseGroupBy(SelectionMixin[NDFrameT], GroupByIndexingMixin): axis: AxisInt grouper: ops.BaseGrouper keys: _KeysArgType | None @@ -417,20 +423,3 @@ class GroupBy(BaseGroupBy[NDFrameT]): weights: Sequence | Series | None = ..., random_state: RandomState | None = ..., ) -> NDFrameT: ... - -@overload -def get_groupby( - obj: Series, - by: KeysArgType | None = ..., - axis: int = ..., - grouper: ops.BaseGrouper | None = ..., - group_keys: bool = ..., -) -> generic.SeriesGroupBy: ... -@overload -def get_groupby( - obj: DataFrame, - by: KeysArgType | None = ..., - axis: int = ..., - grouper: ops.BaseGrouper | None = ..., - group_keys: bool = ..., -) -> generic.DataFrameGroupBy: ... diff --git a/pandas-stubs/core/groupby/grouper.pyi b/pandas-stubs/core/groupby/grouper.pyi index b3ebb9d0c..28042042a 100644 --- a/pandas-stubs/core/groupby/grouper.pyi +++ b/pandas-stubs/core/groupby/grouper.pyi @@ -13,7 +13,6 @@ from pandas import ( Index, Series, ) -from pandas.core.groupby.ops import BaseGrouper from pandas.core.resample import TimeGrouper from typing_extensions import Self @@ -26,7 +25,6 @@ from pandas._typing import ( KeysArgType, Level, ListLikeHashable, - NDFrameT, npt, ) from pandas.util._decorators import cache_readonly @@ -97,14 +95,3 @@ class Grouping: def group_index(self) -> Index: ... @cache_readonly def groups(self) -> dict[Hashable, np.ndarray]: ... - -def get_grouper( - obj: NDFrameT, - key: KeysArgType | None = ..., - axis: Axis = ..., - level: Level | ListLikeHashable[Level] | None = ..., - sort: bool = ..., - observed: bool = ..., - validate: bool = ..., - dropna: bool = ..., -) -> tuple[BaseGrouper, frozenset[Hashable], NDFrameT]: ... diff --git a/pandas-stubs/core/groupby/ops.pyi b/pandas-stubs/core/groupby/ops.pyi index b5ac25cfd..0247b32d1 100644 --- a/pandas-stubs/core/groupby/ops.pyi +++ b/pandas-stubs/core/groupby/ops.pyi @@ -11,7 +11,6 @@ from typing import ( import numpy as np from pandas import ( - DataFrame, Index, Series, ) @@ -30,30 +29,6 @@ from pandas._typing import ( ) from pandas.util._decorators import cache_readonly -def check_result_array(obj, dtype) -> None: ... -def extract_result(res): ... - -class WrappedCythonOp: - cast_blocklist: frozenset[str] - kind: str - how: str - has_dropped_na: bool - - def __init__(self, kind: str, how: str, has_dropped_na: bool) -> None: ... - @classmethod - def get_kind_from_how(cls, how: str) -> str: ... - @final - def cython_operation( - self, - *, - values: ArrayLike, - axis: AxisInt, - min_count: int = ..., - comp_ids: np.ndarray, - ngroups: int, - **kwargs, - ) -> ArrayLike: ... - class BaseGrouper: axis: Index dropna: bool @@ -152,6 +127,3 @@ class DataSplitter(Generic[NDFrameT]): axis: AxisInt = ..., ) -> None: ... def __iter__(self) -> Iterator[NDFrameT]: ... - -class SeriesSplitter(DataSplitter[Series]): ... -class FrameSplitter(DataSplitter[DataFrame]): ... diff --git a/pandas-stubs/core/resample.pyi b/pandas-stubs/core/resample.pyi index 849275ce1..3de8b8c1d 100644 --- a/pandas-stubs/core/resample.pyi +++ b/pandas-stubs/core/resample.pyi @@ -224,50 +224,6 @@ class TimedeltaIndexResamplerGroupby( ): def __getattr__(self, attr: str) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] -_ResamplerGroupBy: TypeAlias = ( - DatetimeIndexResamplerGroupby[NDFrameT] - | PeriodIndexResamplerGroupby[NDFrameT] - | TimedeltaIndexResamplerGroupby[NDFrameT] -) - -def get_resampler( - obj: NDFrameT, - kind: Literal["period", "timestamp", "timedelta"] | None = ..., - *, - # Keyword argumentsmust be kept roughly inline with TimeGrouper.__init__ below - freq: Frequency = ..., - closed: Literal["left", "right"] | None = ..., - label: Literal["left", "right"] | None = ..., - how: str = ..., - axis: Axis = ..., - fill_method: str | None = ..., - limit: int | None = ..., - convention: TimestampConvention | None = ..., - origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., - offset: TimedeltaConvertibleTypes | None = ..., - group_keys: bool = ..., - **kwds, -) -> DatetimeIndexResampler[NDFrameT]: ... -def get_resampler_for_grouping( - groupby: GroupBy[NDFrameT], - rule: Frequency, - how: str | None = ..., - fill_method: str | None = ..., - limit: int | None = ..., - kind: Literal["period", "timestamp", "timedelta"] | None = ..., - on: Hashable | None = ..., - *, - # Keyword argumentsmust be kept roughly inline with TimeGrouper.__init__ below - closed: Literal["left", "right"] | None = ..., - label: Literal["left", "right"] | None = ..., - axis: Axis = ..., - convention: TimestampConvention | None = ..., - origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., - offset: TimedeltaConvertibleTypes | None = ..., - group_keys: bool = ..., - **kwargs, -) -> _ResamplerGroupBy[NDFrameT]: ... - class TimeGrouper(Grouper): closed: Literal["left", "right"] label: Literal["left", "right"] diff --git a/pandas-stubs/util/_decorators.pyi b/pandas-stubs/util/_decorators.pyi index 0e1a1f1ff..ecc2a69f7 100644 --- a/pandas-stubs/util/_decorators.pyi +++ b/pandas-stubs/util/_decorators.pyi @@ -1,62 +1 @@ -from collections.abc import ( - Callable, - Mapping, -) -from typing import Any - from pandas._libs.properties import cache_readonly as cache_readonly -from pandas._typing import ( - F, - T, -) - -__all__ = [ - "Appender", - "cache_readonly", - "deprecate", - "deprecate_kwarg", - "deprecate_nonkeyword_arguments", - "doc", - "future_version_msg", - "Substitution", -] - -def deprecate( - name: str, - alternative: Callable[..., Any], - version: str, - alt_name: str | None = ..., - klass: type[Warning] | None = ..., - stacklevel: int = ..., - msg: str | None = ..., -) -> Callable[[F], F]: ... -def deprecate_kwarg( - old_arg_name: str, - new_arg_name: str | None, - mapping: Mapping[Any, Any] | Callable[[Any], Any] | None = ..., - stacklevel: int = ..., -) -> Callable[[F], F]: ... -def future_version_msg(version: str | None) -> str: ... -def deprecate_nonkeyword_arguments( - version: str | None, - allowed_args: list[str] | None = ..., - name: str | None = ..., -) -> Callable[[F], F]: ... -def doc(*docstrings: str | Callable | None, **params) -> Callable[[F], F]: ... - -class Substitution: - params: Any - def __init__(self, *args, **kwargs) -> None: ... - def __call__(self, func: F) -> F: ... - def update(self, *args, **kwargs) -> None: ... - -class Appender: - addendum: str | None - join: str - - def __init__( - self, addendum: str | None, join: str = ..., indents: int = ... - ) -> None: ... - def __call__(self, func: T) -> T: ... - -def indent(text: str | None, indents: int = ...) -> str: ... diff --git a/tests/test_groupby.py b/tests/test_groupby.py index b2fa84f02..f732082bb 100644 --- a/tests/test_groupby.py +++ b/tests/test_groupby.py @@ -35,7 +35,7 @@ ) if TYPE_CHECKING: - from pandas.core.resample import _ResamplerGroupBy # noqa: F401 + from pandas.core.groupby.groupby import _ResamplerGroupBy # noqa: F401 DR = date_range("1999-1-1", periods=365, freq="D") DF_ = DataFrame(np.random.standard_normal((365, 1)), index=DR) From 9a0cb642775a54ae26aae0fb06687a1c6f7d2d47 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 10:28:45 +0100 Subject: [PATCH 07/23] Remove deprecated Resampler.fillna --- pandas-stubs/core/resample.pyi | 3 --- tests/test_groupby.py | 40 ++++++---------------------------- tests/test_resampler.py | 34 +++++------------------------ 3 files changed, 13 insertions(+), 64 deletions(-) diff --git a/pandas-stubs/core/resample.pyi b/pandas-stubs/core/resample.pyi index 3de8b8c1d..98cfdb518 100644 --- a/pandas-stubs/core/resample.pyi +++ b/pandas-stubs/core/resample.pyi @@ -114,9 +114,6 @@ class Resampler(BaseGroupBy[NDFrameT]): def ffill(self, limit: int | None = ...) -> NDFrameT: ... def nearest(self, limit: int | None = ...) -> NDFrameT: ... def bfill(self, limit: int | None = ...) -> NDFrameT: ... - def fillna( - self, method: Literal[FillnaOptions, "nearest"], limit: int | None = ... - ) -> NDFrameT: ... @overload def interpolate( self, diff --git a/tests/test_groupby.py b/tests/test_groupby.py index f732082bb..253f5776e 100644 --- a/tests/test_groupby.py +++ b/tests/test_groupby.py @@ -30,6 +30,7 @@ from tests import ( PD_LTE_21, + TYPE_CHECKING_INVALID_USAGE, check, pytest_warns_bounded, ) @@ -94,18 +95,9 @@ def test_frame_groupby_resample() -> None: check(assert_type(GB_DF.resample(M).nearest(), DataFrame), DataFrame) check(assert_type(GB_DF.resample(M).bfill(), DataFrame), DataFrame) - # fillna - with pytest_warns_bounded( - FutureWarning, - "DatetimeIndexResamplerGroupby.fillna is deprecated ", - lower="2.0.99", - ): - check(assert_type(GB_DF.resample(M).fillna("ffill"), DataFrame), DataFrame) - check(assert_type(GB_DF.resample(M).fillna("bfill"), DataFrame), DataFrame) - check( - assert_type(GB_DF.resample(M).fillna("nearest", limit=2), DataFrame), - DataFrame, - ) + # fillna (deprecated) + if TYPE_CHECKING_INVALID_USAGE: + GB_DF.resample(M).fillna("ffill") # type: ignore[operator] # pyright: ignore # aggregate / apply with pytest_warns_bounded( @@ -291,27 +283,9 @@ def test_series_groupby_resample() -> None: check(assert_type(GB_S.resample(M).nearest(), "Series[float]"), Series, float) check(assert_type(GB_S.resample(M).bfill(), "Series[float]"), Series, float) - # fillna - with pytest_warns_bounded( - FutureWarning, - "DatetimeIndexResamplerGroupby.fillna is deprecated ", - lower="2.0.99", - ): - check( - assert_type(GB_S.resample(M).fillna("ffill"), "Series[float]"), - Series, - float, - ) - check( - assert_type(GB_S.resample(M).fillna("bfill"), "Series[float]"), - Series, - float, - ) - check( - assert_type(GB_S.resample(M).fillna("nearest", limit=2), "Series[float]"), - Series, - float, - ) + # fillna (deprecated) + if TYPE_CHECKING_INVALID_USAGE: + GB_S.resample(M).fillna("ffill") # type: ignore[operator] # pyright: ignore # aggregate with pytest_warns_bounded( diff --git a/tests/test_resampler.py b/tests/test_resampler.py index 62eda2b84..9c7fe0018 100644 --- a/tests/test_resampler.py +++ b/tests/test_resampler.py @@ -94,21 +94,9 @@ def test_filling() -> None: def test_fillna() -> None: - with pytest_warns_bounded( - FutureWarning, - "DatetimeIndexResampler.fillna is deprecated ", - lower="2.0.99", - ): - check(assert_type(DF.resample(MonthFreq).fillna("pad"), DataFrame), DataFrame) - check( - assert_type(DF.resample(MonthFreq).fillna("backfill"), DataFrame), DataFrame - ) - check(assert_type(DF.resample(MonthFreq).fillna("ffill"), DataFrame), DataFrame) - check(assert_type(DF.resample(MonthFreq).fillna("bfill"), DataFrame), DataFrame) - check( - assert_type(DF.resample(MonthFreq).fillna("nearest", limit=2), DataFrame), - DataFrame, - ) + # deprecated (and removed from stub) + if TYPE_CHECKING_INVALID_USAGE: + DF.resample(MonthFreq).fillna("pad") # type: ignore[operator] # pyright: ignore def test_aggregate() -> None: @@ -342,19 +330,9 @@ def test_filling_series() -> None: def test_fillna_series() -> None: - with pytest_warns_bounded( - FutureWarning, - "DatetimeIndexResampler.fillna is deprecated ", - lower="2.0.99", - ): - check(assert_type(S.resample(MonthFreq).fillna("pad"), Series), Series) - check(assert_type(S.resample(MonthFreq).fillna("backfill"), Series), Series) - check(assert_type(S.resample(MonthFreq).fillna("ffill"), Series), Series) - check(assert_type(S.resample(MonthFreq).fillna("bfill"), Series), Series) - check( - assert_type(S.resample(MonthFreq).fillna("nearest", limit=2), Series), - Series, - ) + # deprecated (and removed from stub) + if TYPE_CHECKING_INVALID_USAGE: + S.resample(MonthFreq).fillna("pad") # type: ignore[operator] # pyright: ignore def test_aggregate_series() -> None: From 2ba2d10a8c7014013226b12c7b4b7e48f2fd9f8b Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 11:12:43 +0100 Subject: [PATCH 08/23] Remove private constructors --- pandas-stubs/core/groupby/groupby.pyi | 16 -------- pandas-stubs/core/groupby/grouper.pyi | 12 ------ pandas-stubs/core/groupby/indexing.pyi | 2 - pandas-stubs/core/resample.pyi | 55 +------------------------- pandas-stubs/core/window/ewm.pyi | 41 +------------------ pandas-stubs/core/window/expanding.pyi | 17 +------- pandas-stubs/core/window/rolling.pyi | 38 +----------------- 7 files changed, 5 insertions(+), 176 deletions(-) diff --git a/pandas-stubs/core/groupby/groupby.pyi b/pandas-stubs/core/groupby/groupby.pyi index 527a8673b..c59d5b6f6 100644 --- a/pandas-stubs/core/groupby/groupby.pyi +++ b/pandas-stubs/core/groupby/groupby.pyi @@ -164,22 +164,6 @@ class GroupBy(BaseGroupBy[NDFrameT]): as_index: bool sort: bool observed: bool - @final - def __init__( - self, - obj: NDFrameT, - keys: _KeysArgType | None = ..., - axis: Axis = ..., - level: IndexLabel | None = ..., - grouper: ops.BaseGrouper | None = ..., - exclusions: frozenset[Hashable] | None = ..., - selection: IndexLabel | None = ..., - as_index: bool = ..., - sort: bool = ..., - group_keys: bool = ..., - observed: bool | NoDefault = ..., - dropna: bool = ..., - ) -> None: ... def __getattr__(self, attr: str) -> Any: ... def apply(self, func: Callable | str, *args, **kwargs) -> NDFrameT: ... @final diff --git a/pandas-stubs/core/groupby/grouper.pyi b/pandas-stubs/core/groupby/grouper.pyi index 28042042a..ab45a3cea 100644 --- a/pandas-stubs/core/groupby/grouper.pyi +++ b/pandas-stubs/core/groupby/grouper.pyi @@ -66,18 +66,6 @@ class Grouping: obj: DataFrame | Series | None in_axis: bool grouping_vector: Incomplete - def __init__( - self, - index: Index, - grouper=..., - obj: DataFrame | Series | None = ..., - level: Level | None = ..., - sort: bool = ..., - observed: bool = ..., - in_axis: bool = ..., - dropna: bool = ..., - uniques: ArrayLike | None = ..., - ) -> None: ... def __iter__(self) -> Iterator[Hashable]: ... @cache_readonly def name(self) -> Hashable: ... diff --git a/pandas-stubs/core/groupby/indexing.pyi b/pandas-stubs/core/groupby/indexing.pyi index b50ca7085..c013d4c74 100644 --- a/pandas-stubs/core/groupby/indexing.pyi +++ b/pandas-stubs/core/groupby/indexing.pyi @@ -19,13 +19,11 @@ class GroupByIndexingMixin: ... class GroupByPositionalSelector: groupby_object: groupby.GroupBy - def __init__(self, groupby_object: groupby.GroupBy) -> None: ... def __getitem__(self, arg: PositionalIndexer | tuple) -> DataFrame | Series: ... class GroupByNthSelector(Generic[_GroupByT]): groupby_object: _GroupByT - def __init__(self, groupby_object: _GroupByT) -> None: ... def __call__( self, n: PositionalIndexer | tuple, diff --git a/pandas-stubs/core/resample.pyi b/pandas-stubs/core/resample.pyi index 98cfdb518..169f1e541 100644 --- a/pandas-stubs/core/resample.pyi +++ b/pandas-stubs/core/resample.pyi @@ -19,10 +19,7 @@ from pandas import ( TimedeltaIndex, ) from pandas.core.groupby.generic import SeriesGroupBy -from pandas.core.groupby.groupby import ( - BaseGroupBy, - GroupBy, -) +from pandas.core.groupby.groupby import BaseGroupBy from pandas.core.groupby.grouper import Grouper from pandas.core.groupby.ops import BinGrouper from typing_extensions import ( @@ -34,16 +31,11 @@ from pandas._libs.lib import NoDefault from pandas._typing import ( S1, Axis, - FillnaOptions, - Frequency, - IndexLabel, InterpolateOptions, NDFrameT, Scalar, - TimedeltaConvertibleTypes, TimeGrouperOrigin, TimestampConvention, - TimestampConvertibleTypes, npt, ) @@ -75,17 +67,6 @@ class Resampler(BaseGroupBy[NDFrameT]): binner: DatetimeIndex | TimedeltaIndex | PeriodIndex exclusions: frozenset[Hashable] ax: Index - def __init__( - self, - obj: NDFrameT, - timegrouper: TimeGrouper, - axis: Axis = ..., - kind: str | None = ..., - *, - gpr_index: Index, - group_keys: bool = ..., - selection: IndexLabel | None = ..., - ) -> None: ... def __getattr__(self, attr: str) -> SeriesGroupBy: ... @overload def aggregate( @@ -190,14 +171,6 @@ class Resampler(BaseGroupBy[NDFrameT]): # attributes via setattr class _GroupByMixin(Resampler[NDFrameT]): k: str | list[str] | None - def __init__( - self, - *, - parent: Resampler, - groupby: GroupBy, - key=..., - selection: IndexLabel | None = ..., - ) -> None: ... def __getitem__(self, key) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] class DatetimeIndexResampler(Resampler[NDFrameT]): ... @@ -232,29 +205,3 @@ class TimeGrouper(Grouper): group_keys: bool origin: TimeGrouperOrigin offset: Timedelta | None - - def __init__( - self, - freq: Frequency = ..., - closed: Literal["left", "right"] | None = ..., - label: Literal["left", "right"] | None = ..., - how: str = ..., - axis: Axis = ..., - fill_method: str | None = ..., - limit: int | None = ..., - kind: Literal["period", "timestamp", "timedelta"] | None = ..., - convention: TimestampConvention | None = ..., - origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., - offset: TimedeltaConvertibleTypes | None = ..., - group_keys: bool = ..., - **kwargs, - ) -> None: ... - -def asfreq( - obj: NDFrameT, - freq: Frequency, - method: Literal[FillnaOptions, "nearest"] | None = ..., - how: str | None = ..., - normalize: bool = ..., - fill_value: Scalar | None = ..., -) -> NDFrameT: ... diff --git a/pandas-stubs/core/window/ewm.pyi b/pandas-stubs/core/window/ewm.pyi index 14401a2e6..cc9d8cbb7 100644 --- a/pandas-stubs/core/window/ewm.pyi +++ b/pandas-stubs/core/window/ewm.pyi @@ -1,4 +1,3 @@ -import numpy as np from pandas import ( DataFrame, Series, @@ -9,32 +8,12 @@ from pandas.core.window.rolling import ( ) from pandas._typing import ( - Axis, - CalculationMethod, - IndexLabel, NDFrameT, - TimedeltaConvertibleTypes, WindowingEngine, WindowingEngineKwargs, ) class ExponentialMovingWindow(BaseWindow[NDFrameT]): - def __init__( - self, - obj: NDFrameT, - com: float | None = ..., - span: float | None = ..., - halflife: TimedeltaConvertibleTypes | None = ..., - alpha: float | None = ..., - min_periods: int | None = ..., - adjust: bool = ..., - ignore_na: bool = ..., - axis: Axis = ..., - times: str | np.ndarray | Series | None | np.timedelta64 = ..., - method: CalculationMethod = ..., - *, - selection: IndexLabel | None = ..., - ) -> None: ... def online( self, engine: WindowingEngine = ..., @@ -70,27 +49,9 @@ class ExponentialMovingWindow(BaseWindow[NDFrameT]): class ExponentialMovingWindowGroupby( BaseWindowGroupby[NDFrameT], ExponentialMovingWindow[NDFrameT] -): - def __init__(self, obj, *args, _grouper=..., **kwargs) -> None: ... +): ... class OnlineExponentialMovingWindow(ExponentialMovingWindow[NDFrameT]): - def __init__( - self, - obj: NDFrameT, - com: float | None = ..., - span: float | None = ..., - halflife: float | TimedeltaConvertibleTypes | None = ..., - alpha: float | None = ..., - min_periods: int | None = ..., - adjust: bool = ..., - ignore_na: bool = ..., - axis: Axis = ..., - times: np.ndarray | NDFrameT | None = ..., - engine: WindowingEngine = ..., - engine_kwargs: WindowingEngineKwargs = ..., - *, - selection: IndexLabel | None = ..., - ) -> None: ... def reset(self) -> None: ... def aggregate(self, func, *args, **kwargs): ... def std(self, bias: bool = ..., *args, **kwargs): ... diff --git a/pandas-stubs/core/window/expanding.pyi b/pandas-stubs/core/window/expanding.pyi index 60ebfd4f0..e5c8e586c 100644 --- a/pandas-stubs/core/window/expanding.pyi +++ b/pandas-stubs/core/window/expanding.pyi @@ -3,20 +3,7 @@ from pandas.core.window.rolling import ( RollingAndExpandingMixin, ) -from pandas._typing import ( - Axis, - IndexLabel, - NDFrameT, -) - -class Expanding(RollingAndExpandingMixin[NDFrameT]): - def __init__( - self, - obj: NDFrameT, - min_periods: int = ..., - axis: Axis = ..., - method: str = ..., - selection: IndexLabel | None = ..., - ) -> None: ... +from pandas._typing import NDFrameT +class Expanding(RollingAndExpandingMixin[NDFrameT]): ... class ExpandingGroupby(BaseWindowGroupby[NDFrameT], Expanding[NDFrameT]): ... diff --git a/pandas-stubs/core/window/rolling.pyi b/pandas-stubs/core/window/rolling.pyi index a0ebcdcc5..06774ef1a 100644 --- a/pandas-stubs/core/window/rolling.pyi +++ b/pandas-stubs/core/window/rolling.pyi @@ -14,7 +14,6 @@ from pandas import ( Series, ) from pandas.core.base import SelectionMixin -from pandas.core.groupby.ops import BaseGrouper from pandas.core.indexers import BaseIndexer from typing_extensions import Self @@ -23,10 +22,8 @@ from pandas._typing import ( AggFuncTypeBase, AggFuncTypeFrame, AggFuncTypeSeriesToFrame, - Axis, AxisInt, CalculationMethod, - IndexLabel, IntervalClosedType, NDFrameT, QuantileInterpolation, @@ -45,22 +42,6 @@ class BaseWindow(SelectionMixin[NDFrameT]): win_type: str | None axis: AxisInt method: CalculationMethod - - def __init__( - self, - obj: NDFrameT, - window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = ..., - min_periods: int | None = ..., - center: bool | None = ..., - win_type: str | None = ..., - axis: Axis = ..., - on: str | Index | None = ..., - closed: IntervalClosedType | None = ..., - step: int | None = ..., - method: CalculationMethod = ..., - *, - selection: IndexLabel | None = ..., - ) -> None: ... def __getitem__(self, key) -> Self: ... def __getattr__(self, attr: str) -> Self: ... def __iter__(self) -> Iterator[NDFrameT]: ... @@ -84,24 +65,7 @@ class BaseWindow(SelectionMixin[NDFrameT]): ) -> DataFrame: ... agg = aggregate -class BaseWindowGroupby(BaseWindow[NDFrameT]): - def __init__( - self, - obj: NDFrameT, - window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = ..., - min_periods: int | None = ..., - center: bool | None = ..., - win_type: str | None = ..., - axis: Axis = ..., - on: str | Index | None = ..., - closed: IntervalClosedType | None = ..., - step: int | None = ..., - method: CalculationMethod = ..., - *, - selection: IndexLabel | None = ..., - _grouper: BaseGrouper, - _as_index: bool = ..., - ) -> None: ... +class BaseWindowGroupby(BaseWindow[NDFrameT]): ... class Window(BaseWindow[NDFrameT]): def sum(self, numeric_only: bool = ..., **kwargs: Any) -> NDFrameT: ... From 8d4bab27c6b2f6827e570885901777c7cd7822d4 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 11:28:48 +0100 Subject: [PATCH 09/23] Remove more private constructors --- pandas-stubs/core/groupby/ops.pyi | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/pandas-stubs/core/groupby/ops.pyi b/pandas-stubs/core/groupby/ops.pyi index 0247b32d1..9a551cf8d 100644 --- a/pandas-stubs/core/groupby/ops.pyi +++ b/pandas-stubs/core/groupby/ops.pyi @@ -2,7 +2,6 @@ from collections.abc import ( Callable, Hashable, Iterator, - Sequence, ) from typing import ( Generic, @@ -17,9 +16,7 @@ from pandas import ( from pandas.core.groupby import grouper from pandas._typing import ( - AnyArrayLike, ArrayLike, - Axes, AxisInt, Incomplete, NDFrameT, @@ -32,13 +29,6 @@ from pandas.util._decorators import cache_readonly class BaseGrouper: axis: Index dropna: bool - def __init__( - self, - axis: Index, - groupings: Sequence[grouper.Grouping], - sort: bool = ..., - dropna: bool = ..., - ) -> None: ... @property def groupings(self) -> list[grouper.Grouping]: ... @property @@ -102,12 +92,6 @@ class BinGrouper(BaseGrouper): bins: npt.NDArray[np.int64] binlabels: Index indexer: npt.NDArray[np.intp] - def __init__( - self, - bins: ArrayLike | AnyArrayLike | Sequence[int], - binlabels: Axes, - indexer: npt.NDArray[np.intp] | None = ..., - ) -> None: ... @cache_readonly def indices(self) -> dict[Incomplete, list[int]]: ... # type: ignore[override] # pyright: ignore @@ -116,14 +100,4 @@ class DataSplitter(Generic[NDFrameT]): labels: npt.NDArray[np.intp] ngroups: int axis: AxisInt - def __init__( - self, - data: NDFrameT, - labels: npt.NDArray[np.intp], - ngroups: int, - *, - sort_idx: npt.NDArray[np.intp], - sorted_ids: npt.NDArray[np.intp], - axis: AxisInt = ..., - ) -> None: ... def __iter__(self) -> Iterator[NDFrameT]: ... From 8e2362d10bd4c2236dd775f9184c68d0063738a1 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 12:52:18 +0100 Subject: [PATCH 10/23] Temporarily type labelsize as int Needs fix everywhere and the upstream docs should be updated --- pandas-stubs/core/groupby/generic.pyi | 8 ++++---- tests/test_plotting.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index e73c9e69f..9fd39c501 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -164,9 +164,9 @@ class SeriesGroupBy(GroupBy[Series[S1]], Generic[S1, ByT]): by: IndexLabel | None = ..., ax: PlotAxes | None = ..., grid: bool = ..., - xlabelsize: float | None = ..., + xlabelsize: int | None = ..., xrot: float | None = ..., - ylabelsize: float | None = ..., + ylabelsize: int | None = ..., yrot: float | None = ..., figsize: tuple[float, float] | None = ..., bins: int | Sequence[int] = ..., @@ -319,9 +319,9 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): column: IndexLabel | None = ..., by: IndexLabel | None = ..., grid: bool = ..., - xlabelsize: float | None = ..., + xlabelsize: int | None = ..., xrot: float | None = ..., - ylabelsize: float | None = ..., + ylabelsize: int | None = ..., yrot: float | None = ..., ax: PlotAxes | None = ..., sharex: bool = ..., diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 36214d8db..e6ebcec20 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -622,8 +622,8 @@ def test_grouped_dataframe_hist(close_figures): column="PetalWidth", by="PetalLength", grid=False, - xlabelsize=1.5, - ylabelsize=0.5, + xlabelsize=2, + ylabelsize=1, yrot=10.0, sharex=True, sharey=False, @@ -647,8 +647,8 @@ def test_grouped_series_hist(close_figures): grouped.hist( by=["a", "b"], grid=False, - xlabelsize=1.5, - ylabelsize=0.5, + xlabelsize=2, + ylabelsize=1, yrot=10.0, figsize=(1.5, 1.5), bins=4, From 0631f07adfed1eeb6b5c05d8460e43c995dff8ea Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 13:02:47 +0100 Subject: [PATCH 11/23] Tighten rolling and expanding method type --- pandas-stubs/core/groupby/groupby.pyi | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pandas-stubs/core/groupby/groupby.pyi b/pandas-stubs/core/groupby/groupby.pyi index c59d5b6f6..e10db7c6b 100644 --- a/pandas-stubs/core/groupby/groupby.pyi +++ b/pandas-stubs/core/groupby/groupby.pyi @@ -277,7 +277,6 @@ class GroupBy(BaseGroupBy[NDFrameT]): def resample( self, rule: Frequency, - # Arguments must be kept roughly inline with pandas.core.resample.get_resampler_for_grouping how: str | None = ..., fill_method: str | None = ..., limit: int | None = ..., @@ -296,7 +295,6 @@ class GroupBy(BaseGroupBy[NDFrameT]): @final def rolling( self, - # Arguments must be kept roughly inline with pandas.core.window.RollingGroupby window: int | dt.timedelta | str | BaseOffset | BaseIndexer | None = ..., min_periods: int | None = ..., center: bool | None = ..., @@ -305,23 +303,21 @@ class GroupBy(BaseGroupBy[NDFrameT]): on: str | Index | None = ..., closed: IntervalClosedType | None = ..., step: int | None = ..., - method: str = ..., + method: CalculationMethod = ..., *, selection: IndexLabel | None = ..., ) -> RollingGroupby[NDFrameT]: ... @final def expanding( self, - # Arguments must be kept roughly inline with pandas.core.window.ExpandingGroupby min_periods: int = ..., axis: Axis = ..., - method: str = ..., + method: CalculationMethod = ..., selection: IndexLabel | None = ..., ) -> ExpandingGroupby[NDFrameT]: ... @final def ewm( self, - # Arguments must be kept roughly inline with pandas.core.window.ExponentialMovingWindowGroupby com: float | None = ..., span: float | None = ..., halflife: TimedeltaConvertibleTypes | None = ..., From ca4f9347c38ad55ea14b9f9ad59eac37ae0294e3 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 13:07:43 +0100 Subject: [PATCH 12/23] Remove step from groupby rolling --- pandas-stubs/core/groupby/groupby.pyi | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas-stubs/core/groupby/groupby.pyi b/pandas-stubs/core/groupby/groupby.pyi index e10db7c6b..d2938433a 100644 --- a/pandas-stubs/core/groupby/groupby.pyi +++ b/pandas-stubs/core/groupby/groupby.pyi @@ -302,7 +302,6 @@ class GroupBy(BaseGroupBy[NDFrameT]): axis: Axis = ..., on: str | Index | None = ..., closed: IntervalClosedType | None = ..., - step: int | None = ..., method: CalculationMethod = ..., *, selection: IndexLabel | None = ..., From 3c6a688cebe4424ddd1457f7d6100f45b3377a66 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 13:49:49 +0100 Subject: [PATCH 13/23] Fix resample rule --- pandas-stubs/core/generic.pyi | 5 +++-- pandas-stubs/core/groupby/groupby.pyi | 2 +- tests/test_frame.py | 8 ++++++-- tests/test_groupby.py | 14 ++++++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/pandas-stubs/core/generic.pyi b/pandas-stubs/core/generic.pyi index 1167df9fc..38a298a2d 100644 --- a/pandas-stubs/core/generic.pyi +++ b/pandas-stubs/core/generic.pyi @@ -5,6 +5,7 @@ from collections.abc import ( Mapping, Sequence, ) +import datetime as dt import sqlite3 from typing import ( Any, @@ -442,12 +443,12 @@ class NDFrame(indexing.IndexingMixin): @final def resample( self, - rule: Frequency, + rule: Frequency | dt.timedelta, axis: Axis | NoDefault = ..., closed: Literal["right", "left"] | None = ..., label: Literal["right", "left"] | None = ..., convention: TimestampConvention = ..., - kind: Literal["period", "timestamp", "timedelta"] | None = ..., + kind: Literal["period", "timestamp"] | None = ..., on: Level | None = ..., level: Level | None = ..., origin: TimeGrouperOrigin | TimestampConvertibleTypes = ..., diff --git a/pandas-stubs/core/groupby/groupby.pyi b/pandas-stubs/core/groupby/groupby.pyi index d2938433a..9dbe47eb2 100644 --- a/pandas-stubs/core/groupby/groupby.pyi +++ b/pandas-stubs/core/groupby/groupby.pyi @@ -276,7 +276,7 @@ class GroupBy(BaseGroupBy[NDFrameT]): @final def resample( self, - rule: Frequency, + rule: Frequency | dt.timedelta, how: str | None = ..., fill_method: str | None = ..., limit: int | None = ..., diff --git a/tests/test_frame.py b/tests/test_frame.py index 78c0ae550..efcb38be7 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -1385,6 +1385,8 @@ def test_types_resample() -> None: df.resample("M", on="date") df.resample("20min", origin="epoch", offset=pd.Timedelta(2, "minutes"), on="date") df.resample("20min", origin="epoch", offset=datetime.timedelta(2), on="date") + df.resample(pd.Timedelta(20, "minutes"), origin="epoch", on="date") + df.resample(datetime.timedelta(minutes=20), origin="epoch", on="date") def test_types_to_dict() -> None: @@ -2692,8 +2694,10 @@ def test_resample_150_changes() -> None: frame = pd.DataFrame(np.random.standard_normal((700, 1)), index=idx, columns=["a"]) with pytest_warns_bounded(FutureWarning, "'M' is deprecated", lower="2.1.99"): resampler = frame.resample("M", group_keys=True) - assert_type(resampler, "DatetimeIndexResampler[pd.DataFrame]") - assert isinstance(resampler, DatetimeIndexResampler) + check( + assert_type(resampler, "DatetimeIndexResampler[pd.DataFrame]"), + DatetimeIndexResampler, + ) def f(s: pd.DataFrame) -> pd.Series: return s.mean() diff --git a/tests/test_groupby.py b/tests/test_groupby.py index 253f5776e..3d34ed19b 100644 --- a/tests/test_groupby.py +++ b/tests/test_groupby.py @@ -1,6 +1,7 @@ from __future__ import annotations from collections.abc import Iterator +import datetime as dt from typing import ( TYPE_CHECKING, Literal, @@ -14,6 +15,7 @@ DatetimeIndex, Index, Series, + Timedelta, date_range, ) from pandas.core.groupby.generic import SeriesGroupBy @@ -56,6 +58,18 @@ def test_frame_groupby_resample() -> None: DatetimeIndexResamplerGroupby, DataFrame, ) + check( + assert_type(GB_DF.resample(Timedelta(days=30)), "_ResamplerGroupBy[DataFrame]"), + DatetimeIndexResamplerGroupby, + DataFrame, + ) + check( + assert_type( + GB_DF.resample(dt.timedelta(days=30)), "_ResamplerGroupBy[DataFrame]" + ), + DatetimeIndexResamplerGroupby, + DataFrame, + ) # props check(assert_type(GB_DF.resample(M).obj, DataFrame), DataFrame) From 92c45baec6d6c87637d11ca6c0ef59ef2af345d2 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 14:08:44 +0100 Subject: [PATCH 14/23] Fix groupby fillna --- pandas-stubs/core/groupby/generic.pyi | 13 ++++++++----- pandas-stubs/core/groupby/groupby.pyi | 3 +-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 9fd39c501..fb05a90a3 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -38,7 +38,6 @@ from pandas._typing import ( ByT, CorrelationMethod, Dtype, - FillnaOptions, IndexLabel, Level, ListLike, @@ -116,8 +115,10 @@ class SeriesGroupBy(GroupBy[Series[S1]], Generic[S1, ByT]): ) -> Series[float]: ... def fillna( self, - value: object | ArrayLike | None = ..., - method: FillnaOptions | None = ..., + value: ( + Scalar | ArrayLike | Series | DataFrame | Mapping[Hashable, Scalar] | None + ) = ..., + method: Literal["bfill", "ffill"] | None = ..., axis: Axis | None | NoDefault = ..., inplace: bool = ..., limit: int | None = ..., @@ -270,8 +271,10 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): ) -> Series[float]: ... def fillna( self, - value: Hashable | Mapping | Series | DataFrame | None = ..., - method: FillnaOptions | None = ..., + value: ( + Scalar | ArrayLike | Series | DataFrame | Mapping[Hashable, Scalar] | None + ) = ..., + method: Literal["bfill", "ffill"] | None = ..., axis: Axis | None | NoDefault = ..., inplace: Literal[False] = ..., limit: int | None = ..., diff --git a/pandas-stubs/core/groupby/groupby.pyi b/pandas-stubs/core/groupby/groupby.pyi index 9dbe47eb2..cac030850 100644 --- a/pandas-stubs/core/groupby/groupby.pyi +++ b/pandas-stubs/core/groupby/groupby.pyi @@ -55,7 +55,6 @@ from pandas._typing import ( AxisInt, CalculationMethod, Dtype, - FillnaOptions, Frequency, IndexLabel, IntervalClosedType, @@ -384,7 +383,7 @@ class GroupBy(BaseGroupBy[NDFrameT]): def pct_change( self, periods: int = ..., - fill_method: FillnaOptions | None | NoDefault = ..., + fill_method: Literal["bfill", "ffill"] | None | NoDefault = ..., limit: int | None | NoDefault = ..., freq=..., axis: Axis | NoDefault = ..., From da04d2e003a69f308d387d99cca519d765ce2cfd Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 14:57:16 +0100 Subject: [PATCH 15/23] Add missing test for linked issue --- tests/test_groupby.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/test_groupby.py b/tests/test_groupby.py index 3d34ed19b..5b5560162 100644 --- a/tests/test_groupby.py +++ b/tests/test_groupby.py @@ -18,7 +18,10 @@ Timedelta, date_range, ) -from pandas.core.groupby.generic import SeriesGroupBy +from pandas.core.groupby.generic import ( + DataFrameGroupBy, + SeriesGroupBy, +) from pandas.core.resample import ( DatetimeIndexResamplerGroupby, Resampler, @@ -933,3 +936,17 @@ def test_series_groupby_ewm() -> None: check(assert_type(iterator, "Iterator[Series[float]]"), Iterator) check(assert_type(next(iterator), "Series[float]"), Series, float) check(assert_type(list(GB_S.ewm(1)), "list[Series[float]]"), list, Series) + + +def test_engine() -> None: + if TYPE_CHECKING_INVALID_USAGE: + # See issue #810 + DataFrameGroupBy().aggregate( + "size", + "some", + "args", + engine=0, # type: ignore[call-overload] # pyright: ignore + engine_kwargs="not valid", # pyright: ignore + other_kwarg="", + ) + GB_DF.aggregate("size", engine="cython", engine_kwargs={}) From 12843df28c37d3c41bd3c2c1689830b718f16dd3 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sat, 13 Jan 2024 15:07:37 +0100 Subject: [PATCH 16/23] Remove pandas.core.apply as it is not used in public code --- pandas-stubs/core/apply.pyi | 242 ------------------------------------ 1 file changed, 242 deletions(-) delete mode 100644 pandas-stubs/core/apply.pyi diff --git a/pandas-stubs/core/apply.pyi b/pandas-stubs/core/apply.pyi deleted file mode 100644 index c080f12f5..000000000 --- a/pandas-stubs/core/apply.pyi +++ /dev/null @@ -1,242 +0,0 @@ -import abc -from abc import abstractmethod -from collections.abc import ( - Callable, - Hashable, - Iterable, - Iterator, - Sequence, -) -from typing import ( - Any, - Generic, - Literal, - TypeVar, -) - -import numpy as np -from pandas import ( - DataFrame, - Index, - Series, -) -from pandas.core.generic import NDFrame -from pandas.core.groupby import GroupBy -from pandas.core.resample import Resampler -from pandas.core.window.rolling import BaseWindow - -from pandas._libs.lib import NoDefault -from pandas._typing import ( - AggFuncType, - AggFuncTypeDict, - Axis, - AxisInt, - Incomplete, - NDFrameT, - npt, -) -from pandas.util._decorators import cache_readonly - -_AggObjT = TypeVar("_AggObjT", bound=NDFrame | GroupBy | BaseWindow | Resampler) -_AggGroupByObjT = TypeVar("_AggGroupByObjT", bound=GroupBy | BaseWindow | Resampler) -_AggResamplerWindowObjT = TypeVar( - "_AggResamplerWindowObjT", bound=BaseWindow | Resampler -) - -def frame_apply( - obj: DataFrame, - func: AggFuncType, - axis: Axis = ..., - raw: bool = ..., - result_type: str | None = ..., - by_row: Literal[False, "compat"] = ..., - args=..., - kwargs=..., -) -> FrameApply: ... - -class Apply(Generic[_AggObjT], metaclass=abc.ABCMeta): - axis: AxisInt - obj: _AggObjT - raw: bool - by_row: Literal[False, "compat", "_compat"] - args: Incomplete - kwargs: Incomplete - result_type: Literal["reduce", "broadcast", "expand"] | None - func: AggFuncType - def __init__( - self, - obj: _AggObjT, - func: AggFuncType, - raw: bool, - result_type: Literal["reduce", "broadcast", "expand"] | None, - *, - by_row: Literal[False, "compat", "_compat"] = ..., - args, - kwargs, - ) -> None: ... - @abstractmethod - def apply(self): ... - @abstractmethod - def agg_or_apply_list_like(self, op_name: Literal["agg", "apply"]): ... - @abstractmethod - def agg_or_apply_dict_like(self, op_name: Literal["agg", "apply"]): ... - def agg(self): ... - def transform(self): ... - def transform_dict_like(self, func: AggFuncTypeDict) -> DataFrame: ... - def transform_str_or_callable(self, func: str | Callable[..., Incomplete]): ... - def agg_list_like(self): ... - def compute_list_like( - self, - op_name: Literal["agg", "apply"], - selected_obj: Series | DataFrame, - kwargs: dict[str, Any], - ) -> tuple[list[Hashable], list[Any]]: ... - def wrap_results_list_like( - self, keys: list[Hashable], results: list[Series | DataFrame] - ): ... - def agg_dict_like(self): ... - def compute_dict_like( - self, - op_name: Literal["agg", "apply"], - selected_obj: Series | DataFrame, - selection: Hashable | Sequence[Hashable], - kwargs: dict[str, Any], - ) -> tuple[list[Hashable], list[Any]]: ... - def wrap_results_dict_like( - self, - selected_obj: Series | DataFrame, - result_index: list[Hashable], - result_data: list, - ) -> Series | DataFrame: ... - def apply_str(self): ... - def apply_list_or_dict_like(self): ... - def normalize_dictlike_arg( - self, how: str, obj: DataFrame | Series, func: AggFuncTypeDict - ) -> AggFuncTypeDict: ... - -class NDFrameApply(Apply[NDFrameT], metaclass=abc.ABCMeta): - @property - def index(self) -> Index: ... - @property - def agg_axis(self) -> Index: ... - def agg_or_apply_list_like(self, op_name: Literal["agg", "apply"]): ... - def agg_or_apply_dict_like(self, op_name: Literal["agg", "apply"]): ... - -class FrameApply(NDFrameApply[DataFrame]): - def __init__( - self, - obj: DataFrame, - func: AggFuncType, - raw: bool, - result_type: Literal["reduce", "broadcast", "expand"] | None, - *, - by_row: Literal[False, "compat"] = ..., - args, - kwargs, - ) -> None: ... - @property - @abstractmethod - def result_index(self) -> Index: ... - @property - @abstractmethod - def result_columns(self) -> Index: ... - @property - @abstractmethod - def series_generator(self) -> Iterator[Series]: ... - @abstractmethod - def wrap_results_for_axis(self, results: dict[int, Any], res_index: Index): ... - @property - def res_columns(self) -> Index: ... - @property - def columns(self) -> Index: ... - @cache_readonly - def values(self): ... - def apply(self): ... - def agg(self): ... - def apply_empty_result(self): ... - def apply_raw(self): ... - def apply_broadcast(self, target: DataFrame) -> DataFrame: ... - def apply_standard(self): ... - def apply_series_generator(self) -> tuple[dict[int, Any], Index]: ... - def wrap_results(self, results: dict[int, Any], res_index: Index): ... - def apply_str(self): ... - -class FrameRowApply(FrameApply): - @property - def series_generator(self) -> Iterator[Series]: ... - @property - def result_index(self) -> Index: ... - @property - def result_columns(self) -> Index: ... - def wrap_results_for_axis(self, results: dict[int, Any], res_index: Index): ... - -class FrameColumnApply(FrameApply): - def apply_broadcast(self, target: DataFrame) -> DataFrame: ... - @property - def series_generator(self) -> Iterator[Series]: ... - @property - def result_index(self) -> Index: ... - @property - def result_columns(self) -> Index: ... - def wrap_results_for_axis(self, results: dict[int, Any], res_index: Index): ... - def infer_to_same_shape( - self, results: dict[int, Any], res_index: Index - ) -> DataFrame: ... - -class SeriesApply(NDFrameApply[Series]): - by_row: Literal[False, "compat", "_compat"] - convert_dtype: bool - def __init__( - self, - obj: Series, - func: AggFuncType, - *, - convert_dtype: bool | NoDefault = ..., - by_row: Literal[False, "compat", "_compat"] = ..., - args, - kwargs, - ) -> None: ... - def apply(self): ... - def agg(self): ... - def apply_empty_result(self) -> Series: ... - def apply_compat(self): ... - def apply_standard(self): ... - -class GroupByApply(Apply[_AggGroupByObjT]): - def __init__( - self, obj: _AggGroupByObjT, func: AggFuncType, *, args, kwargs - ) -> None: ... - def apply(self): ... - def transform(self): ... - def agg_or_apply_list_like(self, op_name: Literal["agg", "apply"]): ... - def agg_or_apply_dict_like(self, op_name: Literal["agg", "apply"]): ... - -class ResamplerWindowApply(GroupByApply[_AggResamplerWindowObjT]): - def __init__( - self, obj: _AggResamplerWindowObjT, func: AggFuncType, *, args, kwargs - ) -> None: ... - def apply(self): ... - def transform(self): ... - -def reconstruct_func( - func: AggFuncType | None, **kwargs -) -> tuple[bool, AggFuncType, list[str] | None, npt.NDArray[np.intp] | None]: ... -def is_multi_agg_with_relabel(**kwargs) -> bool: ... -def normalize_keyword_aggregation( - kwargs: dict, -) -> tuple[dict[str, list], list[str], npt.NDArray[np.intp]]: ... -def relabel_result( - result: DataFrame | Series, - func: dict[str, list[Callable | str]], - columns: Iterable[Hashable], - order: Iterable[int], -) -> dict[Hashable, Series]: ... -def reconstruct_and_relabel_result(result, func, **kwargs): ... -def maybe_mangle_lambdas(agg_spec: Any) -> Any: ... -def validate_func_kwargs( - kwargs: dict, -) -> tuple[list[str], list[str | Callable[..., Any]]]: ... -def include_axis( - op_name: Literal["agg", "apply"], colg: Series | DataFrame -) -> bool: ... -def warn_alias_replacement(obj, func: Callable, alias: str) -> None: ... From 6d0c4087c170b37265a78a15be8e72eb5cb905d4 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 14 Jan 2024 20:55:42 +0100 Subject: [PATCH 17/23] Address CR --- pandas-stubs/core/groupby/grouper.pyi | 9 --------- pandas-stubs/core/groupby/ops.pyi | 2 +- pandas-stubs/core/resample.pyi | 2 +- pandas-stubs/core/window/__init__.pyi | 10 ---------- 4 files changed, 2 insertions(+), 21 deletions(-) diff --git a/pandas-stubs/core/groupby/grouper.pyi b/pandas-stubs/core/groupby/grouper.pyi index ab45a3cea..666cbc9ab 100644 --- a/pandas-stubs/core/groupby/grouper.pyi +++ b/pandas-stubs/core/groupby/grouper.pyi @@ -48,15 +48,6 @@ class Grouper: ) -> Self: ... @overload def __new__(cls, *args, freq: Frequency, **kwargs) -> TimeGrouper: ... - def __init__( - self, - key: KeysArgType | None = ..., - level: Level | ListLikeHashable[Level] | None = ..., - freq: Frequency | None = ..., - axis: Axis | NoDefault = ..., - sort: bool = ..., - dropna: bool = ..., - ) -> None: ... @final def __repr__(self) -> str: ... # noqa: PYI029 __repr__ here is final diff --git a/pandas-stubs/core/groupby/ops.pyi b/pandas-stubs/core/groupby/ops.pyi index 9a551cf8d..2f2665a01 100644 --- a/pandas-stubs/core/groupby/ops.pyi +++ b/pandas-stubs/core/groupby/ops.pyi @@ -93,7 +93,7 @@ class BinGrouper(BaseGrouper): binlabels: Index indexer: npt.NDArray[np.intp] @cache_readonly - def indices(self) -> dict[Incomplete, list[int]]: ... # type: ignore[override] # pyright: ignore + def indices(self) -> dict[Incomplete, list[int]]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] class DataSplitter(Generic[NDFrameT]): data: NDFrameT diff --git a/pandas-stubs/core/resample.pyi b/pandas-stubs/core/resample.pyi index 169f1e541..9b1d8ee96 100644 --- a/pandas-stubs/core/resample.pyi +++ b/pandas-stubs/core/resample.pyi @@ -170,7 +170,7 @@ class Resampler(BaseGroupBy[NDFrameT]): # We lie about inheriting from Resampler because at runtime inherits all Resampler # attributes via setattr class _GroupByMixin(Resampler[NDFrameT]): - k: str | list[str] | None + key: str | list[str] | None def __getitem__(self, key) -> Self: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride] class DatetimeIndexResampler(Resampler[NDFrameT]): ... diff --git a/pandas-stubs/core/window/__init__.pyi b/pandas-stubs/core/window/__init__.pyi index 6a16d7b83..d5dbe6956 100644 --- a/pandas-stubs/core/window/__init__.pyi +++ b/pandas-stubs/core/window/__init__.pyi @@ -11,13 +11,3 @@ from pandas.core.window.rolling import ( RollingGroupby as RollingGroupby, Window as Window, ) - -__all__ = [ - "Expanding", - "ExpandingGroupby", - "ExponentialMovingWindow", - "ExponentialMovingWindowGroupby", - "Rolling", - "RollingGroupby", - "Window", -] From 19ef72022df1a0b9f0bc71dfd4e71a56977c34c4 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Mon, 15 Jan 2024 20:45:17 +0100 Subject: [PATCH 18/23] Address remaining CR --- pandas-stubs/core/groupby/generic.pyi | 59 ++++++++++++++++++++++++--- pandas-stubs/plotting/__init__.pyi | 1 - pandas-stubs/plotting/_core.pyi | 49 ---------------------- pyproject.toml | 3 +- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index fb05a90a3..8dcf63003 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -47,8 +47,6 @@ from pandas._typing import ( WindowingEngineKwargs, ) -from pandas.plotting import boxplot_frame_groupby - AggScalar: TypeAlias = str | Callable[..., Any] class NamedAgg(NamedTuple): @@ -180,7 +178,9 @@ class SeriesGroupBy(GroupBy[Series[S1]], Generic[S1, ByT]): def unique(self) -> Series: ... # Overrides that provide more precise return types over the GroupBy class @final # type: ignore[misc] - def __iter__(self) -> Iterator[tuple[ByT, Series[S1]]]: ... # pyright: ignore + def __iter__( # pyright: ignore[reportIncompatibleMethodOverride] + self, + ) -> Iterator[tuple[ByT, Series[S1]]]: ... class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): # error: Overload 3 for "apply" will never be used because its parameters overlap overload 1 @@ -250,7 +250,54 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): skipna: bool = ..., numeric_only: bool = ..., ) -> DataFrame: ... - boxplot = boxplot_frame_groupby + @overload + def boxplot( + grouped, + subplots: Literal[True] = ..., + column: IndexLabel | None = ..., + fontsize: float | str | None = ..., + rot: float = ..., + grid: bool = ..., + ax: PlotAxes | None = ..., + figsize: tuple[float, float] | None = ..., + layout: tuple[int, int] | None = ..., + sharex: bool = ..., + sharey: bool = ..., + backend: str | None = ..., + **kwargs, + ) -> Series: ... # Series[PlotAxes] but this is not allowed + @overload + def boxplot( + grouped, + subplots: Literal[False], + column: IndexLabel | None = ..., + fontsize: float | str | None = ..., + rot: float = ..., + grid: bool = ..., + ax: PlotAxes | None = ..., + figsize: tuple[float, float] | None = ..., + layout: tuple[int, int] | None = ..., + sharex: bool = ..., + sharey: bool = ..., + backend: str | None = ..., + **kwargs, + ) -> PlotAxes: ... + @overload + def boxplot( + grouped, + subplots: bool, + column: IndexLabel | None = ..., + fontsize: float | str | None = ..., + rot: float = ..., + grid: bool = ..., + ax: PlotAxes | None = ..., + figsize: tuple[float, float] | None = ..., + layout: tuple[int, int] | None = ..., + sharex: bool = ..., + sharey: bool = ..., + backend: str | None = ..., + **kwargs, + ) -> PlotAxes | Series: ... # Series[PlotAxes] @overload def value_counts( self, @@ -349,4 +396,6 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): def __getattr__(self, name: str) -> SeriesGroupBy[Any, ByT]: ... # Overrides that provide more precise return types over the GroupBy class @final # type: ignore[misc] - def __iter__(self) -> Iterator[tuple[ByT, DataFrame]]: ... # pyright: ignore + def __iter__( # pyright: ignore[reportIncompatibleMethodOverride] + self, + ) -> Iterator[tuple[ByT, DataFrame]]: ... diff --git a/pandas-stubs/plotting/__init__.pyi b/pandas-stubs/plotting/__init__.pyi index 02e613ed8..6fd96626e 100644 --- a/pandas-stubs/plotting/__init__.pyi +++ b/pandas-stubs/plotting/__init__.pyi @@ -1,7 +1,6 @@ from pandas.plotting._core import ( PlotAccessor as PlotAccessor, boxplot as boxplot, - boxplot_frame_groupby as boxplot_frame_groupby, ) from pandas.plotting._misc import ( andrews_curves as andrews_curves, diff --git a/pandas-stubs/plotting/_core.pyi b/pandas-stubs/plotting/_core.pyi index a79e74523..b51c0fd3c 100644 --- a/pandas-stubs/plotting/_core.pyi +++ b/pandas-stubs/plotting/_core.pyi @@ -27,7 +27,6 @@ from pandas._typing import ( HashableT1, HashableT2, HashableT3, - IndexLabel, npt, ) @@ -84,54 +83,6 @@ def boxplot( return_type: Literal["both"], **kwargs, ) -> _BoxPlotT: ... -@overload -def boxplot_frame_groupby( - grouped, - subplots: Literal[True] = ..., - column: IndexLabel | None = ..., - fontsize: float | str | None = ..., - rot: float = ..., - grid: bool = ..., - ax: Axes | None = ..., - figsize: tuple[float, float] | None = ..., - layout: tuple[int, int] | None = ..., - sharex: bool = ..., - sharey: bool = ..., - backend: str | None = ..., - **kwargs, -) -> Series: ... # Series[Axes] but this is not allowed -@overload -def boxplot_frame_groupby( - grouped, - subplots: Literal[False], - column: IndexLabel | None = ..., - fontsize: float | str | None = ..., - rot: float = ..., - grid: bool = ..., - ax: Axes | None = ..., - figsize: tuple[float, float] | None = ..., - layout: tuple[int, int] | None = ..., - sharex: bool = ..., - sharey: bool = ..., - backend: str | None = ..., - **kwargs, -) -> Axes: ... -@overload -def boxplot_frame_groupby( - grouped, - subplots: bool, - column: IndexLabel | None = ..., - fontsize: float | str | None = ..., - rot: float = ..., - grid: bool = ..., - ax: Axes | None = ..., - figsize: tuple[float, float] | None = ..., - layout: tuple[int, int] | None = ..., - sharex: bool = ..., - sharey: bool = ..., - backend: str | None = ..., - **kwargs, -) -> Axes | Series: ... # Series[Axes] class PlotAccessor: def __init__(self, data) -> None: ... diff --git a/pyproject.toml b/pyproject.toml index e44933eec..e5e834b44 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ mypy = "1.8.0" pandas = "2.1.4" pyarrow = ">=10.0.1" pytest = ">=7.1.2" -pyright = ">=1.1.344" +pyright = ">=1.1.346" poethepoet = ">=0.16.5" loguru = ">=0.6.0" typing-extensions = ">=4.4.0" @@ -191,6 +191,7 @@ reportUnknownParameterType = false reportUnknownVariableType = false reportUnusedVariable = false reportPrivateUsage = false +reportSelfClsParameterName = false # enable optional checks reportMissingModuleSource = true useLibraryCodeForTypes = false From 83c7dcb26cb002a6e305a82b6465cfc39fef1b32 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 4 Feb 2024 15:35:32 +0100 Subject: [PATCH 19/23] revert pyproject change --- pandas-stubs/core/groupby/generic.pyi | 6 +++--- pyproject.toml | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 8dcf63003..57f62a143 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -252,7 +252,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): ) -> DataFrame: ... @overload def boxplot( - grouped, + grouped, # pyright: ignore[reportSelfClsParameterName] subplots: Literal[True] = ..., column: IndexLabel | None = ..., fontsize: float | str | None = ..., @@ -268,7 +268,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): ) -> Series: ... # Series[PlotAxes] but this is not allowed @overload def boxplot( - grouped, + grouped, # pyright: ignore[reportSelfClsParameterName] subplots: Literal[False], column: IndexLabel | None = ..., fontsize: float | str | None = ..., @@ -284,7 +284,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): ) -> PlotAxes: ... @overload def boxplot( - grouped, + grouped, # pyright: ignore[reportSelfClsParameterName] subplots: bool, column: IndexLabel | None = ..., fontsize: float | str | None = ..., diff --git a/pyproject.toml b/pyproject.toml index e5e834b44..c93f9a092 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -191,7 +191,6 @@ reportUnknownParameterType = false reportUnknownVariableType = false reportUnusedVariable = false reportPrivateUsage = false -reportSelfClsParameterName = false # enable optional checks reportMissingModuleSource = true useLibraryCodeForTypes = false From 831241a7ee87971c11181fcea45d2f87ac3c416d Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 4 Feb 2024 15:54:57 +0100 Subject: [PATCH 20/23] Temporarily pin pyright to unblock CI --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c93f9a092..d10abb29c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ mypy = "1.8.0" pandas = "2.1.4" pyarrow = ">=10.0.1" pytest = ">=7.1.2" -pyright = ">=1.1.346" +pyright = "==1.1.346" poethepoet = ">=0.16.5" loguru = ">=0.6.0" typing-extensions = ">=4.4.0" From 38cf1d93b1a66332a0f2f231b0ab498ce8141b71 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 4 Feb 2024 16:37:40 +0100 Subject: [PATCH 21/23] New deprecations --- tests/test_frame.py | 6 +++--- tests/test_series.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_frame.py b/tests/test_frame.py index efcb38be7..f0850a658 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -956,7 +956,7 @@ def test_types_groupby() -> None: df6: pd.DataFrame = df.groupby(by=["col1", "col2"]).nunique() with pytest_warns_bounded( FutureWarning, - "The provided callable is currently using", + "(The provided callable is currently using|The behavior of DataFrame.sum with)", lower="2.0.99", ): df7: pd.DataFrame = df.groupby(by="col1").apply(sum) @@ -1252,7 +1252,7 @@ def test_types_agg() -> None: with pytest_warns_bounded( FutureWarning, - r"The provided callable is currently using", + r"The provided callable <(built-in function (min|max|mean)|function mean at 0x[0-9a-f]+)> is currently using", lower="2.0.99", ): check(assert_type(df.agg(min), pd.Series), pd.Series) @@ -1711,7 +1711,7 @@ def test_types_regressions() -> None: df = pd.DataFrame({"A": [1, 2, 3], "B": [5, 6, 7]}) with pytest_warns_bounded( FutureWarning, - "The 'closed' keyword in DatetimeIndex construction is deprecated", + "The '(closed|normalize)' keyword in DatetimeIndex construction is deprecated", lower="2.0.99", ): pd.DatetimeIndex( diff --git a/tests/test_series.py b/tests/test_series.py index 27d1b94a8..6e5922274 100644 --- a/tests/test_series.py +++ b/tests/test_series.py @@ -944,7 +944,7 @@ def test_types_agg() -> None: check(assert_type(s.agg("mean", axis=0), float), np.float64) with pytest_warns_bounded( FutureWarning, - r"The provided callable is currently using", + r"The provided callable <(built-in function (min|max|mean)|function mean at 0x[0-9a-f]+)> is currently using", lower="2.0.99", ): check(assert_type(s.agg(min), int), np.integer) From 935aa65a2fd3256b52b8acd82e98ce1dd4484267 Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Sun, 4 Feb 2024 16:44:16 +0100 Subject: [PATCH 22/23] Windows tests --- tests/test_frame.py | 2 +- tests/test_series.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_frame.py b/tests/test_frame.py index f0850a658..cd4ace1ff 100644 --- a/tests/test_frame.py +++ b/tests/test_frame.py @@ -1252,7 +1252,7 @@ def test_types_agg() -> None: with pytest_warns_bounded( FutureWarning, - r"The provided callable <(built-in function (min|max|mean)|function mean at 0x[0-9a-f]+)> is currently using", + r"The provided callable <(built-in function (min|max|mean)|function mean at 0x\w+)> is currently using", lower="2.0.99", ): check(assert_type(df.agg(min), pd.Series), pd.Series) diff --git a/tests/test_series.py b/tests/test_series.py index 6e5922274..1c7e8ff17 100644 --- a/tests/test_series.py +++ b/tests/test_series.py @@ -944,7 +944,7 @@ def test_types_agg() -> None: check(assert_type(s.agg("mean", axis=0), float), np.float64) with pytest_warns_bounded( FutureWarning, - r"The provided callable <(built-in function (min|max|mean)|function mean at 0x[0-9a-f]+)> is currently using", + r"The provided callable <(built-in function (min|max|mean)|function mean at 0x\w+)> is currently using", lower="2.0.99", ): check(assert_type(s.agg(min), int), np.integer) From 875cb0de2b353a5a6f5ce27810b79604a351b7ee Mon Sep 17 00:00:00 2001 From: Ali Hamdan Date: Tue, 6 Feb 2024 21:24:12 +0100 Subject: [PATCH 23/23] Apply suggestions from code review --- pandas-stubs/core/groupby/generic.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas-stubs/core/groupby/generic.pyi b/pandas-stubs/core/groupby/generic.pyi index 57f62a143..e14c104eb 100644 --- a/pandas-stubs/core/groupby/generic.pyi +++ b/pandas-stubs/core/groupby/generic.pyi @@ -252,7 +252,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): ) -> DataFrame: ... @overload def boxplot( - grouped, # pyright: ignore[reportSelfClsParameterName] + self, subplots: Literal[True] = ..., column: IndexLabel | None = ..., fontsize: float | str | None = ..., @@ -268,7 +268,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): ) -> Series: ... # Series[PlotAxes] but this is not allowed @overload def boxplot( - grouped, # pyright: ignore[reportSelfClsParameterName] + self, subplots: Literal[False], column: IndexLabel | None = ..., fontsize: float | str | None = ..., @@ -284,7 +284,7 @@ class DataFrameGroupBy(GroupBy[DataFrame], Generic[ByT]): ) -> PlotAxes: ... @overload def boxplot( - grouped, # pyright: ignore[reportSelfClsParameterName] + self, subplots: bool, column: IndexLabel | None = ..., fontsize: float | str | None = ...,