From 181dc24790dd0b5aa3855ea97db1c55f0a553477 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 25 Sep 2021 10:38:57 -0700 Subject: [PATCH 01/16] Improved the type stubs in the _libs directory to help with type checking. --- pandas/_libs/interval.pyi | 47 +++++++++++++ pandas/_libs/missing.pyi | 12 ++++ pandas/_libs/tslibs/ccalendar.pyi | 2 + pandas/_libs/tslibs/dtypes.pyi | 46 ++++++------- pandas/_libs/tslibs/nattype.pyi | 3 + pandas/_libs/tslibs/np_datetime.pyi | 1 + pandas/_libs/tslibs/offsets.pyi | 102 ++++++++++++++++++++++++++++ pandas/_libs/tslibs/period.pyi | 4 ++ pandas/_libs/tslibs/timestamps.pyi | 1 - 9 files changed, 194 insertions(+), 24 deletions(-) create mode 100644 pandas/_libs/interval.pyi create mode 100644 pandas/_libs/missing.pyi create mode 100644 pandas/_libs/tslibs/np_datetime.pyi create mode 100644 pandas/_libs/tslibs/offsets.pyi diff --git a/pandas/_libs/interval.pyi b/pandas/_libs/interval.pyi new file mode 100644 index 0000000000000..fef7c2531b680 --- /dev/null +++ b/pandas/_libs/interval.pyi @@ -0,0 +1,47 @@ +from typing import FrozenSet, Tuple + +import numpy as np + +class IntervalMixin: + @property + def _left(self) -> object: ... + @property + def _right(self) -> object: ... + @property + def closed_left(self) -> bool: ... + @property + def closed_right(self) -> bool: ... + @property + def open_left(self) -> bool: ... + @property + def open_right(self) -> bool: ... + @property + def mid(self) -> float: ... + @property + def length(self) -> float: ... + @property + def is_empty(self) -> bool: ... + def _check_closed_matches(self, other: IntervalMixin, name: str=...) -> None: ... + +class Interval(IntervalMixin): + def __init__(self, left: object, right: object, closed: str=...) -> None: ... + @property + def closed(self) -> str: ... + @property + def left(self) -> object: ... + @property + def right(self) -> object: ... + def __str__(self) -> str: ... + def __add__(self, y: Interval) -> Interval: ... + def __sub__(self, y: Interval) -> Interval: ... + def __mul__(self, y: Interval) -> Interval: ... + def __trudeiv__(self, y: Interval) -> Interval: ... + def __floordiv__(self, y: Interval) -> Interval: ... + def __overlaps__(self, other: Interval) -> bool: ... + +VALID_CLOSED: FrozenSet[str] + +def intervals_to_interval_bounds( + intervals: np.ndarray, + valdiate_closed: bool = ... +) -> Tuple[object, object, str]: ... \ No newline at end of file diff --git a/pandas/_libs/missing.pyi b/pandas/_libs/missing.pyi new file mode 100644 index 0000000000000..afe823ac32f5a --- /dev/null +++ b/pandas/_libs/missing.pyi @@ -0,0 +1,12 @@ +class C_NAType: + ... + + +class NAType(C_NAType): + ... + +NA: NAType + +def is_matching_na(left: object, right: object, nan_matches_none: bool = ...) -> bool: + ... + diff --git a/pandas/_libs/tslibs/ccalendar.pyi b/pandas/_libs/tslibs/ccalendar.pyi index 993f18a61d74a..5d5b935ffa54b 100644 --- a/pandas/_libs/tslibs/ccalendar.pyi +++ b/pandas/_libs/tslibs/ccalendar.pyi @@ -8,5 +8,7 @@ def get_firstbday(year: int, month: int) -> int: ... def get_lastbday(year: int, month: int) -> int: ... def get_day_of_year(year: int, month: int, day: int) -> int: ... def get_iso_calendar(year: int, month: int, day: int) -> tuple[int, int, int]: ... +def is_leapyear(year: int) -> bool: ... def get_week_of_year(year: int, month: int, day: int) -> int: ... def get_days_in_month(year: int, month: int) -> int: ... +def dayofweek(y: int, m: int, d: int) -> int: ... diff --git a/pandas/_libs/tslibs/dtypes.pyi b/pandas/_libs/tslibs/dtypes.pyi index 8c510b05de4ce..8e47993e9d85f 100644 --- a/pandas/_libs/tslibs/dtypes.pyi +++ b/pandas/_libs/tslibs/dtypes.pyi @@ -18,33 +18,33 @@ class PeriodDtypeBase: def resolution(self) -> Resolution: ... class FreqGroup(Enum): - FR_ANN: int = ... - FR_QTR: int = ... - FR_MTH: int = ... - FR_WK: int = ... - FR_BUS: int = ... - FR_DAY: int = ... - FR_HR: int = ... - FR_MIN: int = ... - FR_SEC: int = ... - FR_MS: int = ... - FR_US: int = ... - FR_NS: int = ... - FR_UND: int = ... + FR_ANN: int + FR_QTR: int + FR_MTH: int + FR_WK: int + FR_BUS: int + FR_DAY: int + FR_HR: int + FR_MIN: int + FR_SEC: int + FR_MS: int + FR_US: int + FR_NS: int + FR_UND: int @staticmethod def get_freq_group(code: int) -> FreqGroup: ... class Resolution(Enum): - RESO_NS: int = ... - RESO_US: int = ... - RESO_MS: int = ... - RESO_SEC: int = ... - RESO_MIN: int = ... - RESO_HR: int = ... - RESO_DAY: int = ... - RESO_MTH: int = ... - RESO_QTR: int = ... - RESO_YR: int = ... + RESO_NS: int + RESO_US: int + RESO_MS: int + RESO_SEC: int + RESO_MIN: int + RESO_HR: int + RESO_DAY: int + RESO_MTH: int + RESO_QTR: int + RESO_YR: int def __lt__(self, other: Resolution) -> bool: ... def __ge__(self, other: Resolution) -> bool: ... @property diff --git a/pandas/_libs/tslibs/nattype.pyi b/pandas/_libs/tslibs/nattype.pyi index 6a5555cfff030..dc1d19219c3c0 100644 --- a/pandas/_libs/tslibs/nattype.pyi +++ b/pandas/_libs/tslibs/nattype.pyi @@ -12,6 +12,9 @@ NaT: NaTType iNaT: int nat_strings: set[str] +def is_null_datetimelike(val: object, inat_is_null: bool = ...) -> bool: ... +def checknull_with_nat(val: object) -> bool: ... + class NaTType(datetime): value: np.int64 def asm8(self) -> np.datetime64: ... diff --git a/pandas/_libs/tslibs/np_datetime.pyi b/pandas/_libs/tslibs/np_datetime.pyi new file mode 100644 index 0000000000000..db0c277b73bd5 --- /dev/null +++ b/pandas/_libs/tslibs/np_datetime.pyi @@ -0,0 +1 @@ +class OutOfBoundsDatetime(ValueError): ... diff --git a/pandas/_libs/tslibs/offsets.pyi b/pandas/_libs/tslibs/offsets.pyi new file mode 100644 index 0000000000000..ba11ac256936a --- /dev/null +++ b/pandas/_libs/tslibs/offsets.pyi @@ -0,0 +1,102 @@ +from __future__ import annotations +from datetime import datetime +from typing import Any, Tuple, Union +from datetime import timedelta + +class BaseOffset: + def __init__(self, n: int = ..., normalize: bool = ...) -> None: ... + def __eq__(self, other) -> bool: ... + def __ne__(self, other) -> bool: ... + def __hash__(self) -> int: ... + @property + def kwds(self) -> dict: ... + @property + def base(self) -> BaseOffset: ... + def __add__(self, other) -> BaseOffset: ... + def __sub__(self, other) -> BaseOffset: ... + def __call__(self, other): ... + def __mul__(self, other): ... + def __neg__(self) -> BaseOffset: ... + def copy(self) -> BaseOffset: ... + def __repr__(self) -> str: ... + @property + def name(self) -> str: ... + @property + def rule_code(self) -> str: ... + def freqstr(self) -> str: ... + # Next one is problematic due to circular imports + #def apply_index(self, dtindex: DatetimeIndex) -> DatetimeIndex: ... + def apply_index(self, dtindex): ... + def _apply_array(self, dtarr) -> None: ... + def rollback(self, dt: datetime) -> datetime: ... + def rollforward(self, dt: datetime) -> datetime: ... + def is_on_offset(self, dt: datetime) -> bool: ... + def __setstate__(self, state) -> None: ... + def __getstate__(self): ... + @property + def nanos(self) -> int: ... + def onOffset(self, dt: datetime) -> bool: ... + def isAnchored(self) -> bool: ... + def is_anchored(self) -> bool: ... + +class SingleConstructorOffset(BaseOffset): + @classmethod + def _from_name(cls, suffix=None): ... + def __reduce__(self): ... + +def to_offset(freq: Union[str, Tuple, timedelta, BaseOffset, None]) -> Union[BaseOffset, None]: ... + +class Tick(SingleConstructorOffset): + def __init__(self, n: int = ..., normalize: bool = ...) -> None: ... + +class Day(Tick): ... +class Hour(Tick): ... +class Minute(Tick): ... +class Second(Tick): ... +class Milli(Tick): ... +class Micro(Tick): ... +class Nano(Tick): ... +class RelativeDeltaOffset(BaseOffset): + def __init__(self, n: int = ..., normalize: bool = ..., **kwds: Any) -> None: ... +class BusinessMixin(SingleConstructorOffset): ... +class BusinessDay(BusinessMixin): ... +class BusinessHour(BusinessMixin): ... +class WeekOfMonthMixin(SingleConstructorOffset): ... +class YearOffset(SingleConstructorOffset): ... +class BYearEnd(YearOffset): ... +class BYearBegin(YearOffset): ... +class YearEnd(YearOffset): ... +class YearBegin(YearOffset): ... +class QuarterOffset(SingleConstructorOffset): ... +class BQuarterEnd(QuarterOffset): ... +class BQuarterBegin(QuarterOffset): ... +class QuarterEnd(QuarterOffset): ... +class QuarterBegin(QuarterOffset): ... +class MonthOffset(SingleConstructorOffset): ... +class MonthEnd(MonthOffset): ... +class MonthBegin(MonthOffset): ... +class BusinessMonthEnd(MonthOffset): ... +class BusinessMonthBegin(MonthOffset): ... +class SemiMonthOffset(SingleConstructorOffset): ... +class SemiMonthEnd(SemiMonthOffset): ... +class SemiMonthBegin(SemiMonthOffset): ... +class Week(SingleConstructorOffset): ... +class WeekOfMonth(WeekOfMonthMixin): ... +class LastWeekOfMonth(WeekOfMonthMixin): ... +class FY5253Mixin(SingleConstructorOffset): ... +class FY5253(FY5253Mixin): ... +class FY5253Quarter(FY5253Mixin): ... +class Easter(SingleConstructorOffset): ... +class _CustomBusinessMonth(BusinessMixin): ... +class CustomBusinessDay(BusinessDay): ... +class CustomBusinessHour(BusinessHour): ... +class CustomBusinessMonthEnd(_CustomBusinessMonth): ... +class CustomBusinessMonthBegin(_CustomBusinessMonth): ... +class DateOffset(RelativeDeltaOffset): ... + +BDay = BusinessDay +BMonthEnd = BusinessMonthEnd +BMonthBegin = BusinessMonthBegin +CBMonthEnd = CustomBusinessMonthEnd +CBMonthBegin = CustomBusinessMonthBegin +CDay = CustomBusinessDay diff --git a/pandas/_libs/tslibs/period.pyi b/pandas/_libs/tslibs/period.pyi index 4f7505fd7e792..c1c217aed230a 100644 --- a/pandas/_libs/tslibs/period.pyi +++ b/pandas/_libs/tslibs/period.pyi @@ -1,3 +1,4 @@ +from datetime import datetime from typing import Literal import numpy as np @@ -14,6 +15,9 @@ from pandas._typing import ( INVALID_FREQ_ERR_MSG: str DIFFERENT_FREQ: str +def is_period_object(obj: object) -> bool: ... +def get_period_ordinal(dts: datetime, freq: int) -> int: ... + class IncompatibleFrequency(ValueError): ... def periodarr_to_dt64arr( diff --git a/pandas/_libs/tslibs/timestamps.pyi b/pandas/_libs/tslibs/timestamps.pyi index a89d0aecfc26c..17ad2bdb1c936 100644 --- a/pandas/_libs/tslibs/timestamps.pyi +++ b/pandas/_libs/tslibs/timestamps.pyi @@ -17,7 +17,6 @@ import numpy as np from pandas._libs.tslibs import ( BaseOffset, - NaT, NaTType, Period, Timedelta, From 87873e48ddff3bf7bd45cf38d971a470631e9163 Mon Sep 17 00:00:00 2001 From: Eric Traut Date: Sat, 25 Sep 2021 10:51:43 -0700 Subject: [PATCH 02/16] Fixed formatting issues --- pandas/_libs/interval.pyi | 9 ++++----- pandas/_libs/missing.pyi | 14 +++++--------- pandas/_libs/tslibs/offsets.pyi | 8 ++++++-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/pandas/_libs/interval.pyi b/pandas/_libs/interval.pyi index fef7c2531b680..6e201601911da 100644 --- a/pandas/_libs/interval.pyi +++ b/pandas/_libs/interval.pyi @@ -21,10 +21,10 @@ class IntervalMixin: def length(self) -> float: ... @property def is_empty(self) -> bool: ... - def _check_closed_matches(self, other: IntervalMixin, name: str=...) -> None: ... + def _check_closed_matches(self, other: IntervalMixin, name: str = ...) -> None: ... class Interval(IntervalMixin): - def __init__(self, left: object, right: object, closed: str=...) -> None: ... + def __init__(self, left: object, right: object, closed: str = ...) -> None: ... @property def closed(self) -> str: ... @property @@ -42,6 +42,5 @@ class Interval(IntervalMixin): VALID_CLOSED: FrozenSet[str] def intervals_to_interval_bounds( - intervals: np.ndarray, - valdiate_closed: bool = ... -) -> Tuple[object, object, str]: ... \ No newline at end of file + intervals: np.ndarray, valdiate_closed: bool = ... +) -> Tuple[object, object, str]: ... diff --git a/pandas/_libs/missing.pyi b/pandas/_libs/missing.pyi index afe823ac32f5a..e405e33060026 100644 --- a/pandas/_libs/missing.pyi +++ b/pandas/_libs/missing.pyi @@ -1,12 +1,8 @@ -class C_NAType: - ... - - -class NAType(C_NAType): - ... +class C_NAType: ... +class NAType(C_NAType): ... NA: NAType -def is_matching_na(left: object, right: object, nan_matches_none: bool = ...) -> bool: - ... - +def is_matching_na( + left: object, right: object, nan_matches_none: bool = ... +) -> bool: ... diff --git a/pandas/_libs/tslibs/offsets.pyi b/pandas/_libs/tslibs/offsets.pyi index ba11ac256936a..4e5448612c0d9 100644 --- a/pandas/_libs/tslibs/offsets.pyi +++ b/pandas/_libs/tslibs/offsets.pyi @@ -25,7 +25,7 @@ class BaseOffset: def rule_code(self) -> str: ... def freqstr(self) -> str: ... # Next one is problematic due to circular imports - #def apply_index(self, dtindex: DatetimeIndex) -> DatetimeIndex: ... + # def apply_index(self, dtindex: DatetimeIndex) -> DatetimeIndex: ... def apply_index(self, dtindex): ... def _apply_array(self, dtarr) -> None: ... def rollback(self, dt: datetime) -> datetime: ... @@ -44,7 +44,9 @@ class SingleConstructorOffset(BaseOffset): def _from_name(cls, suffix=None): ... def __reduce__(self): ... -def to_offset(freq: Union[str, Tuple, timedelta, BaseOffset, None]) -> Union[BaseOffset, None]: ... +def to_offset( + freq: Union[str, Tuple, timedelta, BaseOffset, None] +) -> Union[BaseOffset, None]: ... class Tick(SingleConstructorOffset): def __init__(self, n: int = ..., normalize: bool = ...) -> None: ... @@ -56,8 +58,10 @@ class Second(Tick): ... class Milli(Tick): ... class Micro(Tick): ... class Nano(Tick): ... + class RelativeDeltaOffset(BaseOffset): def __init__(self, n: int = ..., normalize: bool = ..., **kwds: Any) -> None: ... + class BusinessMixin(SingleConstructorOffset): ... class BusinessDay(BusinessMixin): ... class BusinessHour(BusinessMixin): ... From da300c91c81763e0cd738f4d08c44d6d78253915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 28 Oct 2021 17:39:46 -0400 Subject: [PATCH 03/16] remove interval.pyi and offsets.pyi --- pandas/_libs/interval.pyi | 46 -------- pandas/_libs/interval.pyx | 6 +- pandas/_libs/missing.pyi | 10 ++ pandas/_libs/tslibs/offsets.pyi | 106 ------------------ pandas/_libs/tslibs/offsets.pyx | 4 +- pandas/_libs/tslibs/timestamps.pyi | 2 +- pandas/core/arrays/string_.py | 4 +- pandas/core/common.py | 3 +- pandas/core/dtypes/cast.py | 2 +- pandas/core/dtypes/dtypes.py | 8 +- pandas/core/dtypes/missing.py | 7 ++ pandas/core/ops/mask_ops.py | 16 ++- pandas/core/resample.py | 20 ++-- pandas/core/strings/object_array.py | 4 +- pandas/tests/indexes/test_engines.py | 7 +- .../tseries/offsets/test_business_day.py | 2 +- .../tseries/offsets/test_business_hour.py | 2 +- .../tseries/offsets/test_business_month.py | 10 +- .../tseries/offsets/test_business_quarter.py | 10 +- .../tseries/offsets/test_business_year.py | 12 +- .../offsets/test_custom_business_hour.py | 2 +- .../offsets/test_custom_business_month.py | 9 +- pandas/tests/tseries/offsets/test_month.py | 18 ++- pandas/tests/tseries/offsets/test_quarter.py | 2 +- pandas/tests/tseries/offsets/test_week.py | 11 +- pandas/tests/tseries/offsets/test_year.py | 10 +- 26 files changed, 129 insertions(+), 204 deletions(-) delete mode 100644 pandas/_libs/interval.pyi delete mode 100644 pandas/_libs/tslibs/offsets.pyi diff --git a/pandas/_libs/interval.pyi b/pandas/_libs/interval.pyi deleted file mode 100644 index 6e201601911da..0000000000000 --- a/pandas/_libs/interval.pyi +++ /dev/null @@ -1,46 +0,0 @@ -from typing import FrozenSet, Tuple - -import numpy as np - -class IntervalMixin: - @property - def _left(self) -> object: ... - @property - def _right(self) -> object: ... - @property - def closed_left(self) -> bool: ... - @property - def closed_right(self) -> bool: ... - @property - def open_left(self) -> bool: ... - @property - def open_right(self) -> bool: ... - @property - def mid(self) -> float: ... - @property - def length(self) -> float: ... - @property - def is_empty(self) -> bool: ... - def _check_closed_matches(self, other: IntervalMixin, name: str = ...) -> None: ... - -class Interval(IntervalMixin): - def __init__(self, left: object, right: object, closed: str = ...) -> None: ... - @property - def closed(self) -> str: ... - @property - def left(self) -> object: ... - @property - def right(self) -> object: ... - def __str__(self) -> str: ... - def __add__(self, y: Interval) -> Interval: ... - def __sub__(self, y: Interval) -> Interval: ... - def __mul__(self, y: Interval) -> Interval: ... - def __trudeiv__(self, y: Interval) -> Interval: ... - def __floordiv__(self, y: Interval) -> Interval: ... - def __overlaps__(self, other: Interval) -> bool: ... - -VALID_CLOSED: FrozenSet[str] - -def intervals_to_interval_bounds( - intervals: np.ndarray, valdiate_closed: bool = ... -) -> Tuple[object, object, str]: ... diff --git a/pandas/_libs/interval.pyx b/pandas/_libs/interval.pyx index 9d5922f8a50bd..aba635e19995a 100644 --- a/pandas/_libs/interval.pyx +++ b/pandas/_libs/interval.pyx @@ -516,9 +516,9 @@ def intervals_to_interval_bounds(ndarray intervals, bint validate_closed=True): Returns ------- - tuple of tuples - left : (ndarray, object, array) - right : (ndarray, object, array) + tuple of + left : ndarray + right : ndarray closed: str """ cdef: diff --git a/pandas/_libs/missing.pyi b/pandas/_libs/missing.pyi index e405e33060026..ea2a91a9361e7 100644 --- a/pandas/_libs/missing.pyi +++ b/pandas/_libs/missing.pyi @@ -1,3 +1,7 @@ +import numpy as np + +from pandas._typing import npt + class C_NAType: ... class NAType(C_NAType): ... @@ -6,3 +10,9 @@ NA: NAType def is_matching_na( left: object, right: object, nan_matches_none: bool = ... ) -> bool: ... +def isposinf_scalar(val: object) -> bool: ... +def isneginf_scalar(val: object) -> bool: ... +def checknull(val: object) -> bool: ... +def checknull_old(val: object) -> bool: ... +def isnaobj(arr: np.ndarray) -> npt.NDArray[np.bool_]: ... +def isnaobj_old(arr: np.ndarray) -> npt.NDArray[np.bool_]: ... diff --git a/pandas/_libs/tslibs/offsets.pyi b/pandas/_libs/tslibs/offsets.pyi deleted file mode 100644 index 4e5448612c0d9..0000000000000 --- a/pandas/_libs/tslibs/offsets.pyi +++ /dev/null @@ -1,106 +0,0 @@ -from __future__ import annotations -from datetime import datetime -from typing import Any, Tuple, Union -from datetime import timedelta - -class BaseOffset: - def __init__(self, n: int = ..., normalize: bool = ...) -> None: ... - def __eq__(self, other) -> bool: ... - def __ne__(self, other) -> bool: ... - def __hash__(self) -> int: ... - @property - def kwds(self) -> dict: ... - @property - def base(self) -> BaseOffset: ... - def __add__(self, other) -> BaseOffset: ... - def __sub__(self, other) -> BaseOffset: ... - def __call__(self, other): ... - def __mul__(self, other): ... - def __neg__(self) -> BaseOffset: ... - def copy(self) -> BaseOffset: ... - def __repr__(self) -> str: ... - @property - def name(self) -> str: ... - @property - def rule_code(self) -> str: ... - def freqstr(self) -> str: ... - # Next one is problematic due to circular imports - # def apply_index(self, dtindex: DatetimeIndex) -> DatetimeIndex: ... - def apply_index(self, dtindex): ... - def _apply_array(self, dtarr) -> None: ... - def rollback(self, dt: datetime) -> datetime: ... - def rollforward(self, dt: datetime) -> datetime: ... - def is_on_offset(self, dt: datetime) -> bool: ... - def __setstate__(self, state) -> None: ... - def __getstate__(self): ... - @property - def nanos(self) -> int: ... - def onOffset(self, dt: datetime) -> bool: ... - def isAnchored(self) -> bool: ... - def is_anchored(self) -> bool: ... - -class SingleConstructorOffset(BaseOffset): - @classmethod - def _from_name(cls, suffix=None): ... - def __reduce__(self): ... - -def to_offset( - freq: Union[str, Tuple, timedelta, BaseOffset, None] -) -> Union[BaseOffset, None]: ... - -class Tick(SingleConstructorOffset): - def __init__(self, n: int = ..., normalize: bool = ...) -> None: ... - -class Day(Tick): ... -class Hour(Tick): ... -class Minute(Tick): ... -class Second(Tick): ... -class Milli(Tick): ... -class Micro(Tick): ... -class Nano(Tick): ... - -class RelativeDeltaOffset(BaseOffset): - def __init__(self, n: int = ..., normalize: bool = ..., **kwds: Any) -> None: ... - -class BusinessMixin(SingleConstructorOffset): ... -class BusinessDay(BusinessMixin): ... -class BusinessHour(BusinessMixin): ... -class WeekOfMonthMixin(SingleConstructorOffset): ... -class YearOffset(SingleConstructorOffset): ... -class BYearEnd(YearOffset): ... -class BYearBegin(YearOffset): ... -class YearEnd(YearOffset): ... -class YearBegin(YearOffset): ... -class QuarterOffset(SingleConstructorOffset): ... -class BQuarterEnd(QuarterOffset): ... -class BQuarterBegin(QuarterOffset): ... -class QuarterEnd(QuarterOffset): ... -class QuarterBegin(QuarterOffset): ... -class MonthOffset(SingleConstructorOffset): ... -class MonthEnd(MonthOffset): ... -class MonthBegin(MonthOffset): ... -class BusinessMonthEnd(MonthOffset): ... -class BusinessMonthBegin(MonthOffset): ... -class SemiMonthOffset(SingleConstructorOffset): ... -class SemiMonthEnd(SemiMonthOffset): ... -class SemiMonthBegin(SemiMonthOffset): ... -class Week(SingleConstructorOffset): ... -class WeekOfMonth(WeekOfMonthMixin): ... -class LastWeekOfMonth(WeekOfMonthMixin): ... -class FY5253Mixin(SingleConstructorOffset): ... -class FY5253(FY5253Mixin): ... -class FY5253Quarter(FY5253Mixin): ... -class Easter(SingleConstructorOffset): ... -class _CustomBusinessMonth(BusinessMixin): ... -class CustomBusinessDay(BusinessDay): ... -class CustomBusinessHour(BusinessHour): ... -class CustomBusinessMonthEnd(_CustomBusinessMonth): ... -class CustomBusinessMonthBegin(_CustomBusinessMonth): ... -class DateOffset(RelativeDeltaOffset): ... - -BDay = BusinessDay -BMonthEnd = BusinessMonthEnd -BMonthBegin = BusinessMonthBegin -CBMonthEnd = CustomBusinessMonthEnd -CBMonthBegin = CustomBusinessMonthBegin -CDay = CustomBusinessDay diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index f293557a51ac2..7e6d8fa38aa45 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -3573,7 +3573,7 @@ cpdef to_offset(freq): Parameters ---------- - freq : str, tuple, datetime.timedelta, DateOffset or None + freq : str, datetime.timedelta, BaseOffset or None Returns ------- @@ -3586,7 +3586,7 @@ cpdef to_offset(freq): See Also -------- - DateOffset : Standard kind of date increment used for a date range. + BaseOffset : Standard kind of date increment used for a date range. Examples -------- diff --git a/pandas/_libs/tslibs/timestamps.pyi b/pandas/_libs/tslibs/timestamps.pyi index 17ad2bdb1c936..17df594a39c44 100644 --- a/pandas/_libs/tslibs/timestamps.pyi +++ b/pandas/_libs/tslibs/timestamps.pyi @@ -24,7 +24,7 @@ from pandas._libs.tslibs import ( _S = TypeVar("_S") -def integer_op_not_supported(obj) -> None: ... +def integer_op_not_supported(obj) -> TypeError: ... class Timestamp(datetime): min: ClassVar[Timestamp] diff --git a/pandas/core/arrays/string_.py b/pandas/core/arrays/string_.py index df71501d55b20..c6987d9a11e4c 100644 --- a/pandas/core/arrays/string_.py +++ b/pandas/core/arrays/string_.py @@ -512,7 +512,9 @@ def _cmp_method(self, other, op): # ------------------------------------------------------------------------ # String methods interface - _str_na_value = StringDtype.na_value + # error: Incompatible types in assignment (expression has type "NAType", + # base class "PandasArray" defined the type as "float") + _str_na_value = StringDtype.na_value # type: ignore[assignment] def _str_map( self, f, na_value=None, dtype: Dtype | None = None, convert: bool = True diff --git a/pandas/core/common.py b/pandas/core/common.py index 590296c4b12f5..bda7a7cb6804a 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -33,6 +33,7 @@ ArrayLike, NpDtype, RandomState, + IndexLabel, Scalar, T, ) @@ -515,7 +516,7 @@ def f(x): def convert_to_list_like( - values: Scalar | Iterable | AnyArrayLike, + values: Scalar | IndexLabel | AnyArrayLike, ) -> list | AnyArrayLike: """ Convert list-like or scalar input to list-like. List, numpy and pandas array-like diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index 79ea7731466d4..9d6257e7b4db1 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -912,7 +912,7 @@ def maybe_upcast( # We get a copy in all cases _except_ (values.dtype == new_dtype and not copy) upcast_values = values.astype(new_dtype, copy=copy) - return upcast_values, fill_value # type: ignore[return-value] + return upcast_values, fill_value def invalidate_string_dtypes(dtype_set: set[DtypeObj]): diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index 71da0a4b20b41..e74d73b84e94b 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -876,15 +876,15 @@ def freq(self): @classmethod def _parse_dtype_strict(cls, freq: str_type) -> BaseOffset: - if isinstance(freq, str): + if isinstance(freq, str): # note: freq is already of type str! if freq.startswith("period[") or freq.startswith("Period["): m = cls._match.search(freq) if m is not None: freq = m.group("freq") - freq = to_offset(freq) - if freq is not None: - return freq + freq_offset = to_offset(freq) + if freq_offset is not None: + return freq_offset raise ValueError("could not construct PeriodDtype") diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index 47949334df021..94c17c5572d43 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -1,8 +1,11 @@ """ missing types & inference """ +from __future__ import annotations + from decimal import Decimal from functools import partial +from typing import TYPE_CHECKING import numpy as np @@ -51,6 +54,9 @@ ) from pandas.core.dtypes.inference import is_list_like +if TYPE_CHECKING: + from pandas.core.arrays.base import ExtensionArraySupportsAnyAll + isposinf_scalar = libmissing.isposinf_scalar isneginf_scalar = libmissing.isneginf_scalar @@ -235,6 +241,7 @@ def _isna_array(values: ArrayLike, inf_as_na: bool = False): Array of boolean values denoting the NA status of each element. """ dtype = values.dtype + result: np.ndarray | ExtensionArraySupportsAnyAll if not isinstance(values, np.ndarray): # i.e. ExtensionArray diff --git a/pandas/core/ops/mask_ops.py b/pandas/core/ops/mask_ops.py index d21c80b81b582..7d14472689eca 100644 --- a/pandas/core/ops/mask_ops.py +++ b/pandas/core/ops/mask_ops.py @@ -46,7 +46,9 @@ def kleene_or( raise_for_nan(right, method="or") - if right is libmissing.NA: + # error: Non-overlapping identity check (left operand type: + # "Union[bool, ndarray[Any, Any]]", right operand type: "NAType") + if right is libmissing.NA: # type: ignore[comparison-overlap] result = left.copy() else: result = left | right @@ -63,7 +65,9 @@ def kleene_or( else: if right is True: mask = np.zeros_like(left_mask) - elif right is libmissing.NA: + # error: Non-overlapping identity check (left operand type: + # "Union[bool, ndarray[Any, Any]]", right operand type: "NAType") + elif right is libmissing.NA: # type: ignore[comparison-overlap] mask = (~left & ~left_mask) | left_mask else: # False @@ -103,7 +107,9 @@ def kleene_xor( return kleene_xor(right, left, right_mask, left_mask) raise_for_nan(right, method="xor") - if right is libmissing.NA: + # error: Non-overlapping identity check (left operand type: + # "Union[bool, ndarray[Any, Any]]", right operand type: "NAType") + if right is libmissing.NA: # type: ignore[comparison-overlap] result = np.zeros_like(left) else: # error: Incompatible types in assignment (expression has type @@ -111,7 +117,9 @@ def kleene_xor( result = left ^ right # type: ignore[assignment] if right_mask is None: - if right is libmissing.NA: + # error: Non-overlapping identity check (left operand type: + # "Union[bool, ndarray[Any, Any]]", right operand type: "NAType") + if right is libmissing.NA: # type: ignore[comparison-overlap] mask = np.ones_like(left_mask) else: mask = left_mask.copy() diff --git a/pandas/core/resample.py b/pandas/core/resample.py index f132dd88d5147..e00defcfcffd1 100644 --- a/pandas/core/resample.py +++ b/pandas/core/resample.py @@ -2012,30 +2012,30 @@ def _adjust_dates_anchored( if closed == "right": if foffset > 0: # roll back - fresult = first.value - foffset + fresult_int = first.value - foffset else: - fresult = first.value - freq.nanos + fresult_int = first.value - freq.nanos if loffset > 0: # roll forward - lresult = last.value + (freq.nanos - loffset) + lresult_int = last.value + (freq.nanos - loffset) else: # already the end of the road - lresult = last.value + lresult_int = last.value else: # closed == 'left' if foffset > 0: - fresult = first.value - foffset + fresult_int = first.value - foffset else: # start of the road - fresult = first.value + fresult_int = first.value if loffset > 0: # roll forward - lresult = last.value + (freq.nanos - loffset) + lresult_int = last.value + (freq.nanos - loffset) else: - lresult = last.value + freq.nanos - fresult = Timestamp(fresult) - lresult = Timestamp(lresult) + lresult_int = last.value + freq.nanos + fresult = Timestamp(fresult_int) + lresult = Timestamp(lresult_int) if first_tzinfo is not None: fresult = fresult.tz_localize("UTC").tz_convert(first_tzinfo) if last_tzinfo is not None: diff --git a/pandas/core/strings/object_array.py b/pandas/core/strings/object_array.py index 2ce5c0cbea272..6b0380a292f07 100644 --- a/pandas/core/strings/object_array.py +++ b/pandas/core/strings/object_array.py @@ -193,7 +193,7 @@ def rep(x, r): return result def _str_match( - self, pat: str, case: bool = True, flags: int = 0, na: Scalar = None + self, pat: str, case: bool = True, flags: int = 0, na: Scalar | None = None ): if not case: flags |= re.IGNORECASE @@ -208,7 +208,7 @@ def _str_fullmatch( pat: str | re.Pattern, case: bool = True, flags: int = 0, - na: Scalar = None, + na: Scalar | None = None, ): if not case: flags |= re.IGNORECASE diff --git a/pandas/tests/indexes/test_engines.py b/pandas/tests/indexes/test_engines.py index 02d8c5b2a6a22..8cd9da51d782f 100644 --- a/pandas/tests/indexes/test_engines.py +++ b/pandas/tests/indexes/test_engines.py @@ -57,7 +57,12 @@ class TestTimedeltaEngine: @pytest.mark.parametrize( "scalar", [ - pd.Timestamp(pd.Timedelta(days=42).asm8.view("datetime64[ns]")), + # error: Argument 1 to "Timestamp" has incompatible type + # "timedelta64"; expected "Union[integer[Any], float, str, date, + # datetime64]" + pd.Timestamp( + pd.Timedelta(days=42).asm8.view("datetime64[ns]") # type: ignore[arg-type] + ), pd.Timedelta(days=42).value, pd.Timedelta(days=42).to_pytimedelta(), pd.Timedelta(days=42).to_timedelta64(), diff --git a/pandas/tests/tseries/offsets/test_business_day.py b/pandas/tests/tseries/offsets/test_business_day.py index c40ae611687dd..d5b3e9ecad3c3 100644 --- a/pandas/tests/tseries/offsets/test_business_day.py +++ b/pandas/tests/tseries/offsets/test_business_day.py @@ -32,7 +32,7 @@ class TestBusinessDay(Base): - _offset = BDay + _offset: type[BDay] = BDay def setup_method(self, method): self.d = datetime(2008, 1, 1) diff --git a/pandas/tests/tseries/offsets/test_business_hour.py b/pandas/tests/tseries/offsets/test_business_hour.py index 401bfe664a3a2..b37555e63ab7f 100644 --- a/pandas/tests/tseries/offsets/test_business_hour.py +++ b/pandas/tests/tseries/offsets/test_business_hour.py @@ -30,7 +30,7 @@ class TestBusinessHour(Base): - _offset = BusinessHour + _offset: type[BusinessHour] = BusinessHour def setup_method(self, method): self.d = datetime(2014, 7, 1, 10, 00) diff --git a/pandas/tests/tseries/offsets/test_business_month.py b/pandas/tests/tseries/offsets/test_business_month.py index bb2049fd35489..bcb594d86a4aa 100644 --- a/pandas/tests/tseries/offsets/test_business_month.py +++ b/pandas/tests/tseries/offsets/test_business_month.py @@ -7,6 +7,8 @@ import pytest +from pandas._libs.tslibs.offsets import MonthOffset + import pandas as pd from pandas.tests.tseries.offsets.common import ( Base, @@ -43,7 +45,11 @@ def test_apply_index(cls, n): assert res2.iloc[-1] == ser.iloc[-1] + offset -class TestBMonthBegin(Base): +class BaseMonthOffset(Base): + _offset: type[MonthOffset] = BMonthBegin + + +class TestBMonthBegin(BaseMonthOffset): _offset = BMonthBegin def test_offsets_compare_equal(self): @@ -131,7 +137,7 @@ def test_is_on_offset(self, case): assert_is_on_offset(offset, dt, expected) -class TestBMonthEnd(Base): +class TestBMonthEnd(BaseMonthOffset): _offset = BMonthEnd def test_normalize(self): diff --git a/pandas/tests/tseries/offsets/test_business_quarter.py b/pandas/tests/tseries/offsets/test_business_quarter.py index b928b47d30a0d..4c15763ea904b 100644 --- a/pandas/tests/tseries/offsets/test_business_quarter.py +++ b/pandas/tests/tseries/offsets/test_business_quarter.py @@ -7,6 +7,8 @@ import pytest +from pandas._libs.tslibs.offsets import QuarterOffset + from pandas.tests.tseries.offsets.common import ( Base, assert_is_on_offset, @@ -43,7 +45,11 @@ def test_on_offset(offset): assert res == slow_version -class TestBQuarterBegin(Base): +class BaseQuarter(Base): + _offset: type[QuarterOffset] = BQuarterBegin + + +class TestBQuarterBegin(BaseQuarter): _offset = BQuarterBegin def test_repr(self): @@ -168,7 +174,7 @@ def test_offset(self, case): assert_offset_equal(offset, base, expected) -class TestBQuarterEnd(Base): +class TestBQuarterEnd(BaseQuarter): _offset = BQuarterEnd def test_repr(self): diff --git a/pandas/tests/tseries/offsets/test_business_year.py b/pandas/tests/tseries/offsets/test_business_year.py index d531a586c5db2..b0c7724154aea 100644 --- a/pandas/tests/tseries/offsets/test_business_year.py +++ b/pandas/tests/tseries/offsets/test_business_year.py @@ -7,6 +7,8 @@ import pytest +from pandas._libs.tslibs.offsets import YearOffset + from pandas.tests.tseries.offsets.common import ( Base, assert_is_on_offset, @@ -19,7 +21,11 @@ ) -class TestBYearBegin(Base): +class BaseYear(Base): + _offset: type[YearOffset] = BYearBegin + + +class TestBYearBegin(BaseYear): _offset = BYearBegin def test_misspecified(self): @@ -92,7 +98,7 @@ def test_offset(self, case): assert_offset_equal(offset, base, expected) -class TestBYearEnd(Base): +class TestBYearEnd(BaseYear): _offset = BYearEnd offset_cases = [] @@ -165,7 +171,7 @@ def test_is_on_offset(self, case): assert_is_on_offset(offset, dt, expected) -class TestBYearEndLagged(Base): +class TestBYearEndLagged(BaseYear): _offset = BYearEnd def test_bad_month_fail(self): diff --git a/pandas/tests/tseries/offsets/test_custom_business_hour.py b/pandas/tests/tseries/offsets/test_custom_business_hour.py index dbc0ff4371fd9..f942d7ef02391 100644 --- a/pandas/tests/tseries/offsets/test_custom_business_hour.py +++ b/pandas/tests/tseries/offsets/test_custom_business_hour.py @@ -23,7 +23,7 @@ class TestCustomBusinessHour(Base): - _offset = CustomBusinessHour + _offset: type[CustomBusinessHour] = CustomBusinessHour holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] def setup_method(self, method): diff --git a/pandas/tests/tseries/offsets/test_custom_business_month.py b/pandas/tests/tseries/offsets/test_custom_business_month.py index fb0f331fa3ad3..5e4e1b19accff 100644 --- a/pandas/tests/tseries/offsets/test_custom_business_month.py +++ b/pandas/tests/tseries/offsets/test_custom_business_month.py @@ -17,6 +17,7 @@ CBMonthBegin, CBMonthEnd, CDay, + _CustomBusinessMonth, ) from pandas import ( @@ -65,7 +66,11 @@ def test_copy(self): assert off == off.copy() -class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): +class BaseCustomBusinessMonth(CustomBusinessMonthBase, Base): + _offset: type[_CustomBusinessMonth] = CBMonthBegin + + +class TestCustomBusinessMonthBegin(BaseCustomBusinessMonth): _offset = CBMonthBegin def test_different_normalize_equals(self): @@ -255,7 +260,7 @@ def test_apply_with_extra_offset(self, case): assert_offset_equal(offset, base, expected) -class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): +class TestCustomBusinessMonthEnd(BaseCustomBusinessMonth): _offset = CBMonthEnd def test_different_normalize_equals(self): diff --git a/pandas/tests/tseries/offsets/test_month.py b/pandas/tests/tseries/offsets/test_month.py index 00b9d7e186a59..bb2c8c60ffa28 100644 --- a/pandas/tests/tseries/offsets/test_month.py +++ b/pandas/tests/tseries/offsets/test_month.py @@ -13,8 +13,10 @@ from pandas._libs.tslibs.offsets import ( MonthBegin, MonthEnd, + MonthOffset, SemiMonthBegin, SemiMonthEnd, + SemiMonthOffset, ) from pandas import ( @@ -30,7 +32,11 @@ ) -class TestSemiMonthEnd(Base): +class BaseSemiMonthOffset(Base): + _offset: type[SemiMonthOffset] = SemiMonthEnd + + +class TestSemiMonthEnd(BaseSemiMonthOffset): _offset = SemiMonthEnd offset1 = _offset() offset2 = _offset(2) @@ -294,7 +300,7 @@ def test_vectorized_offset_addition(self, klass): tm.assert_equal(result2, exp) -class TestSemiMonthBegin(Base): +class TestSemiMonthBegin(BaseSemiMonthOffset): _offset = SemiMonthBegin offset1 = _offset() offset2 = _offset(2) @@ -534,7 +540,11 @@ def test_vectorized_offset_addition(self, klass): tm.assert_equal(result2, exp) -class TestMonthBegin(Base): +class BaseMonthOffset(Base): + _offset: type[MonthOffset] = MonthBegin + + +class TestMonthBegin(BaseMonthOffset): _offset = MonthBegin offset_cases = [] @@ -599,7 +609,7 @@ def test_offset(self, case): assert_offset_equal(offset, base, expected) -class TestMonthEnd(Base): +class TestMonthEnd(BaseMonthOffset): _offset = MonthEnd def test_day_of_month(self): diff --git a/pandas/tests/tseries/offsets/test_quarter.py b/pandas/tests/tseries/offsets/test_quarter.py index e076fb9f4d53b..8d9c6a606466a 100644 --- a/pandas/tests/tseries/offsets/test_quarter.py +++ b/pandas/tests/tseries/offsets/test_quarter.py @@ -152,7 +152,7 @@ def test_offset(self, case): class TestQuarterEnd(Base): - _offset = QuarterEnd + _offset: type[QuarterEnd] = QuarterEnd def test_repr(self): expected = "" diff --git a/pandas/tests/tseries/offsets/test_week.py b/pandas/tests/tseries/offsets/test_week.py index be574fd963eff..9306d935a4fab 100644 --- a/pandas/tests/tseries/offsets/test_week.py +++ b/pandas/tests/tseries/offsets/test_week.py @@ -17,6 +17,7 @@ LastWeekOfMonth, Week, WeekOfMonth, + WeekOfMonthMixin, ) from pandas.tests.tseries.offsets.common import ( @@ -28,7 +29,7 @@ class TestWeek(Base): - _offset = Week + _offset: type[Week] = Week d = Timestamp(datetime(2008, 1, 2)) offset1 = _offset() offset2 = _offset(2) @@ -150,7 +151,11 @@ def test_week_add_invalid(self): offset + other -class TestWeekOfMonth(Base): +class BaseWeekOfMonthMixin(Base): + _offset: type[WeekOfMonthMixin] = WeekOfMonth + + +class TestWeekOfMonth(BaseWeekOfMonthMixin): _offset = WeekOfMonth offset1 = _offset() offset2 = _offset(2) @@ -266,7 +271,7 @@ def test_is_on_offset_nanoseconds(self, n, week, date, tz): assert fast == slow -class TestLastWeekOfMonth(Base): +class TestLastWeekOfMonth(BaseWeekOfMonthMixin): _offset = LastWeekOfMonth offset1 = _offset() offset2 = _offset(2) diff --git a/pandas/tests/tseries/offsets/test_year.py b/pandas/tests/tseries/offsets/test_year.py index 85994adb6f19d..18f671436ee2a 100644 --- a/pandas/tests/tseries/offsets/test_year.py +++ b/pandas/tests/tseries/offsets/test_year.py @@ -7,6 +7,8 @@ import pytest +from pandas._libs.tslibs.offsets import YearOffset + from pandas.tests.tseries.offsets.common import ( Base, assert_is_on_offset, @@ -19,7 +21,11 @@ ) -class TestYearBegin(Base): +class BaseYear(Base): + _offset: type[YearOffset] = YearBegin + + +class TestYearBegin(BaseYear): _offset = YearBegin def test_misspecified(self): @@ -173,7 +179,7 @@ def test_is_on_offset(self, case): assert_is_on_offset(offset, dt, expected) -class TestYearEnd(Base): +class TestYearEnd(BaseYear): _offset = YearEnd def test_misspecified(self): From 47e6cfb4c12e521969d3cbe1fec59f135f302b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 31 Oct 2021 09:41:09 -0400 Subject: [PATCH 04/16] pre-commit --- pandas/core/common.py | 2 +- pandas/tests/indexes/test_engines.py | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pandas/core/common.py b/pandas/core/common.py index bda7a7cb6804a..53526c41c3cf3 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -31,9 +31,9 @@ from pandas._typing import ( AnyArrayLike, ArrayLike, + IndexLabel, NpDtype, RandomState, - IndexLabel, Scalar, T, ) diff --git a/pandas/tests/indexes/test_engines.py b/pandas/tests/indexes/test_engines.py index 8cd9da51d782f..c80655ec81010 100644 --- a/pandas/tests/indexes/test_engines.py +++ b/pandas/tests/indexes/test_engines.py @@ -61,7 +61,11 @@ class TestTimedeltaEngine: # "timedelta64"; expected "Union[integer[Any], float, str, date, # datetime64]" pd.Timestamp( - pd.Timedelta(days=42).asm8.view("datetime64[ns]") # type: ignore[arg-type] + ( + pd.Timedelta(days=42).asm8.view( + "datetime64[ns]" + ) # type: ignore[arg-type] + ) ), pd.Timedelta(days=42).value, pd.Timedelta(days=42).to_pytimedelta(), From aa96f6c31e9ed785531709d857ebf158d68935b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 31 Oct 2021 09:55:16 -0400 Subject: [PATCH 05/16] () --- pandas/tests/indexes/test_engines.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pandas/tests/indexes/test_engines.py b/pandas/tests/indexes/test_engines.py index c80655ec81010..1fc8514b6b811 100644 --- a/pandas/tests/indexes/test_engines.py +++ b/pandas/tests/indexes/test_engines.py @@ -61,11 +61,9 @@ class TestTimedeltaEngine: # "timedelta64"; expected "Union[integer[Any], float, str, date, # datetime64]" pd.Timestamp( - ( - pd.Timedelta(days=42).asm8.view( - "datetime64[ns]" - ) # type: ignore[arg-type] - ) + pd.Timedelta(days=42).asm8.view( + "datetime64[ns]" + ) # type: ignore[arg-type] ), pd.Timedelta(days=42).value, pd.Timedelta(days=42).to_pytimedelta(), From e9e9878ab2b8f6d1d8c333e856193c54b55eb1db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 31 Oct 2021 16:54:43 -0400 Subject: [PATCH 06/16] mypy errors on CI --- pandas/core/dtypes/cast.py | 6 +++++- pandas/tests/indexes/test_engines.py | 9 +-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/pandas/core/dtypes/cast.py b/pandas/core/dtypes/cast.py index 9d6257e7b4db1..3b04490ae098c 100644 --- a/pandas/core/dtypes/cast.py +++ b/pandas/core/dtypes/cast.py @@ -912,7 +912,11 @@ def maybe_upcast( # We get a copy in all cases _except_ (values.dtype == new_dtype and not copy) upcast_values = values.astype(new_dtype, copy=copy) - return upcast_values, fill_value + # error: Incompatible return value type (got "Tuple[ndarray[Any, dtype[Any]], + # Union[Union[str, int, float, bool] Union[Period, Timestamp, Timedelta, Any]]]", + # expected "Tuple[NumpyArrayT, Union[Union[str, int, float, bool], Union[Period, + # Timestamp, Timedelta, Any]]]") + return upcast_values, fill_value # type: ignore[return-value] def invalidate_string_dtypes(dtype_set: set[DtypeObj]): diff --git a/pandas/tests/indexes/test_engines.py b/pandas/tests/indexes/test_engines.py index 1fc8514b6b811..02d8c5b2a6a22 100644 --- a/pandas/tests/indexes/test_engines.py +++ b/pandas/tests/indexes/test_engines.py @@ -57,14 +57,7 @@ class TestTimedeltaEngine: @pytest.mark.parametrize( "scalar", [ - # error: Argument 1 to "Timestamp" has incompatible type - # "timedelta64"; expected "Union[integer[Any], float, str, date, - # datetime64]" - pd.Timestamp( - pd.Timedelta(days=42).asm8.view( - "datetime64[ns]" - ) # type: ignore[arg-type] - ), + pd.Timestamp(pd.Timedelta(days=42).asm8.view("datetime64[ns]")), pd.Timedelta(days=42).value, pd.Timedelta(days=42).to_pytimedelta(), pd.Timedelta(days=42).to_timedelta64(), From 1002d001800bceee30d674a0d9029f629d96cfe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 4 Nov 2021 16:54:19 -0400 Subject: [PATCH 07/16] remove c class --- pandas/_libs/missing.pyi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pandas/_libs/missing.pyi b/pandas/_libs/missing.pyi index ea2a91a9361e7..1a5b7ce7ad6d2 100644 --- a/pandas/_libs/missing.pyi +++ b/pandas/_libs/missing.pyi @@ -2,8 +2,7 @@ import numpy as np from pandas._typing import npt -class C_NAType: ... -class NAType(C_NAType): ... +class NAType: ... NA: NAType From b59ecd88b39cb4ae4dae22c6fa1ab7bbe05a5980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 4 Nov 2021 19:28:37 -0400 Subject: [PATCH 08/16] future imports --- pandas/tests/tseries/offsets/test_business_day.py | 2 ++ pandas/tests/tseries/offsets/test_business_hour.py | 2 ++ pandas/tests/tseries/offsets/test_business_month.py | 2 ++ pandas/tests/tseries/offsets/test_business_quarter.py | 2 ++ pandas/tests/tseries/offsets/test_business_year.py | 2 ++ pandas/tests/tseries/offsets/test_custom_business_day.py | 2 ++ pandas/tests/tseries/offsets/test_custom_business_hour.py | 2 ++ 7 files changed, 14 insertions(+) diff --git a/pandas/tests/tseries/offsets/test_business_day.py b/pandas/tests/tseries/offsets/test_business_day.py index d5b3e9ecad3c3..c7309bbe330bb 100644 --- a/pandas/tests/tseries/offsets/test_business_day.py +++ b/pandas/tests/tseries/offsets/test_business_day.py @@ -1,6 +1,8 @@ """ Tests for offsets.BDay """ +from __future__ import annotations + from datetime import ( date, datetime, diff --git a/pandas/tests/tseries/offsets/test_business_hour.py b/pandas/tests/tseries/offsets/test_business_hour.py index b37555e63ab7f..7d75543ffeb1f 100644 --- a/pandas/tests/tseries/offsets/test_business_hour.py +++ b/pandas/tests/tseries/offsets/test_business_hour.py @@ -1,6 +1,8 @@ """ Tests for offsets.BusinessHour """ +from __future__ import annotations + from datetime import ( datetime, time as dt_time, diff --git a/pandas/tests/tseries/offsets/test_business_month.py b/pandas/tests/tseries/offsets/test_business_month.py index bcb594d86a4aa..c99a060cfed9b 100644 --- a/pandas/tests/tseries/offsets/test_business_month.py +++ b/pandas/tests/tseries/offsets/test_business_month.py @@ -3,6 +3,8 @@ - BMonthBegin - BMonthEnd """ +from __future__ import annotations + from datetime import datetime import pytest diff --git a/pandas/tests/tseries/offsets/test_business_quarter.py b/pandas/tests/tseries/offsets/test_business_quarter.py index 4c15763ea904b..692f05f70738a 100644 --- a/pandas/tests/tseries/offsets/test_business_quarter.py +++ b/pandas/tests/tseries/offsets/test_business_quarter.py @@ -3,6 +3,8 @@ - BQuarterBegin - BQuarterEnd """ +from __future__ import annotations + from datetime import datetime import pytest diff --git a/pandas/tests/tseries/offsets/test_business_year.py b/pandas/tests/tseries/offsets/test_business_year.py index b0c7724154aea..7abf68d065d22 100644 --- a/pandas/tests/tseries/offsets/test_business_year.py +++ b/pandas/tests/tseries/offsets/test_business_year.py @@ -3,6 +3,8 @@ - BYearBegin - BYearEnd """ +from __future__ import annotations + from datetime import datetime import pytest diff --git a/pandas/tests/tseries/offsets/test_custom_business_day.py b/pandas/tests/tseries/offsets/test_custom_business_day.py index 3bbbaa891709f..cd700018b423b 100644 --- a/pandas/tests/tseries/offsets/test_custom_business_day.py +++ b/pandas/tests/tseries/offsets/test_custom_business_day.py @@ -1,6 +1,8 @@ """ Tests for offsets.CustomBusinessDay / CDay """ +from __future__ import annotations + from datetime import ( datetime, timedelta, diff --git a/pandas/tests/tseries/offsets/test_custom_business_hour.py b/pandas/tests/tseries/offsets/test_custom_business_hour.py index f942d7ef02391..398f294f6140c 100644 --- a/pandas/tests/tseries/offsets/test_custom_business_hour.py +++ b/pandas/tests/tseries/offsets/test_custom_business_hour.py @@ -1,6 +1,8 @@ """ Tests for offsets.CustomBusinessHour """ +from __future__ import annotations + from datetime import datetime import numpy as np From f7ca6939be34348aaee94c77a8a5c5c8fdb9ed7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Thu, 4 Nov 2021 20:26:22 -0400 Subject: [PATCH 09/16] more future --- pandas/tests/tseries/offsets/test_custom_business_month.py | 2 ++ pandas/tests/tseries/offsets/test_month.py | 2 ++ pandas/tests/tseries/offsets/test_quarter.py | 2 ++ pandas/tests/tseries/offsets/test_week.py | 2 ++ pandas/tests/tseries/offsets/test_year.py | 2 ++ 5 files changed, 10 insertions(+) diff --git a/pandas/tests/tseries/offsets/test_custom_business_month.py b/pandas/tests/tseries/offsets/test_custom_business_month.py index 5e4e1b19accff..22bf362b9f4eb 100644 --- a/pandas/tests/tseries/offsets/test_custom_business_month.py +++ b/pandas/tests/tseries/offsets/test_custom_business_month.py @@ -4,6 +4,8 @@ - CustomBusinessMonthBegin - CustomBusinessMonthEnd """ +from __future__ import annotations + from datetime import ( date, datetime, diff --git a/pandas/tests/tseries/offsets/test_month.py b/pandas/tests/tseries/offsets/test_month.py index bb2c8c60ffa28..5059b7fe0001d 100644 --- a/pandas/tests/tseries/offsets/test_month.py +++ b/pandas/tests/tseries/offsets/test_month.py @@ -5,6 +5,8 @@ - MonthBegin - MonthEnd """ +from __future__ import annotations + from datetime import datetime import pytest diff --git a/pandas/tests/tseries/offsets/test_quarter.py b/pandas/tests/tseries/offsets/test_quarter.py index 8d9c6a606466a..9063b71cdece4 100644 --- a/pandas/tests/tseries/offsets/test_quarter.py +++ b/pandas/tests/tseries/offsets/test_quarter.py @@ -3,6 +3,8 @@ - QuarterBegin - QuarterEnd """ +from __future__ import annotations + from datetime import datetime import pytest diff --git a/pandas/tests/tseries/offsets/test_week.py b/pandas/tests/tseries/offsets/test_week.py index 9306d935a4fab..08072228ac4f4 100644 --- a/pandas/tests/tseries/offsets/test_week.py +++ b/pandas/tests/tseries/offsets/test_week.py @@ -4,6 +4,8 @@ - WeekOfMonth - LastWeekOfMonth """ +from __future__ import annotations + from datetime import ( datetime, timedelta, diff --git a/pandas/tests/tseries/offsets/test_year.py b/pandas/tests/tseries/offsets/test_year.py index 18f671436ee2a..4f194209ed8ef 100644 --- a/pandas/tests/tseries/offsets/test_year.py +++ b/pandas/tests/tseries/offsets/test_year.py @@ -3,6 +3,8 @@ - YearBegin - YearEnd """ +from __future__ import annotations + from datetime import datetime import pytest From d5f807d07df7a6f7f11890563f816274d63a24d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Mon, 8 Nov 2021 20:00:08 -0500 Subject: [PATCH 10/16] kleene_or/xor and NA --- pandas/core/ops/mask_ops.py | 38 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/pandas/core/ops/mask_ops.py b/pandas/core/ops/mask_ops.py index 7d14472689eca..2c72b3323e41e 100644 --- a/pandas/core/ops/mask_ops.py +++ b/pandas/core/ops/mask_ops.py @@ -12,8 +12,8 @@ def kleene_or( - left: bool | np.ndarray, - right: bool | np.ndarray, + left: bool | np.ndarray | libmissing.NAType, + right: bool | np.ndarray | libmissing.NAType, left_mask: np.ndarray | None, right_mask: np.ndarray | None, ): @@ -37,7 +37,7 @@ def kleene_or( The result of the logical or, and the new mask. """ # To reduce the number of cases, we ensure that `left` & `left_mask` - # always come from an array, not a scalar. This is safe, since because + # always come from an array, not a scalar. This is safe, since # A | B == B | A if left_mask is None: return kleene_or(right, left, right_mask, left_mask) @@ -46,9 +46,7 @@ def kleene_or( raise_for_nan(right, method="or") - # error: Non-overlapping identity check (left operand type: - # "Union[bool, ndarray[Any, Any]]", right operand type: "NAType") - if right is libmissing.NA: # type: ignore[comparison-overlap] + if right is libmissing.NA: result = left.copy() else: result = left | right @@ -65,9 +63,7 @@ def kleene_or( else: if right is True: mask = np.zeros_like(left_mask) - # error: Non-overlapping identity check (left operand type: - # "Union[bool, ndarray[Any, Any]]", right operand type: "NAType") - elif right is libmissing.NA: # type: ignore[comparison-overlap] + elif right is libmissing.NA: mask = (~left & ~left_mask) | left_mask else: # False @@ -77,8 +73,8 @@ def kleene_or( def kleene_xor( - left: bool | np.ndarray, - right: bool | np.ndarray, + left: bool | np.ndarray | libmissing.NAType, + right: bool | np.ndarray | libmissing.NAType, left_mask: np.ndarray | None, right_mask: np.ndarray | None, ): @@ -103,23 +99,21 @@ def kleene_xor( result, mask: ndarray[bool] The result of the logical xor, and the new mask. """ + # To reduce the number of cases, we ensure that `left` & `left_mask` + # always come from an array, not a scalar. This is safe, since + # A ^ B == B ^ A if left_mask is None: return kleene_xor(right, left, right_mask, left_mask) + assert isinstance(left, np.ndarray) raise_for_nan(right, method="xor") - # error: Non-overlapping identity check (left operand type: - # "Union[bool, ndarray[Any, Any]]", right operand type: "NAType") - if right is libmissing.NA: # type: ignore[comparison-overlap] + if right is libmissing.NA: result = np.zeros_like(left) else: - # error: Incompatible types in assignment (expression has type - # "Union[bool, Any]", variable has type "ndarray") - result = left ^ right # type: ignore[assignment] + result = left ^ right if right_mask is None: - # error: Non-overlapping identity check (left operand type: - # "Union[bool, ndarray[Any, Any]]", right operand type: "NAType") - if right is libmissing.NA: # type: ignore[comparison-overlap] + if right is libmissing.NA: mask = np.ones_like(left_mask) else: mask = left_mask.copy() @@ -154,8 +148,8 @@ def kleene_and( The result of the logical xor, and the new mask. """ # To reduce the number of cases, we ensure that `left` & `left_mask` - # always come from an array, not a scalar. This is safe, since because - # A | B == B | A + # always come from an array, not a scalar. This is safe, since + # A & B == B & A if left_mask is None: return kleene_and(right, left, right_mask, left_mask) From 8830a419b7e56de12917a1da735d4070456de94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Wed, 10 Nov 2021 17:15:24 -0500 Subject: [PATCH 11/16] remove test typing for offset.pyi --- .../tseries/offsets/test_business_day.py | 4 +--- .../tseries/offsets/test_business_hour.py | 4 +--- .../tseries/offsets/test_business_month.py | 12 ++--------- .../tseries/offsets/test_business_quarter.py | 12 ++--------- .../tseries/offsets/test_business_year.py | 14 +++---------- .../offsets/test_custom_business_day.py | 2 -- .../offsets/test_custom_business_hour.py | 4 +--- .../offsets/test_custom_business_month.py | 11 ++-------- pandas/tests/tseries/offsets/test_month.py | 20 ++++--------------- pandas/tests/tseries/offsets/test_quarter.py | 4 +--- pandas/tests/tseries/offsets/test_week.py | 13 +++--------- pandas/tests/tseries/offsets/test_year.py | 12 ++--------- 12 files changed, 22 insertions(+), 90 deletions(-) diff --git a/pandas/tests/tseries/offsets/test_business_day.py b/pandas/tests/tseries/offsets/test_business_day.py index c7309bbe330bb..c40ae611687dd 100644 --- a/pandas/tests/tseries/offsets/test_business_day.py +++ b/pandas/tests/tseries/offsets/test_business_day.py @@ -1,8 +1,6 @@ """ Tests for offsets.BDay """ -from __future__ import annotations - from datetime import ( date, datetime, @@ -34,7 +32,7 @@ class TestBusinessDay(Base): - _offset: type[BDay] = BDay + _offset = BDay def setup_method(self, method): self.d = datetime(2008, 1, 1) diff --git a/pandas/tests/tseries/offsets/test_business_hour.py b/pandas/tests/tseries/offsets/test_business_hour.py index 7d75543ffeb1f..401bfe664a3a2 100644 --- a/pandas/tests/tseries/offsets/test_business_hour.py +++ b/pandas/tests/tseries/offsets/test_business_hour.py @@ -1,8 +1,6 @@ """ Tests for offsets.BusinessHour """ -from __future__ import annotations - from datetime import ( datetime, time as dt_time, @@ -32,7 +30,7 @@ class TestBusinessHour(Base): - _offset: type[BusinessHour] = BusinessHour + _offset = BusinessHour def setup_method(self, method): self.d = datetime(2014, 7, 1, 10, 00) diff --git a/pandas/tests/tseries/offsets/test_business_month.py b/pandas/tests/tseries/offsets/test_business_month.py index c99a060cfed9b..bb2049fd35489 100644 --- a/pandas/tests/tseries/offsets/test_business_month.py +++ b/pandas/tests/tseries/offsets/test_business_month.py @@ -3,14 +3,10 @@ - BMonthBegin - BMonthEnd """ -from __future__ import annotations - from datetime import datetime import pytest -from pandas._libs.tslibs.offsets import MonthOffset - import pandas as pd from pandas.tests.tseries.offsets.common import ( Base, @@ -47,11 +43,7 @@ def test_apply_index(cls, n): assert res2.iloc[-1] == ser.iloc[-1] + offset -class BaseMonthOffset(Base): - _offset: type[MonthOffset] = BMonthBegin - - -class TestBMonthBegin(BaseMonthOffset): +class TestBMonthBegin(Base): _offset = BMonthBegin def test_offsets_compare_equal(self): @@ -139,7 +131,7 @@ def test_is_on_offset(self, case): assert_is_on_offset(offset, dt, expected) -class TestBMonthEnd(BaseMonthOffset): +class TestBMonthEnd(Base): _offset = BMonthEnd def test_normalize(self): diff --git a/pandas/tests/tseries/offsets/test_business_quarter.py b/pandas/tests/tseries/offsets/test_business_quarter.py index 692f05f70738a..b928b47d30a0d 100644 --- a/pandas/tests/tseries/offsets/test_business_quarter.py +++ b/pandas/tests/tseries/offsets/test_business_quarter.py @@ -3,14 +3,10 @@ - BQuarterBegin - BQuarterEnd """ -from __future__ import annotations - from datetime import datetime import pytest -from pandas._libs.tslibs.offsets import QuarterOffset - from pandas.tests.tseries.offsets.common import ( Base, assert_is_on_offset, @@ -47,11 +43,7 @@ def test_on_offset(offset): assert res == slow_version -class BaseQuarter(Base): - _offset: type[QuarterOffset] = BQuarterBegin - - -class TestBQuarterBegin(BaseQuarter): +class TestBQuarterBegin(Base): _offset = BQuarterBegin def test_repr(self): @@ -176,7 +168,7 @@ def test_offset(self, case): assert_offset_equal(offset, base, expected) -class TestBQuarterEnd(BaseQuarter): +class TestBQuarterEnd(Base): _offset = BQuarterEnd def test_repr(self): diff --git a/pandas/tests/tseries/offsets/test_business_year.py b/pandas/tests/tseries/offsets/test_business_year.py index 7abf68d065d22..d531a586c5db2 100644 --- a/pandas/tests/tseries/offsets/test_business_year.py +++ b/pandas/tests/tseries/offsets/test_business_year.py @@ -3,14 +3,10 @@ - BYearBegin - BYearEnd """ -from __future__ import annotations - from datetime import datetime import pytest -from pandas._libs.tslibs.offsets import YearOffset - from pandas.tests.tseries.offsets.common import ( Base, assert_is_on_offset, @@ -23,11 +19,7 @@ ) -class BaseYear(Base): - _offset: type[YearOffset] = BYearBegin - - -class TestBYearBegin(BaseYear): +class TestBYearBegin(Base): _offset = BYearBegin def test_misspecified(self): @@ -100,7 +92,7 @@ def test_offset(self, case): assert_offset_equal(offset, base, expected) -class TestBYearEnd(BaseYear): +class TestBYearEnd(Base): _offset = BYearEnd offset_cases = [] @@ -173,7 +165,7 @@ def test_is_on_offset(self, case): assert_is_on_offset(offset, dt, expected) -class TestBYearEndLagged(BaseYear): +class TestBYearEndLagged(Base): _offset = BYearEnd def test_bad_month_fail(self): diff --git a/pandas/tests/tseries/offsets/test_custom_business_day.py b/pandas/tests/tseries/offsets/test_custom_business_day.py index cd700018b423b..3bbbaa891709f 100644 --- a/pandas/tests/tseries/offsets/test_custom_business_day.py +++ b/pandas/tests/tseries/offsets/test_custom_business_day.py @@ -1,8 +1,6 @@ """ Tests for offsets.CustomBusinessDay / CDay """ -from __future__ import annotations - from datetime import ( datetime, timedelta, diff --git a/pandas/tests/tseries/offsets/test_custom_business_hour.py b/pandas/tests/tseries/offsets/test_custom_business_hour.py index 398f294f6140c..dbc0ff4371fd9 100644 --- a/pandas/tests/tseries/offsets/test_custom_business_hour.py +++ b/pandas/tests/tseries/offsets/test_custom_business_hour.py @@ -1,8 +1,6 @@ """ Tests for offsets.CustomBusinessHour """ -from __future__ import annotations - from datetime import datetime import numpy as np @@ -25,7 +23,7 @@ class TestCustomBusinessHour(Base): - _offset: type[CustomBusinessHour] = CustomBusinessHour + _offset = CustomBusinessHour holidays = ["2014-06-27", datetime(2014, 6, 30), np.datetime64("2014-07-02")] def setup_method(self, method): diff --git a/pandas/tests/tseries/offsets/test_custom_business_month.py b/pandas/tests/tseries/offsets/test_custom_business_month.py index 22bf362b9f4eb..fb0f331fa3ad3 100644 --- a/pandas/tests/tseries/offsets/test_custom_business_month.py +++ b/pandas/tests/tseries/offsets/test_custom_business_month.py @@ -4,8 +4,6 @@ - CustomBusinessMonthBegin - CustomBusinessMonthEnd """ -from __future__ import annotations - from datetime import ( date, datetime, @@ -19,7 +17,6 @@ CBMonthBegin, CBMonthEnd, CDay, - _CustomBusinessMonth, ) from pandas import ( @@ -68,11 +65,7 @@ def test_copy(self): assert off == off.copy() -class BaseCustomBusinessMonth(CustomBusinessMonthBase, Base): - _offset: type[_CustomBusinessMonth] = CBMonthBegin - - -class TestCustomBusinessMonthBegin(BaseCustomBusinessMonth): +class TestCustomBusinessMonthBegin(CustomBusinessMonthBase, Base): _offset = CBMonthBegin def test_different_normalize_equals(self): @@ -262,7 +255,7 @@ def test_apply_with_extra_offset(self, case): assert_offset_equal(offset, base, expected) -class TestCustomBusinessMonthEnd(BaseCustomBusinessMonth): +class TestCustomBusinessMonthEnd(CustomBusinessMonthBase, Base): _offset = CBMonthEnd def test_different_normalize_equals(self): diff --git a/pandas/tests/tseries/offsets/test_month.py b/pandas/tests/tseries/offsets/test_month.py index 5059b7fe0001d..00b9d7e186a59 100644 --- a/pandas/tests/tseries/offsets/test_month.py +++ b/pandas/tests/tseries/offsets/test_month.py @@ -5,8 +5,6 @@ - MonthBegin - MonthEnd """ -from __future__ import annotations - from datetime import datetime import pytest @@ -15,10 +13,8 @@ from pandas._libs.tslibs.offsets import ( MonthBegin, MonthEnd, - MonthOffset, SemiMonthBegin, SemiMonthEnd, - SemiMonthOffset, ) from pandas import ( @@ -34,11 +30,7 @@ ) -class BaseSemiMonthOffset(Base): - _offset: type[SemiMonthOffset] = SemiMonthEnd - - -class TestSemiMonthEnd(BaseSemiMonthOffset): +class TestSemiMonthEnd(Base): _offset = SemiMonthEnd offset1 = _offset() offset2 = _offset(2) @@ -302,7 +294,7 @@ def test_vectorized_offset_addition(self, klass): tm.assert_equal(result2, exp) -class TestSemiMonthBegin(BaseSemiMonthOffset): +class TestSemiMonthBegin(Base): _offset = SemiMonthBegin offset1 = _offset() offset2 = _offset(2) @@ -542,11 +534,7 @@ def test_vectorized_offset_addition(self, klass): tm.assert_equal(result2, exp) -class BaseMonthOffset(Base): - _offset: type[MonthOffset] = MonthBegin - - -class TestMonthBegin(BaseMonthOffset): +class TestMonthBegin(Base): _offset = MonthBegin offset_cases = [] @@ -611,7 +599,7 @@ def test_offset(self, case): assert_offset_equal(offset, base, expected) -class TestMonthEnd(BaseMonthOffset): +class TestMonthEnd(Base): _offset = MonthEnd def test_day_of_month(self): diff --git a/pandas/tests/tseries/offsets/test_quarter.py b/pandas/tests/tseries/offsets/test_quarter.py index 9063b71cdece4..e076fb9f4d53b 100644 --- a/pandas/tests/tseries/offsets/test_quarter.py +++ b/pandas/tests/tseries/offsets/test_quarter.py @@ -3,8 +3,6 @@ - QuarterBegin - QuarterEnd """ -from __future__ import annotations - from datetime import datetime import pytest @@ -154,7 +152,7 @@ def test_offset(self, case): class TestQuarterEnd(Base): - _offset: type[QuarterEnd] = QuarterEnd + _offset = QuarterEnd def test_repr(self): expected = "" diff --git a/pandas/tests/tseries/offsets/test_week.py b/pandas/tests/tseries/offsets/test_week.py index 08072228ac4f4..be574fd963eff 100644 --- a/pandas/tests/tseries/offsets/test_week.py +++ b/pandas/tests/tseries/offsets/test_week.py @@ -4,8 +4,6 @@ - WeekOfMonth - LastWeekOfMonth """ -from __future__ import annotations - from datetime import ( datetime, timedelta, @@ -19,7 +17,6 @@ LastWeekOfMonth, Week, WeekOfMonth, - WeekOfMonthMixin, ) from pandas.tests.tseries.offsets.common import ( @@ -31,7 +28,7 @@ class TestWeek(Base): - _offset: type[Week] = Week + _offset = Week d = Timestamp(datetime(2008, 1, 2)) offset1 = _offset() offset2 = _offset(2) @@ -153,11 +150,7 @@ def test_week_add_invalid(self): offset + other -class BaseWeekOfMonthMixin(Base): - _offset: type[WeekOfMonthMixin] = WeekOfMonth - - -class TestWeekOfMonth(BaseWeekOfMonthMixin): +class TestWeekOfMonth(Base): _offset = WeekOfMonth offset1 = _offset() offset2 = _offset(2) @@ -273,7 +266,7 @@ def test_is_on_offset_nanoseconds(self, n, week, date, tz): assert fast == slow -class TestLastWeekOfMonth(BaseWeekOfMonthMixin): +class TestLastWeekOfMonth(Base): _offset = LastWeekOfMonth offset1 = _offset() offset2 = _offset(2) diff --git a/pandas/tests/tseries/offsets/test_year.py b/pandas/tests/tseries/offsets/test_year.py index 4f194209ed8ef..85994adb6f19d 100644 --- a/pandas/tests/tseries/offsets/test_year.py +++ b/pandas/tests/tseries/offsets/test_year.py @@ -3,14 +3,10 @@ - YearBegin - YearEnd """ -from __future__ import annotations - from datetime import datetime import pytest -from pandas._libs.tslibs.offsets import YearOffset - from pandas.tests.tseries.offsets.common import ( Base, assert_is_on_offset, @@ -23,11 +19,7 @@ ) -class BaseYear(Base): - _offset: type[YearOffset] = YearBegin - - -class TestYearBegin(BaseYear): +class TestYearBegin(Base): _offset = YearBegin def test_misspecified(self): @@ -181,7 +173,7 @@ def test_is_on_offset(self, case): assert_is_on_offset(offset, dt, expected) -class TestYearEnd(BaseYear): +class TestYearEnd(Base): _offset = YearEnd def test_misspecified(self): From fac9933f9576035bc168ba251ea98535b650dceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Wed, 10 Nov 2021 17:37:25 -0500 Subject: [PATCH 12/16] TypeError and test for it --- pandas/core/ops/mask_ops.py | 7 +++++++ pandas/tests/arrays/boolean/test_logical.py | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/pandas/core/ops/mask_ops.py b/pandas/core/ops/mask_ops.py index 2c72b3323e41e..72ebcef0543c1 100644 --- a/pandas/core/ops/mask_ops.py +++ b/pandas/core/ops/mask_ops.py @@ -42,6 +42,8 @@ def kleene_or( if left_mask is None: return kleene_or(right, left, right_mask, left_mask) + if not isinstance(left, np.ndarray): + raise TypeError("Either `left` or `right` need to be a np.ndarray.") assert isinstance(left, np.ndarray) raise_for_nan(right, method="or") @@ -105,7 +107,10 @@ def kleene_xor( if left_mask is None: return kleene_xor(right, left, right_mask, left_mask) + if not isinstance(left, np.ndarray): + raise TypeError("Either `left` or `right` need to be a np.ndarray.") assert isinstance(left, np.ndarray) + raise_for_nan(right, method="xor") if right is libmissing.NA: result = np.zeros_like(left) @@ -153,6 +158,8 @@ def kleene_and( if left_mask is None: return kleene_and(right, left, right_mask, left_mask) + if not isinstance(left, np.ndarray): + raise TypeError("Either `left` or `right` need to be a np.ndarray.") assert isinstance(left, np.ndarray) raise_for_nan(right, method="and") diff --git a/pandas/tests/arrays/boolean/test_logical.py b/pandas/tests/arrays/boolean/test_logical.py index 938fa8f1a5d6a..17d85d218d07e 100644 --- a/pandas/tests/arrays/boolean/test_logical.py +++ b/pandas/tests/arrays/boolean/test_logical.py @@ -6,6 +6,11 @@ import pandas as pd import pandas._testing as tm from pandas.arrays import BooleanArray +from pandas.core.ops.mask_ops import ( + kleene_and, + kleene_or, + kleene_xor, +) from pandas.tests.extension.base import BaseOpsUtil @@ -239,3 +244,11 @@ def test_no_masked_assumptions(self, other, all_logical_operators): result = getattr(a, all_logical_operators)(other) expected = getattr(b, all_logical_operators)(other) tm.assert_extension_array_equal(result, expected) + + +@pytest.mark.parametrize("operation", [kleene_or, kleene_xor, kleene_and]) +def test_error_both_scalar(operation): + msg = "Either `left` or `right` need to be a np.ndarray." + with pytest.raises(TypeError, match=msg): + # masks need to be non-None, otherwise it ends up in an infinite recursion + operation(True, True, np.zeros(1), np.zeros(1)) From c3b0d283de9bf164a9586786a1505ba0bc8c0e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 14 Nov 2021 14:24:43 -0500 Subject: [PATCH 13/16] remove pyx-only functions --- pandas/_libs/tslibs/ccalendar.pyi | 2 -- pandas/_libs/tslibs/nattype.pyi | 1 - pandas/_libs/tslibs/period.pyi | 4 ---- 3 files changed, 7 deletions(-) diff --git a/pandas/_libs/tslibs/ccalendar.pyi b/pandas/_libs/tslibs/ccalendar.pyi index 5d5b935ffa54b..993f18a61d74a 100644 --- a/pandas/_libs/tslibs/ccalendar.pyi +++ b/pandas/_libs/tslibs/ccalendar.pyi @@ -8,7 +8,5 @@ def get_firstbday(year: int, month: int) -> int: ... def get_lastbday(year: int, month: int) -> int: ... def get_day_of_year(year: int, month: int, day: int) -> int: ... def get_iso_calendar(year: int, month: int, day: int) -> tuple[int, int, int]: ... -def is_leapyear(year: int) -> bool: ... def get_week_of_year(year: int, month: int, day: int) -> int: ... def get_days_in_month(year: int, month: int) -> int: ... -def dayofweek(y: int, m: int, d: int) -> int: ... diff --git a/pandas/_libs/tslibs/nattype.pyi b/pandas/_libs/tslibs/nattype.pyi index dc1d19219c3c0..a7ee9a70342d4 100644 --- a/pandas/_libs/tslibs/nattype.pyi +++ b/pandas/_libs/tslibs/nattype.pyi @@ -13,7 +13,6 @@ iNaT: int nat_strings: set[str] def is_null_datetimelike(val: object, inat_is_null: bool = ...) -> bool: ... -def checknull_with_nat(val: object) -> bool: ... class NaTType(datetime): value: np.int64 diff --git a/pandas/_libs/tslibs/period.pyi b/pandas/_libs/tslibs/period.pyi index c1c217aed230a..4f7505fd7e792 100644 --- a/pandas/_libs/tslibs/period.pyi +++ b/pandas/_libs/tslibs/period.pyi @@ -1,4 +1,3 @@ -from datetime import datetime from typing import Literal import numpy as np @@ -15,9 +14,6 @@ from pandas._typing import ( INVALID_FREQ_ERR_MSG: str DIFFERENT_FREQ: str -def is_period_object(obj: object) -> bool: ... -def get_period_ordinal(dts: datetime, freq: int) -> int: ... - class IncompatibleFrequency(ValueError): ... def periodarr_to_dt64arr( From 113ee898e382501ebbdb318f4b361cb2495b2522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 14 Nov 2021 14:40:49 -0500 Subject: [PATCH 14/16] other comments --- pandas/_libs/missing.pyi | 3 +-- pandas/core/common.py | 3 +-- pandas/core/dtypes/missing.py | 7 ------- pandas/core/ops/mask_ops.py | 3 --- pandas/tests/arrays/boolean/test_logical.py | 2 +- 5 files changed, 3 insertions(+), 15 deletions(-) diff --git a/pandas/_libs/missing.pyi b/pandas/_libs/missing.pyi index 1a5b7ce7ad6d2..d832010208ea2 100644 --- a/pandas/_libs/missing.pyi +++ b/pandas/_libs/missing.pyi @@ -1,6 +1,5 @@ import numpy as np - -from pandas._typing import npt +from numpy import typing as npt class NAType: ... diff --git a/pandas/core/common.py b/pandas/core/common.py index 53526c41c3cf3..590296c4b12f5 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -31,7 +31,6 @@ from pandas._typing import ( AnyArrayLike, ArrayLike, - IndexLabel, NpDtype, RandomState, Scalar, @@ -516,7 +515,7 @@ def f(x): def convert_to_list_like( - values: Scalar | IndexLabel | AnyArrayLike, + values: Scalar | Iterable | AnyArrayLike, ) -> list | AnyArrayLike: """ Convert list-like or scalar input to list-like. List, numpy and pandas array-like diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index 94c17c5572d43..47949334df021 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -1,11 +1,8 @@ """ missing types & inference """ -from __future__ import annotations - from decimal import Decimal from functools import partial -from typing import TYPE_CHECKING import numpy as np @@ -54,9 +51,6 @@ ) from pandas.core.dtypes.inference import is_list_like -if TYPE_CHECKING: - from pandas.core.arrays.base import ExtensionArraySupportsAnyAll - isposinf_scalar = libmissing.isposinf_scalar isneginf_scalar = libmissing.isneginf_scalar @@ -241,7 +235,6 @@ def _isna_array(values: ArrayLike, inf_as_na: bool = False): Array of boolean values denoting the NA status of each element. """ dtype = values.dtype - result: np.ndarray | ExtensionArraySupportsAnyAll if not isinstance(values, np.ndarray): # i.e. ExtensionArray diff --git a/pandas/core/ops/mask_ops.py b/pandas/core/ops/mask_ops.py index 72ebcef0543c1..57bacba0d4bee 100644 --- a/pandas/core/ops/mask_ops.py +++ b/pandas/core/ops/mask_ops.py @@ -44,7 +44,6 @@ def kleene_or( if not isinstance(left, np.ndarray): raise TypeError("Either `left` or `right` need to be a np.ndarray.") - assert isinstance(left, np.ndarray) raise_for_nan(right, method="or") @@ -109,7 +108,6 @@ def kleene_xor( if not isinstance(left, np.ndarray): raise TypeError("Either `left` or `right` need to be a np.ndarray.") - assert isinstance(left, np.ndarray) raise_for_nan(right, method="xor") if right is libmissing.NA: @@ -160,7 +158,6 @@ def kleene_and( if not isinstance(left, np.ndarray): raise TypeError("Either `left` or `right` need to be a np.ndarray.") - assert isinstance(left, np.ndarray) raise_for_nan(right, method="and") if right is libmissing.NA: diff --git a/pandas/tests/arrays/boolean/test_logical.py b/pandas/tests/arrays/boolean/test_logical.py index 17d85d218d07e..b4cca635fa238 100644 --- a/pandas/tests/arrays/boolean/test_logical.py +++ b/pandas/tests/arrays/boolean/test_logical.py @@ -248,7 +248,7 @@ def test_no_masked_assumptions(self, other, all_logical_operators): @pytest.mark.parametrize("operation", [kleene_or, kleene_xor, kleene_and]) def test_error_both_scalar(operation): - msg = "Either `left` or `right` need to be a np.ndarray." + msg = r"Either `left` or `right` need to be a np\.ndarray." with pytest.raises(TypeError, match=msg): # masks need to be non-None, otherwise it ends up in an infinite recursion operation(True, True, np.zeros(1), np.zeros(1)) From 23ce14abcb63d274ce5c8925adcf524915240fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 28 Nov 2021 17:23:10 -0500 Subject: [PATCH 15/16] inf_as_na --- pandas/_libs/missing.pyi | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pandas/_libs/missing.pyi b/pandas/_libs/missing.pyi index d832010208ea2..30ade3d617c87 100644 --- a/pandas/_libs/missing.pyi +++ b/pandas/_libs/missing.pyi @@ -10,7 +10,5 @@ def is_matching_na( ) -> bool: ... def isposinf_scalar(val: object) -> bool: ... def isneginf_scalar(val: object) -> bool: ... -def checknull(val: object) -> bool: ... -def checknull_old(val: object) -> bool: ... -def isnaobj(arr: np.ndarray) -> npt.NDArray[np.bool_]: ... -def isnaobj_old(arr: np.ndarray) -> npt.NDArray[np.bool_]: ... +def checknull(val: object, inf_as_na: bool = ...) -> bool: ... +def isnaobj(arr: np.ndarray, inf_as_na: bool = ...) -> npt.NDArray[np.bool_]: ... From aa080428469d6bc39bc72d4db9d88a3a22aa80b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sun, 12 Dec 2021 14:23:37 -0500 Subject: [PATCH 16/16] is_numeric_na --- pandas/_libs/missing.pyi | 1 + pandas/core/dtypes/missing.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/_libs/missing.pyi b/pandas/_libs/missing.pyi index 30ade3d617c87..1177e82906190 100644 --- a/pandas/_libs/missing.pyi +++ b/pandas/_libs/missing.pyi @@ -12,3 +12,4 @@ def isposinf_scalar(val: object) -> bool: ... def isneginf_scalar(val: object) -> bool: ... def checknull(val: object, inf_as_na: bool = ...) -> bool: ... def isnaobj(arr: np.ndarray, inf_as_na: bool = ...) -> npt.NDArray[np.bool_]: ... +def is_numeric_na(values: np.ndarray) -> npt.NDArray[np.bool_]: ... diff --git a/pandas/core/dtypes/missing.py b/pandas/core/dtypes/missing.py index 47949334df021..4e3306e84c1a1 100644 --- a/pandas/core/dtypes/missing.py +++ b/pandas/core/dtypes/missing.py @@ -241,7 +241,10 @@ def _isna_array(values: ArrayLike, inf_as_na: bool = False): if inf_as_na and is_categorical_dtype(dtype): result = libmissing.isnaobj(values.to_numpy(), inf_as_na=inf_as_na) else: - result = values.isna() + # error: Incompatible types in assignment (expression has type + # "Union[ndarray[Any, Any], ExtensionArraySupportsAnyAll]", variable has + # type "ndarray[Any, dtype[bool_]]") + result = values.isna() # type: ignore[assignment] elif is_string_or_object_np_dtype(values.dtype): result = _isna_string_dtype(values, inf_as_na=inf_as_na) elif needs_i8_conversion(dtype):