diff --git a/pandas/_config/config.py b/pandas/_config/config.py index b74883dbe5734..6a0e544afafbf 100644 --- a/pandas/_config/config.py +++ b/pandas/_config/config.py @@ -60,8 +60,10 @@ Any, Callable, Generic, + Literal, NamedTuple, cast, + overload, ) import warnings @@ -740,7 +742,23 @@ def _build_option_description(k: str) -> str: return s -def pp_options_list(keys: Iterable[str], width: int = 80, _print: bool = False): +@overload +def pp_options_list( + keys: Iterable[str], *, width: int = ..., _print: Literal[False] = ... +) -> str: + ... + + +@overload +def pp_options_list( + keys: Iterable[str], *, width: int = ..., _print: Literal[True] +) -> None: + ... + + +def pp_options_list( + keys: Iterable[str], *, width: int = 80, _print: bool = False +) -> str | None: """Builds a concise listing of available options, grouped by prefix""" from itertools import groupby from textwrap import wrap @@ -770,8 +788,7 @@ def pp(name: str, ks: Iterable[str]) -> list[str]: s = "\n".join(ls) if _print: print(s) - else: - return s + return s # diff --git a/pandas/_libs/arrays.pyi b/pandas/_libs/arrays.pyi index 86f69c3cdfc75..dda23d9dec98b 100644 --- a/pandas/_libs/arrays.pyi +++ b/pandas/_libs/arrays.pyi @@ -14,9 +14,9 @@ class NDArrayBacked: _ndarray: np.ndarray def __init__(self, values: np.ndarray, dtype: DtypeObj) -> None: ... @classmethod - def _simple_new(cls, values: np.ndarray, dtype: DtypeObj): ... - def _from_backing_data(self, values: np.ndarray): ... - def __setstate__(self, state): ... + def _simple_new(cls, values: np.ndarray, dtype: DtypeObj) -> Self: ... + def _from_backing_data(self, values: np.ndarray) -> Self: ... + def __setstate__(self, state) -> None: ... def __len__(self) -> int: ... @property def shape(self) -> Shape: ... @@ -26,14 +26,14 @@ class NDArrayBacked: def size(self) -> int: ... @property def nbytes(self) -> int: ... - def copy(self, order=...): ... - def delete(self, loc, axis=...): ... - def swapaxes(self, axis1, axis2): ... - def repeat(self, repeats: int | Sequence[int], axis: int | None = ...): ... - def reshape(self, *args, **kwargs): ... - def ravel(self, order=...): ... + def copy(self, order=...) -> Self: ... + def delete(self, loc, axis=...) -> Self: ... + def swapaxes(self, axis1, axis2) -> Self: ... + def repeat(self, repeats: int | Sequence[int], axis: int | None = ...) -> Self: ... + def reshape(self, *args, **kwargs) -> Self: ... + def ravel(self, order=...) -> Self: ... @property - def T(self): ... + def T(self) -> Self: ... @classmethod def _concat_same_type( cls, to_concat: Sequence[Self], axis: AxisInt = ... diff --git a/pandas/_libs/testing.pyi b/pandas/_libs/testing.pyi index 01da496975f51..ab87e58eba9b9 100644 --- a/pandas/_libs/testing.pyi +++ b/pandas/_libs/testing.pyi @@ -1,4 +1,6 @@ -def assert_dict_equal(a, b, compare_keys: bool = ...): ... +from typing import Mapping + +def assert_dict_equal(a: Mapping, b: Mapping, compare_keys: bool = ...) -> bool: ... def assert_almost_equal( a, b, @@ -9,4 +11,4 @@ def assert_almost_equal( lobj=..., robj=..., index_values=..., -): ... +) -> bool: ... diff --git a/pandas/_libs/tslibs/dtypes.pyi b/pandas/_libs/tslibs/dtypes.pyi index 7fdeb88d498ac..dc2855cbecd69 100644 --- a/pandas/_libs/tslibs/dtypes.pyi +++ b/pandas/_libs/tslibs/dtypes.pyi @@ -1,5 +1,7 @@ from enum import Enum +from pandas._typing import Self + OFFSET_TO_PERIOD_FREQSTR: dict[str, str] def periods_per_day(reso: int = ...) -> int: ... @@ -12,7 +14,7 @@ class PeriodDtypeBase: _n: int # actually __cinit__ - def __new__(cls, code: int, n: int): ... + def __new__(cls, code: int, n: int) -> Self: ... @property def _freq_group_code(self) -> int: ... @property diff --git a/pandas/_libs/tslibs/offsets.pyi b/pandas/_libs/tslibs/offsets.pyi index 7eb8dc0813868..434f10a00745f 100644 --- a/pandas/_libs/tslibs/offsets.pyi +++ b/pandas/_libs/tslibs/offsets.pyi @@ -64,7 +64,7 @@ class BaseOffset: @overload def __rsub__(self, other: npt.NDArray[np.object_]) -> npt.NDArray[np.object_]: ... @overload - def __rsub__(self, other: BaseOffset): ... + def __rsub__(self, other: BaseOffset) -> Self: ... @overload def __rsub__(self, other: _DatetimeT) -> _DatetimeT: ... @overload @@ -72,7 +72,7 @@ class BaseOffset: @overload def __mul__(self, other: np.ndarray) -> np.ndarray: ... @overload - def __mul__(self, other: int): ... + def __mul__(self, other: int) -> Self: ... @overload def __rmul__(self, other: np.ndarray) -> np.ndarray: ... @overload @@ -100,7 +100,7 @@ def _get_offset(name: str) -> BaseOffset: ... class SingleConstructorOffset(BaseOffset): @classmethod - def _from_name(cls, suffix: None = ...): ... + def _from_name(cls, suffix: None = ...) -> Self: ... def __reduce__(self): ... @overload diff --git a/pandas/_testing/__init__.py b/pandas/_testing/__init__.py index 3f5fd2e61b0cb..274de33738f5b 100644 --- a/pandas/_testing/__init__.py +++ b/pandas/_testing/__init__.py @@ -482,7 +482,7 @@ def iat(x): _UNITS = ["s", "ms", "us", "ns"] -def get_finest_unit(left: str, right: str): +def get_finest_unit(left: str, right: str) -> str: """ Find the higher of two datetime64 units. """ diff --git a/pandas/core/arrays/_mixins.py b/pandas/core/arrays/_mixins.py index 560845d375b56..adbb971f777b4 100644 --- a/pandas/core/arrays/_mixins.py +++ b/pandas/core/arrays/_mixins.py @@ -89,7 +89,9 @@ def method(self, *args, **kwargs): return cast(F, method) -class NDArrayBackedExtensionArray(NDArrayBacked, ExtensionArray): +# error: Definition of "delete/ravel/T/repeat/copy" in base class "NDArrayBacked" +# is incompatible with definition in base class "ExtensionArray" +class NDArrayBackedExtensionArray(NDArrayBacked, ExtensionArray): # type: ignore[misc] """ ExtensionArray that is backed by a single NumPy ndarray. """ @@ -386,7 +388,7 @@ def fillna( # ------------------------------------------------------------------------ # Reductions - def _wrap_reduction_result(self, axis: AxisInt | None, result): + def _wrap_reduction_result(self, axis: AxisInt | None, result) -> Any: if axis is None or self.ndim == 1: return self._box_func(result) return self._from_backing_data(result) diff --git a/pandas/core/arrays/base.py b/pandas/core/arrays/base.py index 58264f2aef6f3..b5946594fc7fc 100644 --- a/pandas/core/arrays/base.py +++ b/pandas/core/arrays/base.py @@ -1781,7 +1781,7 @@ def _formatter(self, boxed: bool = False) -> Callable[[Any], str | None]: # Reshaping # ------------------------------------------------------------------------ - def transpose(self, *axes: int) -> ExtensionArray: + def transpose(self, *axes: int) -> Self: """ Return a transposed view on this array. @@ -1802,10 +1802,10 @@ def transpose(self, *axes: int) -> ExtensionArray: return self[:] @property - def T(self) -> ExtensionArray: + def T(self) -> Self: return self.transpose() - def ravel(self, order: Literal["C", "F", "A", "K"] | None = "C") -> ExtensionArray: + def ravel(self, order: Literal["C", "F", "A", "K"] | None = "C") -> Self: """ Return a flattened view on this array. diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 9d94cbbc5706e..09f506e117aaa 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -243,7 +243,9 @@ def contains(cat, key, container) -> bool: return any(loc_ in container for loc_ in loc) -class Categorical(NDArrayBackedExtensionArray, PandasObject, ObjectStringArrayMixin): +# error: Definition of "delete/ravel/T/repeat/copy" in base class "NDArrayBacked" +# is incompatible with definition in base class "ExtensionArray" +class Categorical(NDArrayBackedExtensionArray, PandasObject, ObjectStringArrayMixin): # type: ignore[misc] """ Represent a categorical variable in classic R / S-plus fashion. @@ -561,6 +563,7 @@ def astype(self, dtype: AstypeArg, copy: bool = True) -> ArrayLike: object is returned. """ dtype = pandas_dtype(dtype) + result: Categorical | np.ndarray if self.dtype is dtype: result = self.copy() if copy else self @@ -1818,10 +1821,14 @@ def value_counts(self, dropna: bool = True) -> Series: ix = np.append(ix, -1) ix = coerce_indexer_dtype(ix, self.dtype.categories) - ix = self._from_backing_data(ix) + ix_categorical = self._from_backing_data(ix) return Series( - count, index=CategoricalIndex(ix), dtype="int64", name="count", copy=False + count, + index=CategoricalIndex(ix_categorical), + dtype="int64", + name="count", + copy=False, ) # error: Argument 2 of "_empty" is incompatible with supertype @@ -2526,7 +2533,9 @@ def _concat_same_type(cls, to_concat: Sequence[Self], axis: AxisInt = 0) -> Self result = res_flat.reshape(len(first), -1, order="F") return result - result = union_categoricals(to_concat) + # error: Incompatible types in assignment (expression has type "Categorical", + # variable has type "Self") + result = union_categoricals(to_concat) # type: ignore[assignment] return result # ------------------------------------------------------------------ @@ -2666,11 +2675,11 @@ def _replace(self, *, to_replace, value, inplace: bool = False) -> Self | None: new_categories = ser.take(locs) new_categories = new_categories.drop_duplicates(keep="first") - new_categories = Index(new_categories) + index_categories = Index(new_categories) new_codes = recode_for_categories( - cat._codes, all_values, new_categories, copy=False + cat._codes, all_values, index_categories, copy=False ) - new_dtype = CategoricalDtype(new_categories, ordered=self.dtype.ordered) + new_dtype = CategoricalDtype(index_categories, ordered=self.dtype.ordered) NDArrayBacked.__init__(cat, new_codes, new_dtype) if new_dtype != orig_dtype: diff --git a/pandas/core/arrays/interval.py b/pandas/core/arrays/interval.py index 2dbc2a663c8a8..05e8b981f4e8a 100644 --- a/pandas/core/arrays/interval.py +++ b/pandas/core/arrays/interval.py @@ -1727,6 +1727,8 @@ def insert(self, loc: int, item: Interval) -> Self: return self._shallow_copy(new_left, new_right) def delete(self, loc) -> Self: + new_left: np.ndarray | DatetimeArray | TimedeltaArray + new_right: np.ndarray | DatetimeArray | TimedeltaArray if isinstance(self._left, np.ndarray): new_left = np.delete(self._left, loc) assert isinstance(self._right, np.ndarray) diff --git a/pandas/core/arrays/string_.py b/pandas/core/arrays/string_.py index b73b49eca3e18..2272d7e38003d 100644 --- a/pandas/core/arrays/string_.py +++ b/pandas/core/arrays/string_.py @@ -499,10 +499,10 @@ def astype(self, dtype, copy: bool = True): values = arr.astype(dtype.numpy_dtype) return IntegerArray(values, mask, copy=False) elif isinstance(dtype, FloatingDtype): - arr = self.copy() + arr_ea = self.copy() mask = self.isna() - arr[mask] = "0" - values = arr.astype(dtype.numpy_dtype) + arr_ea[mask] = "0" + values = arr_ea.astype(dtype.numpy_dtype) return FloatingArray(values, mask, copy=False) elif isinstance(dtype, ExtensionDtype): # Skip the NumpyExtensionArray.astype method diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index 0f15b2edc0ca8..e8675a6d74746 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -98,7 +98,7 @@ def hist_series( Returns ------- - matplotlib.Axes + matplotlib.axes.Axes A histogram plot. See Also diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 136056e3ff428..6fa75ba5fb12d 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1021,7 +1021,7 @@ def _col_idx_to_axis_idx(self, col_idx: int) -> int: return col_idx @final - def _get_ax(self, i: int): + def _get_ax(self, i: int) -> Axes: # get the twinx ax if appropriate if self.subplots: i = self._col_idx_to_axis_idx(i) @@ -1037,7 +1037,7 @@ def _get_ax(self, i: int): return ax @final - def on_right(self, i: int): + def on_right(self, i: int) -> bool: if isinstance(self.secondary_y, bool): return self.secondary_y @@ -1210,7 +1210,7 @@ def _get_errorbars( return errors @final - def _get_subplots(self, fig: Figure): + def _get_subplots(self, fig: Figure) -> list[Axes]: if Version(mpl.__version__) < Version("3.8"): from matplotlib.axes import Subplot as Klass else: @@ -2100,9 +2100,11 @@ def blank_labeler(label, value): results = ax.pie(y, labels=blabels, **kwds) if kwds.get("autopct", None) is not None: - patches, texts, autotexts = results + # error: Need more than 2 values to unpack (3 expected) + patches, texts, autotexts = results # type: ignore[misc] else: - patches, texts = results + # error: Too many values to unpack (2 expected, 3 provided) + patches, texts = results # type: ignore[misc] autotexts = [] if self.fontsize is not None: diff --git a/pandas/tseries/holiday.py b/pandas/tseries/holiday.py index 646284c79a3ad..650e77b264d14 100644 --- a/pandas/tseries/holiday.py +++ b/pandas/tseries/holiday.py @@ -384,7 +384,7 @@ def register(cls) -> None: holiday_calendars[name] = cls -def get_calendar(name: str): +def get_calendar(name: str) -> AbstractHolidayCalendar: """ Return an instance of a calendar based on its name. @@ -433,7 +433,7 @@ def __init__(self, name: str = "", rules=None) -> None: if rules is not None: self.rules = rules - def rule_from_name(self, name: str): + def rule_from_name(self, name: str) -> Holiday | None: for rule in self.rules: if rule.name == name: return rule diff --git a/pandas/util/_doctools.py b/pandas/util/_doctools.py index 12619abf4baaf..828b7a4591bf2 100644 --- a/pandas/util/_doctools.py +++ b/pandas/util/_doctools.py @@ -9,6 +9,8 @@ if TYPE_CHECKING: from collections.abc import Iterable + from matplotlib.figure import Figure + class TablePlotter: """ @@ -46,7 +48,9 @@ def _get_cells(self, left, right, vertical) -> tuple[int, int]: hcells = sum([self._shape(df)[1] for df in left] + [self._shape(right)[1]]) return hcells, vcells - def plot(self, left, right, labels: Iterable[str] = (), vertical: bool = True): + def plot( + self, left, right, labels: Iterable[str] = (), vertical: bool = True + ) -> Figure: """ Plot left / right DataFrames in specified layout.