From 043b268f773ffaecc7f91ff50f9448c946a5c06a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 30 Sep 2021 22:10:30 -0400 Subject: [PATCH 01/13] TYP: enable disallow_untyped_decorators --- pandas/_libs/properties.pyi | 11 +++++++++++ pandas/_libs/properties.pyx | 12 ++++++------ pandas/core/_numba/executor.py | 3 ++- pandas/core/_numba/kernels/mean_.py | 9 ++++++--- pandas/core/arrays/categorical.py | 4 +++- pandas/core/arrays/period.py | 4 +++- pandas/core/frame.py | 8 ++++++-- pandas/core/groupby/generic.py | 6 +++++- pandas/core/groupby/groupby.py | 4 +++- pandas/core/groupby/numba_.py | 6 ++++-- pandas/core/indexes/base.py | 22 +++++++++++++++++----- pandas/core/indexes/datetimelike.py | 7 +++++-- pandas/core/indexes/extension.py | 8 +++++--- pandas/core/indexes/interval.py | 8 ++++++-- pandas/core/indexes/multi.py | 4 +++- pandas/core/indexes/numeric.py | 10 +++++++--- pandas/core/indexes/period.py | 8 ++++++-- pandas/core/indexes/range.py | 7 +++++-- pandas/core/internals/blocks.py | 4 +++- pandas/core/reshape/reshape.py | 7 ++++++- pandas/core/series.py | 8 ++++++-- pandas/core/strings/accessor.py | 16 +++++++++++----- pandas/core/window/numba_.py | 12 ++++++++---- pandas/core/window/online.py | 3 ++- pyproject.toml | 2 +- 25 files changed, 140 insertions(+), 53 deletions(-) create mode 100644 pandas/_libs/properties.pyi diff --git a/pandas/_libs/properties.pyi b/pandas/_libs/properties.pyi new file mode 100644 index 0000000000000..ff228d9eb7d53 --- /dev/null +++ b/pandas/_libs/properties.pyi @@ -0,0 +1,11 @@ +from typing import ( + Any, + Type, +) + +cache_readonly = property + +class AxisProperty: + def __init__(self, axis: int = ..., doc: str = ...) -> None: ... + def __get__(self, obj: Any, typ: Type) -> Any: ... # TODO + def __set__(self, obj: Any, value: Any) -> None: ... # TODO diff --git a/pandas/_libs/properties.pyx b/pandas/_libs/properties.pyx index 7b786e9c0493d..0ae29a6a641a7 100644 --- a/pandas/_libs/properties.pyx +++ b/pandas/_libs/properties.pyx @@ -10,12 +10,12 @@ from cpython.dict cimport ( cdef class CachedProperty: cdef readonly: - object func, name, __doc__ + object fget, name, __doc__ - def __init__(self, func): - self.func = func - self.name = func.__name__ - self.__doc__ = getattr(func, '__doc__', None) + def __init__(self, fget): + self.fget = fget + self.name = fget.__name__ + self.__doc__ = getattr(fget, '__doc__', None) def __get__(self, obj, typ): if obj is None: @@ -34,7 +34,7 @@ cdef class CachedProperty: # not necessary to Py_INCREF val = PyDict_GetItem(cache, self.name) else: - val = self.func(obj) + val = self.fget(obj) PyDict_SetItem(cache, self.name, val) return val diff --git a/pandas/core/_numba/executor.py b/pandas/core/_numba/executor.py index c666bb1a0ad4b..c2b6191c05152 100644 --- a/pandas/core/_numba/executor.py +++ b/pandas/core/_numba/executor.py @@ -44,7 +44,8 @@ def generate_shared_aggregator( numba = import_optional_dependency("numba") - @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) + # error: Untyped decorator makes function "column_looper" untyped + @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) # type: ignore[misc] def column_looper( values: np.ndarray, start: np.ndarray, diff --git a/pandas/core/_numba/kernels/mean_.py b/pandas/core/_numba/kernels/mean_.py index 8f67dd9b51c06..f3a2c7c2170a8 100644 --- a/pandas/core/_numba/kernels/mean_.py +++ b/pandas/core/_numba/kernels/mean_.py @@ -14,7 +14,8 @@ from pandas.core._numba.kernels.shared import is_monotonic_increasing -@numba.jit(nopython=True, nogil=True, parallel=False) +# error: Untyped decorator makes function "add_mean" untyped +@numba.jit(nopython=True, nogil=True, parallel=False) # type: ignore[misc] def add_mean( val: float, nobs: int, sum_x: float, neg_ct: int, compensation: float ) -> tuple[int, float, int, float]: @@ -29,7 +30,8 @@ def add_mean( return nobs, sum_x, neg_ct, compensation -@numba.jit(nopython=True, nogil=True, parallel=False) +# error: Untyped decorator makes function "remove_mean" untyped +@numba.jit(nopython=True, nogil=True, parallel=False) # type: ignore[misc] def remove_mean( val: float, nobs: int, sum_x: float, neg_ct: int, compensation: float ) -> tuple[int, float, int, float]: @@ -44,7 +46,8 @@ def remove_mean( return nobs, sum_x, neg_ct, compensation -@numba.jit(nopython=True, nogil=True, parallel=False) +# error: Untyped decorator makes function "sliding_mean" untyped +@numba.jit(nopython=True, nogil=True, parallel=False) # type: ignore[misc] def sliding_mean( values: np.ndarray, start: np.ndarray, diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 107cefdf31188..cfe6f48ce031a 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -2703,7 +2703,9 @@ def _get_codes_for_values(values, categories: Index) -> np.ndarray: # Support inferring the correct extension dtype from an array of # scalar objects. e.g. # Categorical(array[Period, Period], categories=PeriodIndex(...)) - cls = categories.dtype.construct_array_type() + # error: Item "dtype[Any]" of "Union[dtype[Any], ExtensionDtype]" has no + # attribute "construct_array_type" + cls = categories.dtype.construct_array_type() # type: ignore[union-attr] values = maybe_cast_to_extension_array(cls, values) if not isinstance(values, cls): # exception raised in _from_sequence diff --git a/pandas/core/arrays/period.py b/pandas/core/arrays/period.py index 84e611659b165..2f36b72229225 100644 --- a/pandas/core/arrays/period.py +++ b/pandas/core/arrays/period.py @@ -669,7 +669,9 @@ def fillna(self, value=None, method=None, limit=None) -> PeriodArray: # view as dt64 so we get treated as timelike in core.missing dta = self.view("M8[ns]") result = dta.fillna(value=value, method=method, limit=limit) - return result.view(self.dtype) + # error: Incompatible return value type (got "Union[ExtensionArray, + # ndarray[Any, Any]]", expected "PeriodArray") + return result.view(self.dtype) # type: ignore[return-value] return super().fillna(value=value, method=method, limit=limit) # ------------------------------------------------------------------ diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 565c153603b86..b8e0c4e5168e2 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -10716,10 +10716,14 @@ def isin(self, values) -> DataFrame: _info_axis_number = 1 _info_axis_name = "columns" - index: Index = properties.AxisProperty( + # error: Incompatible types in assignment (expression has type "AxisProperty", + # variable has type "Index") + index: Index = properties.AxisProperty( # type: ignore[assignment] axis=1, doc="The index (row labels) of the DataFrame." ) - columns: Index = properties.AxisProperty( + # error: Incompatible types in assignment (expression has type "AxisProperty", + # variable has type "Index") + columns: Index = properties.AxisProperty( # type: ignore[assignment] axis=0, doc="The column labels of the DataFrame." ) diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 5f2ee996c26b4..8a330d08bef78 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -675,7 +675,11 @@ def apply_series_value_counts(): # multi-index components codes = self.grouper.reconstructed_codes codes = [rep(level_codes) for level_codes in codes] + [llab(lab, inc)] - levels = [ping.group_index for ping in self.grouper.groupings] + [lev] + # error: List item 0 has incompatible type "Union[ndarray[Any, Any], Index]"; + # expected "Index" + levels = [ping.group_index for ping in self.grouper.groupings] + [ + lev # type: ignore[list-item] + ] names = self.grouper.names + [self.obj.name] if dropna: diff --git a/pandas/core/groupby/groupby.py b/pandas/core/groupby/groupby.py index 77281441c2ed2..d583c2fc6dd9e 100644 --- a/pandas/core/groupby/groupby.py +++ b/pandas/core/groupby/groupby.py @@ -3449,7 +3449,9 @@ def _reindex_output( levels_list = [ping.group_index for ping in groupings] names = self.grouper.names if qs is not None: - levels_list.append(qs) + # error: Argument 1 to "append" of "list" has incompatible type + # "ndarray[Any, dtype[floating[_64Bit]]]"; expected "Index" + levels_list.append(qs) # type: ignore[arg-type] names = names + [None] index, _ = MultiIndex.from_product(levels_list, names=names).sortlevel() diff --git a/pandas/core/groupby/numba_.py b/pandas/core/groupby/numba_.py index beb77360d5a3f..ea295af8d7910 100644 --- a/pandas/core/groupby/numba_.py +++ b/pandas/core/groupby/numba_.py @@ -92,7 +92,8 @@ def generate_numba_agg_func( numba_func = jit_user_function(func, nopython, nogil, parallel) numba = import_optional_dependency("numba") - @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) + # error: Untyped decorator makes function "group_agg" untyped + @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) # type: ignore[misc] def group_agg( values: np.ndarray, index: np.ndarray, @@ -153,7 +154,8 @@ def generate_numba_transform_func( numba_func = jit_user_function(func, nopython, nogil, parallel) numba = import_optional_dependency("numba") - @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) + # error: Untyped decorator makes function "group_transform" untyped + @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) # type: ignore[misc] def group_transform( values: np.ndarray, index: np.ndarray, diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index e82bd61938f15..d6dcb7fe45d92 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -3681,7 +3681,11 @@ def _get_indexer( else: tgt_values = target._get_engine_target() if target._is_multi and self._is_multi: - tgt_values = self._engine._extract_level_codes(target) + engine = self._engine + # error: "IndexEngine" has no attribute "_extract_level_codes" + tgt_values = engine._extract_level_codes( # type: ignore[attr-defined] + target + ) indexer = self._engine.get_indexer(tgt_values) @@ -3758,7 +3762,8 @@ def _get_fill_indexer( if self._is_multi: # TODO: get_indexer_with_fill docstring says values must be _sorted_ # but that doesn't appear to be enforced - return self._engine.get_indexer_with_fill( + # error: "IndexEngine" has no attribute "get_indexer_with_fill" + return self._engine.get_indexer_with_fill( # type: ignore[attr-defined] target=target._values, values=self._values, method=method, limit=limit ) @@ -4677,7 +4682,8 @@ def values(self) -> ArrayLike: """ return self._data - @cache_readonly + # error: Decorated property not supported + @cache_readonly # type: ignore[misc] @doc(IndexOpsMixin.array) def array(self) -> ExtensionArray: array = self._data @@ -5596,7 +5602,11 @@ def get_indexer_non_unique( # self and non-Multi target tgt_values = target._get_engine_target() if self._is_multi and target._is_multi: - tgt_values = self._engine._extract_level_codes(target) + engine = self._engine + # error: "IndexEngine" has no attribute "_extract_level_codes" + tgt_values = engine._extract_level_codes( # type: ignore[attr-defined] + target + ) indexer, missing = self._engine.get_indexer_non_unique(tgt_values) return ensure_platform_int(indexer), ensure_platform_int(missing) @@ -7049,7 +7059,9 @@ def unpack_nested_dtype(other: _IndexT) -> _IndexT: if is_categorical_dtype(dtype): # If there is ever a SparseIndex, this could get dispatched # here too. - return dtype.categories + # error: Item "dtype[Any]"/"ExtensionDtype" of "Union[dtype[Any], + # ExtensionDtype]" has no attribute "categories" + return dtype.categories # type: ignore[union-attr] return other diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index 791c1110e3cd2..a0902a5fb32fe 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -95,8 +95,11 @@ class DatetimeIndexOpsMixin(NDArrayBackedExtensionIndex): _field_ops: list[str] = [] # error: "Callable[[Any], Any]" has no attribute "fget" - hasnans = cache_readonly( - DatetimeLikeArrayMixin._hasnans.fget # type: ignore[attr-defined] + hasnans = cast( + bool, + cache_readonly( + DatetimeLikeArrayMixin._hasnans.fget # type: ignore[attr-defined] + ), ) @property diff --git a/pandas/core/indexes/extension.py b/pandas/core/indexes/extension.py index 7c7f1b267b5be..e7b37dfbf307d 100644 --- a/pandas/core/indexes/extension.py +++ b/pandas/core/indexes/extension.py @@ -81,8 +81,9 @@ def fset(self, value): method = attr else: - - def method(self, *args, **kwargs): + # error: Incompatible redefinition (redefinition with type "Callable[[Any, + # VarArg(Any), KwArg(Any)], Any]", original type "property") + def method(self, *args, **kwargs): # type: ignore[misc] if "inplace" in kwargs: raise ValueError(f"cannot use inplace with {type(self).__name__}") result = attr(self._data, *args, **kwargs) @@ -94,7 +95,8 @@ def method(self, *args, **kwargs): return Index(result, name=self.name) return result - method.__name__ = name + # error: "property" has no attribute "__name__" + method.__name__ = name # type: ignore[attr-defined] method.__doc__ = attr.__doc__ return method diff --git a/pandas/core/indexes/interval.py b/pandas/core/indexes/interval.py index 72398ab9d43f6..5791f89828ca3 100644 --- a/pandas/core/indexes/interval.py +++ b/pandas/core/indexes/interval.py @@ -531,7 +531,9 @@ def _maybe_convert_i8(self, key): key_i8 = key_i8.where(~key._isnan) # ensure consistency with IntervalIndex subtype - subtype = self.dtype.subtype + # error: Item "ExtensionDtype"/"dtype[Any]" of "Union[dtype[Any], + # ExtensionDtype]" has no attribute "subtype" + subtype = self.dtype.subtype # type: ignore[union-attr] if not is_dtype_equal(subtype, key_dtype): raise ValueError( @@ -766,7 +768,9 @@ def _convert_slice_indexer(self, key: slice, kind: str): def _should_fallback_to_positional(self) -> bool: # integer lookups in Series.__getitem__ are unambiguously # positional in this case - return self.dtype.subtype.kind in ["m", "M"] + # error: Item "ExtensionDtype"/"dtype[Any]" of "Union[dtype[Any], + # ExtensionDtype]" has no attribute "subtype" + return self.dtype.subtype.kind in ["m", "M"] # type: ignore[union-attr] def _maybe_cast_slice_bound(self, label, side: str, kind=lib.no_default): self._deprecated_arg(kind, "kind", "_maybe_cast_slice_bound") diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index e2f1a2d6a1e23..d753307aea109 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -1095,8 +1095,10 @@ def _engine(self): return MultiIndexPyIntEngine(self.levels, self.codes, offsets) return MultiIndexUIntEngine(self.levels, self.codes, offsets) + # Return type "Callable[..., MultiIndex]" of "_constructor" incompatible with return + # type "Type[MultiIndex]" in supertype "Index" @property - def _constructor(self) -> Callable[..., MultiIndex]: + def _constructor(self) -> Callable[..., MultiIndex]: # type: ignore[override] return type(self).from_tuples @doc(Index._shallow_copy) diff --git a/pandas/core/indexes/numeric.py b/pandas/core/indexes/numeric.py index 8e8ed294304c5..40aa70a2ada2f 100644 --- a/pandas/core/indexes/numeric.py +++ b/pandas/core/indexes/numeric.py @@ -101,8 +101,9 @@ class NumericIndex(Index): _can_hold_strings = False _is_backward_compat_public_numeric_index: bool = True + # error: Signature of "_can_hold_na" incompatible with supertype "Index" @cache_readonly - def _can_hold_na(self) -> bool: + def _can_hold_na(self) -> bool: # type: ignore[override] if is_float_dtype(self.dtype): return True else: @@ -123,7 +124,9 @@ def _can_hold_na(self) -> bool: @property def _engine_type(self): - return self._engine_types[self.dtype] + # error: Invalid index type "Union[dtype[Any], ExtensionDtype]" for + # "Dict[dtype[Any], Type[IndexEngine]]"; expected type "dtype[Any]" + return self._engine_types[self.dtype] # type: ignore[index] @cache_readonly def inferred_type(self) -> str: @@ -264,7 +267,8 @@ def astype(self, dtype, copy=True): # ---------------------------------------------------------------- # Indexing Methods - @cache_readonly + # error: Decorated property not supported + @cache_readonly # type: ignore[misc] @doc(Index._should_fallback_to_positional) def _should_fallback_to_positional(self) -> bool: return False diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index e422f2bc3ff9a..e80a88826e4ed 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -434,7 +434,9 @@ def get_loc(self, key, method=None, tolerance=None): # TODO: pass if method is not None, like DTI does? raise KeyError(key) from err - if reso == self.dtype.resolution: + # error: Item "ExtensionDtype"/"dtype[Any]" of "Union[dtype[Any], + # ExtensionDtype]" has no attribute "resolution" + if reso == self.dtype.resolution: # type: ignore[union-attr] # the reso < self.dtype.resolution case goes through _get_string_slice key = Period(parsed, freq=self.freq) loc = self.get_loc(key, method=method, tolerance=tolerance) @@ -487,7 +489,9 @@ def _parsed_string_to_bounds(self, reso: Resolution, parsed: datetime): def _can_partial_date_slice(self, reso: Resolution) -> bool: assert isinstance(reso, Resolution), (type(reso), reso) # e.g. test_getitem_setitem_periodindex - return reso > self.dtype.resolution + # error: Item "ExtensionDtype"/"dtype[Any]" of "Union[dtype[Any], + # ExtensionDtype]" has no attribute "resolution" + return reso > self.dtype.resolution # type: ignore[union-attr] def period_range( diff --git a/pandas/core/indexes/range.py b/pandas/core/indexes/range.py index 3fae0fbe7d2a0..8aedc56d8e1cd 100644 --- a/pandas/core/indexes/range.py +++ b/pandas/core/indexes/range.py @@ -177,13 +177,16 @@ def _simple_new(cls, values: range, name: Hashable = None) -> RangeIndex: # -------------------------------------------------------------------- + # error: Return type "Type[Int64Index]" of "_constructor" incompatible with return + # type "Type[RangeIndex]" in supertype "Index" @cache_readonly - def _constructor(self) -> type[Int64Index]: + def _constructor(self) -> type[Int64Index]: # type: ignore[override] """return the class to use for construction""" return Int64Index + # error: Signature of "_data" incompatible with supertype "Index" @cache_readonly - def _data(self) -> np.ndarray: + def _data(self) -> np.ndarray: # type: ignore[override] """ An int array that for performance reasons is created only when needed. diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 57f07313ebdc4..e461706aab760 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -1593,7 +1593,9 @@ def where(self, other, cond, errors="raise") -> list[Block]: # The default `other` for Series / Frame is np.nan # we want to replace that with the correct NA value # for the type - other = self.dtype.na_value + # error: Item "dtype[Any]" of "Union[dtype[Any], ExtensionDtype]" has no + # attribute "na_value" + other = self.dtype.na_value # type: ignore[union-attr] try: result = self.values._where(cond, other) diff --git a/pandas/core/reshape/reshape.py b/pandas/core/reshape/reshape.py index 567f0c20bbfd5..813c4282e543a 100644 --- a/pandas/core/reshape/reshape.py +++ b/pandas/core/reshape/reshape.py @@ -313,7 +313,12 @@ def get_new_columns(self, value_columns: Index | None): new_codes = [lab.take(propagator) for lab in value_columns.codes] else: - new_levels = [value_columns, self.removed_level_full] + # error: Incompatible types in assignment (expression has type "List[Any]", + # variable has type "FrozenList") + new_levels = [ # type: ignore[assignment] + value_columns, + self.removed_level_full, + ] new_names = [value_columns.name, self.removed_name] new_codes = [propagator] diff --git a/pandas/core/series.py b/pandas/core/series.py index 15715af05f904..c4d7a255182a7 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -302,7 +302,9 @@ class Series(base.IndexOpsMixin, generic.NDFrame): # error: Incompatible types in assignment (expression has type "property", # base class "IndexOpsMixin" defined the type as "Callable[[IndexOpsMixin], bool]") hasnans = property( # type: ignore[assignment] - base.IndexOpsMixin.hasnans.func, doc=base.IndexOpsMixin.hasnans.__doc__ + # error: "Callable[[IndexOpsMixin], bool]" has no attribute "fget" + base.IndexOpsMixin.hasnans.fget, # type: ignore[attr-defined] + doc=base.IndexOpsMixin.hasnans.__doc__, ) _mgr: SingleManager div: Callable[[Series, Any], Series] @@ -5474,7 +5476,9 @@ def mask( _info_axis_number = 0 _info_axis_name = "index" - index: Index = properties.AxisProperty( + # error: Incompatible types in assignment (expression has type "AxisProperty", + # variable has type "Index") + index: Index = properties.AxisProperty( # type: ignore[assignment] axis=0, doc="The index (axis labels) of the Series." ) diff --git a/pandas/core/strings/accessor.py b/pandas/core/strings/accessor.py index 4ea29edb7d41b..a62d701413bf1 100644 --- a/pandas/core/strings/accessor.py +++ b/pandas/core/strings/accessor.py @@ -1,19 +1,23 @@ from __future__ import annotations import codecs -from collections.abc import Callable # noqa: PDF001 from functools import wraps import re from typing import ( TYPE_CHECKING, + Callable, Hashable, + cast, ) import warnings import numpy as np import pandas._libs.lib as lib -from pandas._typing import DtypeObj +from pandas._typing import ( + DtypeObj, + F, +) from pandas.util._decorators import Appender from pandas.core.dtypes.common import ( @@ -56,7 +60,9 @@ _cpython_optimized_decoders = _cpython_optimized_encoders + ("utf-16", "utf-32") -def forbid_nonstring_types(forbidden, name=None): +def forbid_nonstring_types( + forbidden: list[str] | None, name: str | None = None +) -> Callable[[F], F]: """ Decorator to forbid specific types for a method of StringMethods. @@ -104,7 +110,7 @@ def forbid_nonstring_types(forbidden, name=None): forbidden ) - def _forbid_nonstring_types(func): + def _forbid_nonstring_types(func: F) -> F: func_name = func.__name__ if name is None else name @wraps(func) @@ -118,7 +124,7 @@ def wrapper(self, *args, **kwargs): return func(self, *args, **kwargs) wrapper.__name__ = func_name - return wrapper + return cast(F, wrapper) return _forbid_nonstring_types diff --git a/pandas/core/window/numba_.py b/pandas/core/window/numba_.py index f41711a4d1f19..d1820133bd4e8 100644 --- a/pandas/core/window/numba_.py +++ b/pandas/core/window/numba_.py @@ -57,7 +57,8 @@ def generate_numba_apply_func( numba_func = jit_user_function(func, nopython, nogil, parallel) numba = import_optional_dependency("numba") - @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) + # error: Untyped decorator makes function "roll_apply" untyped + @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) # type: ignore[misc] def roll_apply( values: np.ndarray, begin: np.ndarray, @@ -115,7 +116,8 @@ def generate_numba_ewm_func( numba = import_optional_dependency("numba") - @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) + # error: Untyped decorator makes function "ewma" untyped + @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) # type: ignore[misc] def ewm( values: np.ndarray, begin: np.ndarray, @@ -216,7 +218,8 @@ def generate_numba_table_func( numba_func = jit_user_function(func, nopython, nogil, parallel) numba = import_optional_dependency("numba") - @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) + # error: Untyped decorator makes function "roll_table" untyped + @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) # type: ignore[misc] def roll_table( values: np.ndarray, begin: np.ndarray, @@ -294,7 +297,8 @@ def generate_numba_ewm_table_func( numba = import_optional_dependency("numba") - @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) + # error: Untyped decorator makes function "ewm_table" untyped + @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) # type: ignore[misc] def ewm_table( values: np.ndarray, begin: np.ndarray, diff --git a/pandas/core/window/online.py b/pandas/core/window/online.py index 5a9e8d65255ae..e8804936da78f 100644 --- a/pandas/core/window/online.py +++ b/pandas/core/window/online.py @@ -33,7 +33,8 @@ def generate_online_numba_ewma_func(engine_kwargs: Optional[Dict[str, bool]]): numba = import_optional_dependency("numba") - @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) + # error: Untyped decorator makes function "online_ewma" untyped + @numba.jit(nopython=nopython, nogil=nogil, parallel=parallel) # type: ignore[misc] def online_ewma( values: np.ndarray, deltas: np.ndarray, diff --git a/pyproject.toml b/pyproject.toml index f329784d050e0..1a70d6cbae44c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,7 +82,7 @@ disallow_untyped_calls = false # TODO disallow_untyped_defs = false # TODO disallow_incomplete_defs = false # TODO check_untyped_defs = true -disallow_untyped_decorators = false # GH#33455 +disallow_untyped_decorators = true # None and Optional handling no_implicit_optional = true strict_optional = true From 1065856f39e97fb081812dce7fd6876b963df832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Wed, 13 Oct 2021 13:30:35 -0400 Subject: [PATCH 02/13] one more --- pandas/core/indexes/extension.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pandas/core/indexes/extension.py b/pandas/core/indexes/extension.py index e7b37dfbf307d..28a0b43d5b02b 100644 --- a/pandas/core/indexes/extension.py +++ b/pandas/core/indexes/extension.py @@ -3,7 +3,10 @@ """ from __future__ import annotations -from typing import TypeVar +from typing import ( + Callable, + TypeVar, +) import numpy as np @@ -23,9 +26,12 @@ from pandas.core.indexes.base import Index _T = TypeVar("_T", bound="NDArrayBackedExtensionIndex") +_ExtensionIndexT = TypeVar("_ExtensionIndexT", bound="ExtensionIndex") -def _inherit_from_data(name: str, delegate, cache: bool = False, wrap: bool = False): +def _inherit_from_data( + name: str, delegate: type, cache: bool = False, wrap: bool = False +): """ Make an alias for a method of the underlying ExtensionArray. @@ -101,7 +107,9 @@ def method(self, *args, **kwargs): # type: ignore[misc] return method -def inherit_names(names: list[str], delegate, cache: bool = False, wrap: bool = False): +def inherit_names( + names: list[str], delegate: type, cache: bool = False, wrap: bool = False +) -> Callable[[type[_ExtensionIndexT]], type[_ExtensionIndexT]]: """ Class decorator to pin attributes from an ExtensionArray to a Index subclass. @@ -114,7 +122,7 @@ def inherit_names(names: list[str], delegate, cache: bool = False, wrap: bool = Whether to wrap the inherited result in an Index. """ - def wrapper(cls): + def wrapper(cls: type[_ExtensionIndexT]) -> type[_ExtensionIndexT]: for name in names: meth = _inherit_from_data(name, delegate, cache=cache, wrap=wrap) setattr(cls, name, meth) From 456c4ba4ba6b74d6b142c4eb8e1876e400a3174f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Mon, 18 Oct 2021 17:51:25 -0400 Subject: [PATCH 03/13] use type instead of typing.Type --- pandas/_libs/properties.pyi | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pandas/_libs/properties.pyi b/pandas/_libs/properties.pyi index ff228d9eb7d53..481de4202718e 100644 --- a/pandas/_libs/properties.pyi +++ b/pandas/_libs/properties.pyi @@ -1,11 +1,10 @@ from typing import ( - Any, - Type, + Any ) cache_readonly = property class AxisProperty: def __init__(self, axis: int = ..., doc: str = ...) -> None: ... - def __get__(self, obj: Any, typ: Type) -> Any: ... # TODO + def __get__(self, obj: Any, typ: type) -> Any: ... # TODO def __set__(self, obj: Any, value: Any) -> None: ... # TODO From da798fa42879bed2a315c6f59fdd38b8b8a2beb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Mon, 18 Oct 2021 17:52:31 -0400 Subject: [PATCH 04/13] black --- pandas/_libs/properties.pyi | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pandas/_libs/properties.pyi b/pandas/_libs/properties.pyi index 481de4202718e..286813ff24d0f 100644 --- a/pandas/_libs/properties.pyi +++ b/pandas/_libs/properties.pyi @@ -1,6 +1,4 @@ -from typing import ( - Any -) +from typing import Any cache_readonly = property From 590dd415a803057e3befbfed8899933f2ec0d2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 21 Oct 2021 12:38:47 -0400 Subject: [PATCH 05/13] enable pyright's rule but skip two files --- pandas/conftest.py | 1 + pandas/core/util/numba_.py | 1 + pyproject.toml | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/conftest.py b/pandas/conftest.py index 75711b19dfcfd..1e1d14f46cc6e 100644 --- a/pandas/conftest.py +++ b/pandas/conftest.py @@ -17,6 +17,7 @@ - Dtypes - Misc """ +# pyright: reportUntypedFunctionDecorator = false from collections import abc from datetime import ( diff --git a/pandas/core/util/numba_.py b/pandas/core/util/numba_.py index 03a0157a8bde4..c738213d4c487 100644 --- a/pandas/core/util/numba_.py +++ b/pandas/core/util/numba_.py @@ -1,4 +1,5 @@ """Common utilities for Numba operations""" +# pyright: reportUntypedFunctionDecorator = false from __future__ import annotations import types diff --git a/pyproject.toml b/pyproject.toml index 1a70d6cbae44c..7966e94cff2f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -176,7 +176,6 @@ reportUnnecessaryComparison = false reportUnnecessaryIsInstance = false reportUnsupportedDunderAll = false reportUntypedBaseClass = false -reportUntypedFunctionDecorator = false reportUnusedClass = false reportUnusedFunction = false reportUnusedImport = false From 7325a6b1cf604b565326769d7fda6247a558c7f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 21 Oct 2021 12:44:25 -0400 Subject: [PATCH 06/13] partial stub --- pandas/_libs/properties.pyi | 5 +---- pandas/core/frame.py | 8 ++------ pandas/core/series.py | 4 +--- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/pandas/_libs/properties.pyi b/pandas/_libs/properties.pyi index 286813ff24d0f..1942074f1fc43 100644 --- a/pandas/_libs/properties.pyi +++ b/pandas/_libs/properties.pyi @@ -2,7 +2,4 @@ from typing import Any cache_readonly = property -class AxisProperty: - def __init__(self, axis: int = ..., doc: str = ...) -> None: ... - def __get__(self, obj: Any, typ: type) -> Any: ... # TODO - def __set__(self, obj: Any, value: Any) -> None: ... # TODO +def __getattr__(name: str) -> Any: ... # incomplete diff --git a/pandas/core/frame.py b/pandas/core/frame.py index b8e0c4e5168e2..565c153603b86 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -10716,14 +10716,10 @@ def isin(self, values) -> DataFrame: _info_axis_number = 1 _info_axis_name = "columns" - # error: Incompatible types in assignment (expression has type "AxisProperty", - # variable has type "Index") - index: Index = properties.AxisProperty( # type: ignore[assignment] + index: Index = properties.AxisProperty( axis=1, doc="The index (row labels) of the DataFrame." ) - # error: Incompatible types in assignment (expression has type "AxisProperty", - # variable has type "Index") - columns: Index = properties.AxisProperty( # type: ignore[assignment] + columns: Index = properties.AxisProperty( axis=0, doc="The column labels of the DataFrame." ) diff --git a/pandas/core/series.py b/pandas/core/series.py index c4d7a255182a7..39cf884e21e31 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -5476,9 +5476,7 @@ def mask( _info_axis_number = 0 _info_axis_name = "index" - # error: Incompatible types in assignment (expression has type "AxisProperty", - # variable has type "Index") - index: Index = properties.AxisProperty( # type: ignore[assignment] + index: Index = properties.AxisProperty( axis=0, doc="The index (axis labels) of the Series." ) From 89be59349fc10aff753274ad0780a2f5ed28fbbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 21 Oct 2021 12:48:44 -0400 Subject: [PATCH 07/13] ignore incomplete stub for pyright --- pandas/_libs/properties.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/_libs/properties.pyi b/pandas/_libs/properties.pyi index 1942074f1fc43..b323df40768ed 100644 --- a/pandas/_libs/properties.pyi +++ b/pandas/_libs/properties.pyi @@ -1,3 +1,4 @@ +# pyright: reportIncompleteStub = false from typing import Any cache_readonly = property From c13c0cdbd1da6557a941c6d14dae42d0dfaa61d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 21 Oct 2021 13:33:14 -0400 Subject: [PATCH 08/13] note on lie --- pandas/_libs/properties.pyi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pandas/_libs/properties.pyi b/pandas/_libs/properties.pyi index b323df40768ed..b2ba55aefb8a5 100644 --- a/pandas/_libs/properties.pyi +++ b/pandas/_libs/properties.pyi @@ -1,6 +1,9 @@ # pyright: reportIncompleteStub = false from typing import Any +# 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 def __getattr__(name: str) -> Any: ... # incomplete From cd61bdd105b253804ec4064043d751f3cf419aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Fri, 22 Oct 2021 09:10:03 -0400 Subject: [PATCH 09/13] pyright comment after removing numba wrapper --- pandas/core/window/numba_.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/core/window/numba_.py b/pandas/core/window/numba_.py index d1820133bd4e8..74dc104b6db90 100644 --- a/pandas/core/window/numba_.py +++ b/pandas/core/window/numba_.py @@ -1,3 +1,4 @@ +# pyright: reportUntypedFunctionDecorator = false from __future__ import annotations import functools From baf088f7c9b801d4c6407c9470cc285e0133393a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Fri, 22 Oct 2021 12:17:35 -0400 Subject: [PATCH 10/13] use isinstance --- pandas/core/arrays/categorical.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index cfe6f48ce031a..9f54e917c19db 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -2699,13 +2699,10 @@ def _get_codes_for_values(values, categories: Index) -> np.ndarray: """ dtype_equal = is_dtype_equal(values.dtype, categories.dtype) - if is_extension_array_dtype(categories.dtype) and is_object_dtype(values): + if isinstance(categories.dtype, ExtensionDtype) and is_object_dtype(values): # Support inferring the correct extension dtype from an array of # scalar objects. e.g. - # Categorical(array[Period, Period], categories=PeriodIndex(...)) - # error: Item "dtype[Any]" of "Union[dtype[Any], ExtensionDtype]" has no - # attribute "construct_array_type" - cls = categories.dtype.construct_array_type() # type: ignore[union-attr] + cls = categories.dtype.construct_array_type() values = maybe_cast_to_extension_array(cls, values) if not isinstance(values, cls): # exception raised in _from_sequence From 966418b685a893c28ac6819fec250aee49da7eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Fri, 29 Oct 2021 20:35:50 -0400 Subject: [PATCH 11/13] new numbas --- pandas/core/_numba/kernels/shared.py | 5 ++++- pandas/core/_numba/kernels/sum_.py | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pandas/core/_numba/kernels/shared.py b/pandas/core/_numba/kernels/shared.py index d84e409ca879d..7c2e7636c7d81 100644 --- a/pandas/core/_numba/kernels/shared.py +++ b/pandas/core/_numba/kernels/shared.py @@ -2,7 +2,10 @@ import numpy as np -@numba.jit(numba.boolean(numba.int64[:]), nopython=True, nogil=True, parallel=False) +# error: Untyped decorator makes function "is_monotonic_increasing" untyped +@numba.jit( # type: ignore[misc] + numba.boolean(numba.int64[:]), nopython=True, nogil=True, parallel=False +) def is_monotonic_increasing(bounds: np.ndarray) -> bool: """Check if int64 values are monotonically increasing.""" n = len(bounds) diff --git a/pandas/core/_numba/kernels/sum_.py b/pandas/core/_numba/kernels/sum_.py index c2e81b4990ba9..0439953bf47ec 100644 --- a/pandas/core/_numba/kernels/sum_.py +++ b/pandas/core/_numba/kernels/sum_.py @@ -13,8 +13,8 @@ from pandas.core._numba.kernels.shared import is_monotonic_increasing - -@numba.jit(nopython=True, nogil=True, parallel=False) +# error: Untyped decorator makes function "add_sum" untyped +@numba.jit(nopython=True, nogil=True, parallel=False) # type: ignore[misc] def add_sum( val: float, nobs: int, sum_x: float, compensation: float ) -> tuple[int, float, float]: @@ -27,7 +27,8 @@ def add_sum( return nobs, sum_x, compensation -@numba.jit(nopython=True, nogil=True, parallel=False) +# error: Untyped decorator makes function "remove_sum" untyped +@numba.jit(nopython=True, nogil=True, parallel=False) # type: ignore[misc] def remove_sum( val: float, nobs: int, sum_x: float, compensation: float ) -> tuple[int, float, float]: @@ -40,7 +41,8 @@ def remove_sum( return nobs, sum_x, compensation -@numba.jit(nopython=True, nogil=True, parallel=False) +# error: Untyped decorator makes function "sliding_sum" untyped +@numba.jit(nopython=True, nogil=True, parallel=False) # type: ignore[misc] def sliding_sum( values: np.ndarray, start: np.ndarray, From 4e083784872bdf4c486b9c38e505bb4fd7e0cc29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Fri, 29 Oct 2021 21:48:25 -0400 Subject: [PATCH 12/13] empty line --- pandas/core/_numba/kernels/sum_.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pandas/core/_numba/kernels/sum_.py b/pandas/core/_numba/kernels/sum_.py index 0439953bf47ec..66a1587c49f3f 100644 --- a/pandas/core/_numba/kernels/sum_.py +++ b/pandas/core/_numba/kernels/sum_.py @@ -13,6 +13,7 @@ from pandas.core._numba.kernels.shared import is_monotonic_increasing + # error: Untyped decorator makes function "add_sum" untyped @numba.jit(nopython=True, nogil=True, parallel=False) # type: ignore[misc] def add_sum( From bf8026be94b3156d329d64110fb738cdc12b8185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sat, 30 Oct 2021 07:54:55 -0400 Subject: [PATCH 13/13] comments --- pandas/core/arrays/categorical.py | 1 + pandas/core/indexes/base.py | 1 + 2 files changed, 2 insertions(+) diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py index 9f54e917c19db..c7f587b35f557 100644 --- a/pandas/core/arrays/categorical.py +++ b/pandas/core/arrays/categorical.py @@ -2702,6 +2702,7 @@ def _get_codes_for_values(values, categories: Index) -> np.ndarray: if isinstance(categories.dtype, ExtensionDtype) and is_object_dtype(values): # Support inferring the correct extension dtype from an array of # scalar objects. e.g. + # Categorical(array[Period, Period], categories=PeriodIndex(...)) cls = categories.dtype.construct_array_type() values = maybe_cast_to_extension_array(cls, values) if not isinstance(values, cls): diff --git a/pandas/core/indexes/base.py b/pandas/core/indexes/base.py index d6dcb7fe45d92..7ad24015ac371 100644 --- a/pandas/core/indexes/base.py +++ b/pandas/core/indexes/base.py @@ -4683,6 +4683,7 @@ def values(self) -> ArrayLike: return self._data # error: Decorated property not supported + # https://github.com/python/mypy/issues/1362 @cache_readonly # type: ignore[misc] @doc(IndexOpsMixin.array) def array(self) -> ExtensionArray: