From 76a998c228f35fd33581734297cd5babbf47dc64 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 10 Feb 2023 10:22:28 -0800 Subject: [PATCH 01/15] TYP: TypeGuard --- pandas/_libs/lib.pyi | 19 +++++++++++-------- pandas/core/arrays/datetimelike.py | 1 - pandas/core/dtypes/cast.py | 10 ++-------- pandas/core/dtypes/inference.py | 17 +++++++++++++---- pandas/core/frame.py | 6 +----- pandas/core/generic.py | 1 + pandas/core/indexes/api.py | 8 ++++++-- pandas/core/indexes/multi.py | 1 + pandas/core/indexes/period.py | 2 +- pandas/core/indexing.py | 4 ++-- pandas/core/window/rolling.py | 2 +- pandas/io/parsers/python_parser.py | 2 +- pandas/io/sql.py | 1 + 13 files changed, 41 insertions(+), 33 deletions(-) diff --git a/pandas/_libs/lib.pyi b/pandas/_libs/lib.pyi index fbc577712d294..6f0f7479269e3 100644 --- a/pandas/_libs/lib.pyi +++ b/pandas/_libs/lib.pyi @@ -1,6 +1,6 @@ # TODO(npdtypes): Many types specified here can be made more specific/accurate; # the more specific versions are specified in comments - +from decimal import Decimal from typing import ( Any, Callable, @@ -12,7 +12,10 @@ from typing import ( ) import numpy as np +from typing_extensions import TypeGuard +from pandas._libs.interval import Interval +from pandas._libs.tslibs import Period from pandas._typing import ( ArrayLike, DtypeObj, @@ -38,13 +41,13 @@ def infer_dtype(value: object, skipna: bool = ...) -> str: ... def is_iterator(obj: object) -> bool: ... def is_scalar(val: object) -> bool: ... def is_list_like(obj: object, allow_sets: bool = ...) -> bool: ... -def is_period(val: object) -> bool: ... -def is_interval(val: object) -> bool: ... -def is_decimal(val: object) -> bool: ... -def is_complex(val: object) -> bool: ... -def is_bool(val: object) -> bool: ... -def is_integer(val: object) -> bool: ... -def is_float(val: object) -> bool: ... +def is_period(val: object) -> TypeGuard[Period]: ... +def is_interval(val: object) -> TypeGuard[Interval]: ... +def is_decimal(val: object) -> TypeGuard[Decimal]: ... +def is_complex(val: object) -> TypeGuard[complex | np.complex_]: ... +def is_bool(val: object) -> TypeGuard[bool | np.bool_]: ... +def is_integer(val: object) -> TypeGuard[int | np.integer]: ... +def is_float(val: object) -> TypeGuard[float | np.floating]: ... def is_interval_array(values: np.ndarray) -> bool: ... def is_datetime64_array(values: np.ndarray) -> bool: ... def is_timedelta_or_timedelta64_array(values: np.ndarray) -> bool: ... diff --git a/pandas/core/arrays/datetimelike.py b/pandas/core/arrays/datetimelike.py index 8c537a5082585..bd3d4b57c6d63 100644 --- a/pandas/core/arrays/datetimelike.py +++ b/pandas/core/arrays/datetimelike.py @@ -2182,7 +2182,6 @@ def validate_periods(periods: int | float | None) -> int | None: periods = int(periods) elif not lib.is_integer(periods): raise TypeError(f"periods must be a number, got {periods}") - periods = cast(int, periods) return periods diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index e9da7598d1ebc..aa43c53d3c56c 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -194,15 +194,9 @@ def maybe_box_native(value: Scalar | None | NAType) -> Scalar | None | NAType: scalar or Series """ if is_float(value): - # error: Argument 1 to "float" has incompatible type - # "Union[Union[str, int, float, bool], Union[Any, Timestamp, Timedelta, Any]]"; - # expected "Union[SupportsFloat, _SupportsIndex, str]" - value = float(value) # type: ignore[arg-type] + value = float(value) elif is_integer(value): - # error: Argument 1 to "int" has incompatible type - # "Union[Union[str, int, float, bool], Union[Any, Timestamp, Timedelta, Any]]"; - # expected "Union[str, SupportsInt, _SupportsIndex, _SupportsTrunc]" - value = int(value) # type: ignore[arg-type] + value = int(value) elif is_bool(value): value = bool(value) elif isinstance(value, (np.datetime64, np.timedelta64)): diff --git a/pandas/core/dtypes/inference.py b/pandas/core/dtypes/inference.py index 28e034de869f4..2f0bc373e8098 100644 --- a/pandas/core/dtypes/inference.py +++ b/pandas/core/dtypes/inference.py @@ -5,7 +5,11 @@ from collections import abc from numbers import Number import re -from typing import Pattern +from typing import ( + TYPE_CHECKING, + Hashable, + Pattern, +) import numpy as np @@ -30,7 +34,12 @@ is_iterator = lib.is_iterator -def is_number(obj) -> bool: +if TYPE_CHECKING: + # TypeGuard only available in py310+ + from typing_extensions import TypeGuard + + +def is_number(obj) -> TypeGuard[Number | np.number]: """ Check if the object is a number. @@ -132,7 +141,7 @@ def is_file_like(obj) -> bool: return bool(hasattr(obj, "__iter__")) -def is_re(obj) -> bool: +def is_re(obj) -> TypeGuard[Pattern]: """ Check if the object is a regex pattern instance. @@ -325,7 +334,7 @@ def is_named_tuple(obj) -> bool: return isinstance(obj, abc.Sequence) and hasattr(obj, "_fields") -def is_hashable(obj) -> bool: +def is_hashable(obj) -> TypeGuard[Hashable]: """ Return True if hash(obj) will succeed, False otherwise. diff --git a/pandas/core/frame.py b/pandas/core/frame.py index ce4c3d81c4f90..43bfbaff744da 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -9501,11 +9501,7 @@ def melt( ) def diff(self, periods: int = 1, axis: Axis = 0) -> DataFrame: if not lib.is_integer(periods): - if not ( - is_float(periods) - # error: "int" has no attribute "is_integer" - and periods.is_integer() # type: ignore[attr-defined] - ): + if not (is_float(periods) and periods.is_integer()): raise ValueError("periods must be an integer") periods = int(periods) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 17e4a4c142f66..1f5e4f3bf7734 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -4089,6 +4089,7 @@ class animal locomotion loc, new_index = index._get_loc_level(key, level=0) if not drop_level: if lib.is_integer(loc): + loc = int(loc) new_index = index[loc : loc + 1] else: new_index = index[loc] diff --git a/pandas/core/indexes/api.py b/pandas/core/indexes/api.py index f880e1f10106d..ce5c68a9c8ebc 100644 --- a/pandas/core/indexes/api.py +++ b/pandas/core/indexes/api.py @@ -70,7 +70,11 @@ def get_objs_combined_axis( - objs, intersect: bool = False, axis: Axis = 0, sort: bool = True, copy: bool = False + objs, + intersect: bool = False, + axis: Axis = 0, + sort: bool | np.bool_ = True, + copy: bool = False, ) -> Index: """ Extract combined index: return intersection or union (depending on the @@ -116,7 +120,7 @@ def _get_distinct_objs(objs: list[Index]) -> list[Index]: def _get_combined_index( indexes: list[Index], intersect: bool = False, - sort: bool = False, + sort: bool | np.bool_ = False, copy: bool = False, ) -> Index: """ diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 37df3a7024626..62b84276ebc79 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2930,6 +2930,7 @@ def get_loc_level(self, key, level: IndexLabel = 0, drop_level: bool = True): loc, mi = self._get_loc_level(key, level=level) if not drop_level: if lib.is_integer(loc): + loc = int(loc) mi = self[loc : loc + 1] else: mi = self[loc] diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index faa1e9658fa80..2e800d140901d 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -301,7 +301,7 @@ def _maybe_convert_timedelta(self, other) -> int | npt.NDArray[np.int64]: # integer is passed to .shift via # _add_datetimelike_methods basically # but ufunc may pass integer to _add_delta - return other + return int(other) # raise when input doesn't have freq raise raise_on_incompatible(self, None) diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index 8db08fc15c0f4..1dac439ad9aea 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1562,7 +1562,7 @@ def _is_scalar_access(self, key: tuple) -> bool: return all(is_integer(k) for k in key) - def _validate_integer(self, key: int, axis: AxisInt) -> None: + def _validate_integer(self, key: int | np.integer, axis: AxisInt) -> None: """ Check that 'key' is a valid position in the desired axis. @@ -2171,7 +2171,7 @@ def _ensure_iterable_column_indexer(self, column_indexer): """ Ensure that our column indexer is something that can be iterated over. """ - ilocs: Sequence[int] | np.ndarray + ilocs: Sequence[int | np.integer] | np.ndarray if is_integer(column_indexer): ilocs = [column_indexer] elif isinstance(column_indexer, slice): diff --git a/pandas/core/window/rolling.py b/pandas/core/window/rolling.py index b11ff11421ed4..ed0de80e381c3 100644 --- a/pandas/core/window/rolling.py +++ b/pandas/core/window/rolling.py @@ -1402,7 +1402,7 @@ def _generate_cython_apply_func( self, args: tuple[Any, ...], kwargs: dict[str, Any], - raw: bool, + raw: bool | np.bool_, function: Callable[..., Any], ) -> Callable[[np.ndarray, np.ndarray, np.ndarray, int], np.ndarray]: from pandas import Series diff --git a/pandas/io/parsers/python_parser.py b/pandas/io/parsers/python_parser.py index 315d18d052d9f..fc1278434a251 100644 --- a/pandas/io/parsers/python_parser.py +++ b/pandas/io/parsers/python_parser.py @@ -1348,4 +1348,4 @@ def _validate_skipfooter_arg(skipfooter: int) -> int: if skipfooter < 0: raise ValueError("skipfooter cannot be negative") - return skipfooter + return int(skipfooter) diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 8d48d04c738e8..033e07dd47a5c 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -1023,6 +1023,7 @@ def insert( num_inserted = exec_insert(conn, keys, chunk_iter) # GH 46891 if is_integer(num_inserted): + num_inserted = int(num_inserted) if total_inserted is None: total_inserted = num_inserted else: From e12b7a7baa20db4e0480b7b2fa0174ce94a1c345 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 10 Feb 2023 10:32:31 -0800 Subject: [PATCH 02/15] TYP: try TypeGuard --- pandas/core/indexes/multi.py | 5 ++++- pandas/core/reshape/merge.py | 3 ++- pandas/tests/extension/decimal/array.py | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 62b84276ebc79..b7644eed27b13 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2710,7 +2710,10 @@ def _partial_tup_index(self, tup: tuple, side: Literal["left", "right"] = "left" # non-comparable level, e.g. test_groupby_example raise TypeError(f"Level type mismatch: {lab}") if side == "right" and loc >= 0: - loc -= 1 + # error: Incompatible types in assignment (expression has type + # "Union[int, Any]", variable has type "Union[ndarray[Any, + # dtype[signedinteger[Any]]], signedinteger[Any]]") + loc -= 1 # type: ignore[assignment] return start + algos.searchsorted(section, loc, side=side) idx = self._get_loc_single_level_index(lev, lab) diff --git a/pandas/core/reshape/merge.py b/pandas/core/reshape/merge.py index 21ce1d3c96379..d2b022214167f 100644 --- a/pandas/core/reshape/merge.py +++ b/pandas/core/reshape/merge.py @@ -2026,7 +2026,8 @@ def _get_merge_keys( elif is_float_dtype(lt): if not is_number(self.tolerance): raise MergeError(msg) - if self.tolerance < 0: + # error: Unsupported operand types for > ("int" and "Number") + if self.tolerance < 0: # type: ignore[operator] raise MergeError("tolerance must be positive") else: diff --git a/pandas/tests/extension/decimal/array.py b/pandas/tests/extension/decimal/array.py index 3e495e9ac6814..edea595905205 100644 --- a/pandas/tests/extension/decimal/array.py +++ b/pandas/tests/extension/decimal/array.py @@ -74,7 +74,10 @@ def __init__(self, values, dtype=None, copy=False, context=None) -> None: if np.isnan(val): values[i] = DecimalDtype.na_value else: - values[i] = DecimalDtype.type(val) + # error: Argument 1 has incompatible type "Union[float, + # floating[Any]]"; expected "Union[Decimal, float, str, + # Tuple[int, Sequence[int], int]]" + values[i] = DecimalDtype.type(val) # type: ignore[arg-type] elif not isinstance(val, decimal.Decimal): raise TypeError("All values must be of type " + str(decimal.Decimal)) values = np.asarray(values, dtype=object) From 1b3ef00d9ffa2f5e0b0493a37e679351e283d5e1 Mon Sep 17 00:00:00 2001 From: Brock Date: Sat, 11 Feb 2023 08:32:14 -0800 Subject: [PATCH 03/15] suggested edits --- pandas/_libs/lib.pyi | 6 +++--- pandas/_typing.py | 6 ++++++ pandas/core/dtypes/inference.py | 7 +------ pandas/tests/extension/decimal/array.py | 5 +---- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/pandas/_libs/lib.pyi b/pandas/_libs/lib.pyi index 6f0f7479269e3..31d4274bb5f8d 100644 --- a/pandas/_libs/lib.pyi +++ b/pandas/_libs/lib.pyi @@ -12,13 +12,13 @@ from typing import ( ) import numpy as np -from typing_extensions import TypeGuard from pandas._libs.interval import Interval from pandas._libs.tslibs import Period from pandas._typing import ( ArrayLike, DtypeObj, + TypeGuard, npt, ) @@ -44,10 +44,10 @@ def is_list_like(obj: object, allow_sets: bool = ...) -> bool: ... def is_period(val: object) -> TypeGuard[Period]: ... def is_interval(val: object) -> TypeGuard[Interval]: ... def is_decimal(val: object) -> TypeGuard[Decimal]: ... -def is_complex(val: object) -> TypeGuard[complex | np.complex_]: ... +def is_complex(val: object) -> TypeGuard[complex]: ... def is_bool(val: object) -> TypeGuard[bool | np.bool_]: ... def is_integer(val: object) -> TypeGuard[int | np.integer]: ... -def is_float(val: object) -> TypeGuard[float | np.floating]: ... +def is_float(val: object) -> TypeGuard[float]: ... def is_interval_array(values: np.ndarray) -> bool: ... def is_datetime64_array(values: np.ndarray) -> bool: ... def is_timedelta_or_timedelta64_array(values: np.ndarray) -> bool: ... diff --git a/pandas/_typing.py b/pandas/_typing.py index 9d64842373573..e299d5309a6b9 100644 --- a/pandas/_typing.py +++ b/pandas/_typing.py @@ -84,6 +84,11 @@ # Name "npt._ArrayLikeInt_co" is not defined [name-defined] NumpySorter = Optional[npt._ArrayLikeInt_co] # type: ignore[name-defined] + if sys.version_info >= (3, 10): + from typing import TypeGuard + else: + from typing_extensions import TypeGuard # pyright: reportUnusedImport = false + if sys.version_info >= (3, 11): from typing import Self else: @@ -91,6 +96,7 @@ else: npt: Any = None Self: Any = None + TypeGuard: Any = None HashableT = TypeVar("HashableT", bound=Hashable) diff --git a/pandas/core/dtypes/inference.py b/pandas/core/dtypes/inference.py index 2f0bc373e8098..828026a81206b 100644 --- a/pandas/core/dtypes/inference.py +++ b/pandas/core/dtypes/inference.py @@ -6,7 +6,6 @@ from numbers import Number import re from typing import ( - TYPE_CHECKING, Hashable, Pattern, ) @@ -14,6 +13,7 @@ import numpy as np from pandas._libs import lib +from pandas._typing import TypeGuard is_bool = lib.is_bool @@ -34,11 +34,6 @@ is_iterator = lib.is_iterator -if TYPE_CHECKING: - # TypeGuard only available in py310+ - from typing_extensions import TypeGuard - - def is_number(obj) -> TypeGuard[Number | np.number]: """ Check if the object is a number. diff --git a/pandas/tests/extension/decimal/array.py b/pandas/tests/extension/decimal/array.py index edea595905205..3e495e9ac6814 100644 --- a/pandas/tests/extension/decimal/array.py +++ b/pandas/tests/extension/decimal/array.py @@ -74,10 +74,7 @@ def __init__(self, values, dtype=None, copy=False, context=None) -> None: if np.isnan(val): values[i] = DecimalDtype.na_value else: - # error: Argument 1 has incompatible type "Union[float, - # floating[Any]]"; expected "Union[Decimal, float, str, - # Tuple[int, Sequence[int], int]]" - values[i] = DecimalDtype.type(val) # type: ignore[arg-type] + values[i] = DecimalDtype.type(val) elif not isinstance(val, decimal.Decimal): raise TypeError("All values must be of type " + str(decimal.Decimal)) values = np.asarray(values, dtype=object) From a1d1517ca8453ea03531e87383117f297d237860 Mon Sep 17 00:00:00 2001 From: Brock Date: Sat, 11 Feb 2023 17:14:00 -0800 Subject: [PATCH 04/15] pyright fixup --- pandas/compat/numpy/function.py | 2 +- pandas/util/_validators.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/compat/numpy/function.py b/pandas/compat/numpy/function.py index bdd26b315ed83..88c2b3b4e29a6 100644 --- a/pandas/compat/numpy/function.py +++ b/pandas/compat/numpy/function.py @@ -226,7 +226,7 @@ def validate_cum_func_with_skipna(skipna, args, kwargs, name) -> bool: skipna = True validate_cum_func(args, kwargs, fname=name) - return skipna + return bool(skipna) ALLANY_DEFAULTS: dict[str, bool | None] = {} diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index 17ef583febc24..295c02981eb4a 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -249,6 +249,9 @@ def validate_bool_kwarg( If the value is not a valid boolean. """ good_value = is_bool(value) + if good_value: + value = bool(value) + if none_allowed: good_value = good_value or value is None @@ -433,6 +436,7 @@ def validate_insert_loc(loc: int, length: int) -> int: """ if not is_integer(loc): raise TypeError(f"loc must be an integer between -{length} and {length}") + loc = int(loc) if loc < 0: loc += length From 024ed70cad4658db94940da5f25ff5fa69b0c363 Mon Sep 17 00:00:00 2001 From: Brock Date: Sun, 12 Feb 2023 12:08:28 -0800 Subject: [PATCH 05/15] mypy fixup --- pandas/util/_validators.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index 295c02981eb4a..691a4b870197c 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -249,8 +249,6 @@ def validate_bool_kwarg( If the value is not a valid boolean. """ good_value = is_bool(value) - if good_value: - value = bool(value) if none_allowed: good_value = good_value or value is None From 0e4d37a837669a9145f9285fac265d80b5de1450 Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 13 Feb 2023 07:27:38 -0800 Subject: [PATCH 06/15] mypy/pyright fixup --- pandas/util/_validators.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index 691a4b870197c..6f441eb4f42e7 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -249,9 +249,13 @@ def validate_bool_kwarg( If the value is not a valid boolean. """ good_value = is_bool(value) + if good_value: + # error: Incompatible types in assignment (expression has type "bool", + # variable has type "None") + value = bool(value) # type: ignore[assignment] if none_allowed: - good_value = good_value or value is None + good_value = good_value or (value is None) if int_allowed: good_value = good_value or isinstance(value, int) From 6be72281be3c0d49b3bfeb0b667eb6e3997a20ab Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 13 Feb 2023 14:25:53 -0800 Subject: [PATCH 07/15] ignore instead of cast --- pandas/compat/numpy/function.py | 2 +- pandas/core/generic.py | 4 ++-- pandas/core/indexes/multi.py | 4 ++-- pandas/core/indexes/period.py | 4 +++- pandas/io/parsers/python_parser.py | 4 +++- pandas/util/_validators.py | 6 ------ 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/pandas/compat/numpy/function.py b/pandas/compat/numpy/function.py index 88c2b3b4e29a6..bdd26b315ed83 100644 --- a/pandas/compat/numpy/function.py +++ b/pandas/compat/numpy/function.py @@ -226,7 +226,7 @@ def validate_cum_func_with_skipna(skipna, args, kwargs, name) -> bool: skipna = True validate_cum_func(args, kwargs, fname=name) - return bool(skipna) + return skipna ALLANY_DEFAULTS: dict[str, bool | None] = {} diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 1f5e4f3bf7734..0811c5d450b05 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -4089,8 +4089,8 @@ class animal locomotion loc, new_index = index._get_loc_level(key, level=0) if not drop_level: if lib.is_integer(loc): - loc = int(loc) - new_index = index[loc : loc + 1] + # error: Slice index must be an integer or None + new_index = index[loc : loc + 1] # type: ignore[misc] else: new_index = index[loc] else: diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index b7644eed27b13..527ef07bd0a0f 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2933,8 +2933,8 @@ def get_loc_level(self, key, level: IndexLabel = 0, drop_level: bool = True): loc, mi = self._get_loc_level(key, level=level) if not drop_level: if lib.is_integer(loc): - loc = int(loc) - mi = self[loc : loc + 1] + # error: Slice index must be an integer or None + mi = self[loc : loc + 1] # type: ignore[misc] else: mi = self[loc] return loc, mi diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index 2e800d140901d..e42dc590a026f 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -301,7 +301,9 @@ def _maybe_convert_timedelta(self, other) -> int | npt.NDArray[np.int64]: # integer is passed to .shift via # _add_datetimelike_methods basically # but ufunc may pass integer to _add_delta - return int(other) + # error: Incompatible return value type (got "Union[int, integer[Any]]", + # expected "Union[int, ndarray[Any, dtype[signedinteger[_64Bit]]]]") + return other # type: ignore[return-value] # raise when input doesn't have freq raise raise_on_incompatible(self, None) diff --git a/pandas/io/parsers/python_parser.py b/pandas/io/parsers/python_parser.py index fc1278434a251..5b691c41100ec 100644 --- a/pandas/io/parsers/python_parser.py +++ b/pandas/io/parsers/python_parser.py @@ -1348,4 +1348,6 @@ def _validate_skipfooter_arg(skipfooter: int) -> int: if skipfooter < 0: raise ValueError("skipfooter cannot be negative") - return int(skipfooter) + # error: Incompatible return value type (got "Union[int, integer[Any]]", + # expected "int") + return skipfooter # type: ignore[return-value] diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index 6f441eb4f42e7..dd07ea71994e7 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -249,11 +249,6 @@ def validate_bool_kwarg( If the value is not a valid boolean. """ good_value = is_bool(value) - if good_value: - # error: Incompatible types in assignment (expression has type "bool", - # variable has type "None") - value = bool(value) # type: ignore[assignment] - if none_allowed: good_value = good_value or (value is None) @@ -438,7 +433,6 @@ def validate_insert_loc(loc: int, length: int) -> int: """ if not is_integer(loc): raise TypeError(f"loc must be an integer between -{length} and {length}") - loc = int(loc) if loc < 0: loc += length From b4ee9758cf590e0b4922c1b5d6ff2d4fd1d6c3f5 Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 13 Feb 2023 17:52:06 -0800 Subject: [PATCH 08/15] pyright fixup --- pandas/compat/numpy/function.py | 2 +- pandas/util/_validators.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/compat/numpy/function.py b/pandas/compat/numpy/function.py index bdd26b315ed83..bc4494526f6e9 100644 --- a/pandas/compat/numpy/function.py +++ b/pandas/compat/numpy/function.py @@ -226,7 +226,7 @@ def validate_cum_func_with_skipna(skipna, args, kwargs, name) -> bool: skipna = True validate_cum_func(args, kwargs, fname=name) - return skipna + return skipna # pyright: ignore[reportGeneralTypeIssues] ALLANY_DEFAULTS: dict[str, bool | None] = {} diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index dd07ea71994e7..f03d1ceb507fd 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -260,7 +260,7 @@ def validate_bool_kwarg( f'For argument "{arg_name}" expected type bool, received ' f"type {type(value).__name__}." ) - return value + return value # pyright: ignore[reportGeneralTypeIssues] def validate_fillna_kwargs(value, method, validate_scalar_dict_value: bool = True): @@ -438,7 +438,7 @@ def validate_insert_loc(loc: int, length: int) -> int: loc += length if not 0 <= loc <= length: raise IndexError(f"loc must be an integer between -{length} and {length}") - return loc + return loc # pyright: ignore[reportGeneralTypeIssues] def check_dtype_backend(dtype_backend) -> None: From e683d19948dfbd94102a05d8b1a4e99720fa1036 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Fri, 17 Feb 2023 09:17:56 +0000 Subject: [PATCH 09/15] make use of typing_extensions odepend of python version --- pandas/core/dtypes/inference.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pandas/core/dtypes/inference.py b/pandas/core/dtypes/inference.py index 828026a81206b..af4f0a1c0aa05 100644 --- a/pandas/core/dtypes/inference.py +++ b/pandas/core/dtypes/inference.py @@ -6,6 +6,7 @@ from numbers import Number import re from typing import ( + TYPE_CHECKING, Hashable, Pattern, ) @@ -13,7 +14,9 @@ import numpy as np from pandas._libs import lib -from pandas._typing import TypeGuard + +if TYPE_CHECKING: + from pandas._typing import TypeGuard is_bool = lib.is_bool From 64e398e74858be18380294b8a3fd0231fa403046 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sat, 18 Feb 2023 13:29:58 +0000 Subject: [PATCH 10/15] fixes to typing --- pandas/compat/numpy/function.py | 2 +- pandas/core/generic.py | 4 ++-- pandas/core/indexes/api.py | 4 ++-- pandas/core/indexes/multi.py | 10 ++++------ pandas/core/indexes/period.py | 8 ++------ pandas/core/reshape/concat.py | 2 +- pandas/io/parsers/python_parser.py | 7 ++----- pandas/io/sql.py | 4 +--- pandas/util/_validators.py | 2 +- 9 files changed, 16 insertions(+), 27 deletions(-) diff --git a/pandas/compat/numpy/function.py b/pandas/compat/numpy/function.py index bc4494526f6e9..bdd26b315ed83 100644 --- a/pandas/compat/numpy/function.py +++ b/pandas/compat/numpy/function.py @@ -226,7 +226,7 @@ def validate_cum_func_with_skipna(skipna, args, kwargs, name) -> bool: skipna = True validate_cum_func(args, kwargs, fname=name) - return skipna # pyright: ignore[reportGeneralTypeIssues] + return skipna ALLANY_DEFAULTS: dict[str, bool | None] = {} diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 0811c5d450b05..e219ccc7d9356 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -4089,8 +4089,8 @@ class animal locomotion loc, new_index = index._get_loc_level(key, level=0) if not drop_level: if lib.is_integer(loc): - # error: Slice index must be an integer or None - new_index = index[loc : loc + 1] # type: ignore[misc] + loc = cast(int, loc) + new_index = index[loc : loc + 1] else: new_index = index[loc] else: diff --git a/pandas/core/indexes/api.py b/pandas/core/indexes/api.py index ce5c68a9c8ebc..4070b25767912 100644 --- a/pandas/core/indexes/api.py +++ b/pandas/core/indexes/api.py @@ -73,7 +73,7 @@ def get_objs_combined_axis( objs, intersect: bool = False, axis: Axis = 0, - sort: bool | np.bool_ = True, + sort: bool = True, copy: bool = False, ) -> Index: """ @@ -120,7 +120,7 @@ def _get_distinct_objs(objs: list[Index]) -> list[Index]: def _get_combined_index( indexes: list[Index], intersect: bool = False, - sort: bool | np.bool_ = False, + sort: bool = False, copy: bool = False, ) -> Index: """ diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 527ef07bd0a0f..44278277b7f78 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2699,6 +2699,7 @@ def _partial_tup_index(self, tup: tuple, side: Literal["left", "right"] = "left" for k, (lab, lev, level_codes) in enumerate(zipped): section = level_codes[start:end] + loc: npt.NDArray[np.intp] | np.intp | int if lab not in lev and not isna(lab): # short circuit try: @@ -2710,10 +2711,7 @@ def _partial_tup_index(self, tup: tuple, side: Literal["left", "right"] = "left" # non-comparable level, e.g. test_groupby_example raise TypeError(f"Level type mismatch: {lab}") if side == "right" and loc >= 0: - # error: Incompatible types in assignment (expression has type - # "Union[int, Any]", variable has type "Union[ndarray[Any, - # dtype[signedinteger[Any]]], signedinteger[Any]]") - loc -= 1 # type: ignore[assignment] + loc -= 1 return start + algos.searchsorted(section, loc, side=side) idx = self._get_loc_single_level_index(lev, lab) @@ -2933,8 +2931,8 @@ def get_loc_level(self, key, level: IndexLabel = 0, drop_level: bool = True): loc, mi = self._get_loc_level(key, level=level) if not drop_level: if lib.is_integer(loc): - # error: Slice index must be an integer or None - mi = self[loc : loc + 1] # type: ignore[misc] + loc = cast(int, loc) + mi = self[loc : loc + 1] else: mi = self[loc] return loc, mi diff --git a/pandas/core/indexes/period.py b/pandas/core/indexes/period.py index e42dc590a026f..d92a3fe13e42f 100644 --- a/pandas/core/indexes/period.py +++ b/pandas/core/indexes/period.py @@ -298,12 +298,8 @@ def _maybe_convert_timedelta(self, other) -> int | npt.NDArray[np.int64]: raise raise_on_incompatible(self, other) elif is_integer(other): - # integer is passed to .shift via - # _add_datetimelike_methods basically - # but ufunc may pass integer to _add_delta - # error: Incompatible return value type (got "Union[int, integer[Any]]", - # expected "Union[int, ndarray[Any, dtype[signedinteger[_64Bit]]]]") - return other # type: ignore[return-value] + assert isinstance(other, int) + return other # raise when input doesn't have freq raise raise_on_incompatible(self, None) diff --git a/pandas/core/reshape/concat.py b/pandas/core/reshape/concat.py index 650d51b896dc5..f0447560346de 100644 --- a/pandas/core/reshape/concat.py +++ b/pandas/core/reshape/concat.py @@ -555,7 +555,7 @@ def __init__( raise ValueError( f"The 'sort' keyword only accepts boolean values; {sort} was passed." ) - self.sort = sort + self.sort = cast(bool, sort) self.ignore_index = ignore_index self.verify_integrity = verify_integrity diff --git a/pandas/io/parsers/python_parser.py b/pandas/io/parsers/python_parser.py index 5b691c41100ec..6a9ddf67e7d68 100644 --- a/pandas/io/parsers/python_parser.py +++ b/pandas/io/parsers/python_parser.py @@ -29,7 +29,6 @@ ParserError, ) -from pandas.core.dtypes.common import is_integer from pandas.core.dtypes.inference import is_dict_like from pandas.io.common import ( @@ -1342,12 +1341,10 @@ def _validate_skipfooter_arg(skipfooter: int) -> int: ------ ValueError : 'skipfooter' was not a non-negative integer. """ - if not is_integer(skipfooter): + if not isinstance(skipfooter, int): raise ValueError("skipfooter must be an integer") if skipfooter < 0: raise ValueError("skipfooter cannot be negative") - # error: Incompatible return value type (got "Union[int, integer[Any]]", - # expected "int") - return skipfooter # type: ignore[return-value] + return skipfooter diff --git a/pandas/io/sql.py b/pandas/io/sql.py index 033e07dd47a5c..ec04a9ce81d92 100644 --- a/pandas/io/sql.py +++ b/pandas/io/sql.py @@ -44,7 +44,6 @@ from pandas.core.dtypes.common import ( is_datetime64tz_dtype, is_dict_like, - is_integer, is_list_like, ) from pandas.core.dtypes.dtypes import DatetimeTZDtype @@ -1022,8 +1021,7 @@ def insert( chunk_iter = zip(*(arr[start_i:end_i] for arr in data_list)) num_inserted = exec_insert(conn, keys, chunk_iter) # GH 46891 - if is_integer(num_inserted): - num_inserted = int(num_inserted) + if num_inserted is not None: if total_inserted is None: total_inserted = num_inserted else: diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index f03d1ceb507fd..75235d473df3d 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -260,7 +260,7 @@ def validate_bool_kwarg( f'For argument "{arg_name}" expected type bool, received ' f"type {type(value).__name__}." ) - return value # pyright: ignore[reportGeneralTypeIssues] + return value def validate_fillna_kwargs(value, method, validate_scalar_dict_value: bool = True): From 2940b014b4edbe1dbcf6578d72a7f47801275899 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sat, 18 Feb 2023 16:06:21 +0000 Subject: [PATCH 11/15] fix integer --- pandas/io/parsers/python_parser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pandas/io/parsers/python_parser.py b/pandas/io/parsers/python_parser.py index 6a9ddf67e7d68..e8476af8cc3c2 100644 --- a/pandas/io/parsers/python_parser.py +++ b/pandas/io/parsers/python_parser.py @@ -29,6 +29,7 @@ ParserError, ) +from pandas.core.dtypes.common import is_integer from pandas.core.dtypes.inference import is_dict_like from pandas.io.common import ( @@ -1341,9 +1342,10 @@ def _validate_skipfooter_arg(skipfooter: int) -> int: ------ ValueError : 'skipfooter' was not a non-negative integer. """ - if not isinstance(skipfooter, int): + if not is_integer(skipfooter): raise ValueError("skipfooter must be an integer") + skipfooter = cast(int, skipfooter) if skipfooter < 0: raise ValueError("skipfooter cannot be negative") From 35746accf83c4e441dae71b0e77b6c7cb2046745 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sat, 18 Feb 2023 18:46:34 +0000 Subject: [PATCH 12/15] fix pyright --- pandas/compat/numpy/function.py | 5 ++++- pandas/util/_validators.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pandas/compat/numpy/function.py b/pandas/compat/numpy/function.py index bdd26b315ed83..8b2916bf1ded9 100644 --- a/pandas/compat/numpy/function.py +++ b/pandas/compat/numpy/function.py @@ -25,6 +25,7 @@ overload, ) +import numpy as np from numpy import ndarray from pandas._libs.lib import ( @@ -215,7 +216,7 @@ def validate_clip_with_axis( ) -def validate_cum_func_with_skipna(skipna, args, kwargs, name) -> bool: +def validate_cum_func_with_skipna(skipna: bool, args, kwargs, name) -> bool: """ If this function is called via the 'numpy' library, the third parameter in its signature is 'dtype', which takes either a 'numpy' dtype or 'None', so @@ -224,6 +225,8 @@ def validate_cum_func_with_skipna(skipna, args, kwargs, name) -> bool: if not is_bool(skipna): args = (skipna,) + args skipna = True + elif isinstance(skipna, np.bool_): + skipna = bool(skipna) validate_cum_func(args, kwargs, fname=name) return skipna diff --git a/pandas/util/_validators.py b/pandas/util/_validators.py index 75235d473df3d..f03d1ceb507fd 100644 --- a/pandas/util/_validators.py +++ b/pandas/util/_validators.py @@ -260,7 +260,7 @@ def validate_bool_kwarg( f'For argument "{arg_name}" expected type bool, received ' f"type {type(value).__name__}." ) - return value + return value # pyright: ignore[reportGeneralTypeIssues] def validate_fillna_kwargs(value, method, validate_scalar_dict_value: bool = True): From f8248e5e1ca3480e3fdf0f8f17e3f18c213d475f Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sat, 18 Feb 2023 23:51:16 +0000 Subject: [PATCH 13/15] fix sql tests --- pandas/tests/io/test_sql.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py index dc51a5b0a77fb..3d79d483038ee 100644 --- a/pandas/tests/io/test_sql.py +++ b/pandas/tests/io/test_sql.py @@ -775,7 +775,7 @@ def psql_insert_copy(table, conn, keys, data_iter): "test_frame", conn, index=False, method=psql_insert_copy ) # GH 46891 - if not isinstance(expected_count, int): + if expected_count is None: assert result_count is None else: assert result_count == expected_count From 1d5f3e49383ecaa0a5cedd6c24035503aacd6af9 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Sun, 26 Feb 2023 23:36:35 +0000 Subject: [PATCH 14/15] remove typing.cast --- pandas/core/generic.py | 4 ++-- pandas/core/indexes/multi.py | 4 ++-- pandas/core/reshape/concat.py | 6 +++++- pandas/io/parsers/python_parser.py | 4 ++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index e219ccc7d9356..fa19aae674621 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -4089,8 +4089,8 @@ class animal locomotion loc, new_index = index._get_loc_level(key, level=0) if not drop_level: if lib.is_integer(loc): - loc = cast(int, loc) - new_index = index[loc : loc + 1] + # Slice index must be an integer or None + new_index = index[loc : loc + 1] # type: ignore[misc] else: new_index = index[loc] else: diff --git a/pandas/core/indexes/multi.py b/pandas/core/indexes/multi.py index 44278277b7f78..c2dcd7389db5c 100644 --- a/pandas/core/indexes/multi.py +++ b/pandas/core/indexes/multi.py @@ -2931,8 +2931,8 @@ def get_loc_level(self, key, level: IndexLabel = 0, drop_level: bool = True): loc, mi = self._get_loc_level(key, level=level) if not drop_level: if lib.is_integer(loc): - loc = cast(int, loc) - mi = self[loc : loc + 1] + # Slice index must be an integer or None + mi = self[loc : loc + 1] # type: ignore[misc] else: mi = self[loc] return loc, mi diff --git a/pandas/core/reshape/concat.py b/pandas/core/reshape/concat.py index f0447560346de..395db8060ce0e 100644 --- a/pandas/core/reshape/concat.py +++ b/pandas/core/reshape/concat.py @@ -391,6 +391,8 @@ class _Concatenator: Orchestrates a concatenation operation for BlockManagers """ + sort: bool + def __init__( self, objs: Iterable[NDFrame] | Mapping[HashableT, NDFrame], @@ -555,7 +557,9 @@ def __init__( raise ValueError( f"The 'sort' keyword only accepts boolean values; {sort} was passed." ) - self.sort = cast(bool, sort) + # Incompatible types in assignment (expression has type "Union[bool, bool_]", + # variable has type "bool") + self.sort = sort # type: ignore[assignment] self.ignore_index = ignore_index self.verify_integrity = verify_integrity diff --git a/pandas/io/parsers/python_parser.py b/pandas/io/parsers/python_parser.py index e8476af8cc3c2..d8c9ece3b2cce 100644 --- a/pandas/io/parsers/python_parser.py +++ b/pandas/io/parsers/python_parser.py @@ -1345,8 +1345,8 @@ def _validate_skipfooter_arg(skipfooter: int) -> int: if not is_integer(skipfooter): raise ValueError("skipfooter must be an integer") - skipfooter = cast(int, skipfooter) if skipfooter < 0: raise ValueError("skipfooter cannot be negative") - return skipfooter + # Incompatible return value type (got "Union[int, integer[Any]]", expected "int") + return skipfooter # type: ignore[return-value] From 3e0c4a0dd6a568c6db666bc72b65f0d2d9c8b848 Mon Sep 17 00:00:00 2001 From: Terji Petersen Date: Thu, 16 Mar 2023 06:17:52 +0000 Subject: [PATCH 15/15] fix mypy --- pandas/core/frame.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 43bfbaff744da..93edb93781ba3 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -10393,8 +10393,13 @@ def _series_round(ser: Series, decimals: int) -> Series: new_cols = list(_dict_round(self, decimals)) elif is_integer(decimals): # Dispatch to Block.round + # Argument "decimals" to "round" of "BaseBlockManager" has incompatible + # type "Union[int, integer[Any]]"; expected "int" return self._constructor( - self._mgr.round(decimals=decimals, using_cow=using_copy_on_write()), + self._mgr.round( + decimals=decimals, # type: ignore[arg-type] + using_cow=using_copy_on_write(), + ), ).__finalize__(self, method="round") else: raise TypeError("decimals must be an integer, a dict-like or a Series")