From d157fa1cc3e2207936424937e8ab0271baf01546 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 10:07:10 +0100 Subject: [PATCH 01/18] wip --- pandas-stubs/_libs/missing.pyi | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index 2c9485299..40d845fd3 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -1,3 +1,14 @@ +from typing import ( + Any, + overload, +) + +import numpy as np +import numpy.typing as npt +from pandas import ( + Index, + Series, +) from typing_extensions import Self class NAType: @@ -8,8 +19,26 @@ class NAType: def __reduce__(self) -> str: ... def __add__(self, other) -> NAType: ... def __radd__(self, other) -> NAType: ... - def __sub__(self, other) -> NAType: ... - def __rsub__(self, other) -> NAType: ... + @overload + def __sub__( + self, other: Series, / + ) -> Series[type[object]]: ... # pyright: ignore[reportOverlappingOverload] + @overload + def __sub__(self, other: Index, /) -> Index[type[object]]: ... + @overload + def __sub__(self, other: npt.NDArray[Any], /) -> npt.NDArray[np.object_]: ... + @overload + def __sub__(self, other: Any, /) -> NAType: ... + @overload + def __rsub__( + self, other: Series, / + ) -> Series[type[object]]: ... # pyright: ignore[reportOverlappingOverload] + @overload + def __rsub__(self, other: Index, /) -> Index[type[object]]: ... + @overload + def __rsub__(self, other: npt.NDArray[Any], /) -> npt.NDArray[np.object_]: ... + @overload + def __rsub__(self, other: Any, /) -> NAType: ... def __mul__(self, other) -> NAType: ... def __rmul__(self, other) -> NAType: ... def __matmul__(self, other) -> NAType: ... From b305640e5329a9928225b7deb526608e21ff3840 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:09:38 +0100 Subject: [PATCH 02/18] maybe fix the overloads --- pandas-stubs/_libs/missing.pyi | 357 ++++++++++++++++++++++++++++----- 1 file changed, 302 insertions(+), 55 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index 40d845fd3..ac51c46d2 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -1,9 +1,10 @@ from typing import ( Any, + Callable, + Literal, overload, ) -import numpy as np import numpy.typing as npt from pandas import ( Index, @@ -12,64 +13,310 @@ from pandas import ( from typing_extensions import Self class NAType: - def __new__(cls, *args, **kwargs) -> Self: ... + def __new__(cls, *args: Any, **kwargs: Any) -> Self: ... def __format__(self, format_spec: str) -> str: ... def __bool__(self) -> None: ... def __hash__(self) -> int: ... def __reduce__(self) -> str: ... - def __add__(self, other) -> NAType: ... - def __radd__(self, other) -> NAType: ... - @overload - def __sub__( - self, other: Series, / - ) -> Series[type[object]]: ... # pyright: ignore[reportOverlappingOverload] - @overload - def __sub__(self, other: Index, /) -> Index[type[object]]: ... - @overload - def __sub__(self, other: npt.NDArray[Any], /) -> npt.NDArray[np.object_]: ... - @overload - def __sub__(self, other: Any, /) -> NAType: ... - @overload - def __rsub__( - self, other: Series, / - ) -> Series[type[object]]: ... # pyright: ignore[reportOverlappingOverload] - @overload - def __rsub__(self, other: Index, /) -> Index[type[object]]: ... - @overload - def __rsub__(self, other: npt.NDArray[Any], /) -> npt.NDArray[np.object_]: ... - @overload - def __rsub__(self, other: Any, /) -> NAType: ... - def __mul__(self, other) -> NAType: ... - def __rmul__(self, other) -> NAType: ... - def __matmul__(self, other) -> NAType: ... - def __rmatmul__(self, other) -> NAType: ... - def __truediv__(self, other) -> NAType: ... - def __rtruediv__(self, other) -> NAType: ... - def __floordiv__(self, other) -> NAType: ... - def __rfloordiv__(self, other) -> NAType: ... - def __mod__(self, other) -> NAType: ... - def __rmod__(self, other) -> NAType: ... - def __divmod__(self, other) -> NAType: ... - def __rdivmod__(self, other) -> NAType: ... - def __eq__(self, other) -> bool: ... - def __ne__(self, other) -> bool: ... - def __le__(self, other) -> bool: ... - def __lt__(self, other) -> bool: ... - def __gt__(self, other) -> bool: ... - def __ge__(self, other) -> bool: ... - def __neg__(self, other) -> NAType: ... - def __pos__(self, other) -> NAType: ... - def __abs__(self, other) -> NAType: ... - def __invert__(self, other) -> NAType: ... - def __pow__(self, other) -> NAType: ... - def __rpow__(self, other) -> NAType: ... - def __and__(self, other) -> NAType | None: ... - __rand__ = __and__ - def __or__(self, other) -> bool | NAType: ... - __ror__ = __or__ - def __xor__(self, other) -> NAType: ... - __rxor__ = __xor__ + @overload + def __add__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __add__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __add__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __add__(self, other: object, /) -> NAType: ... + @overload + def __radd__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __radd__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __radd__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __radd__(self, other: object, /) -> NAType: ... + @overload + def __sub__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __sub__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __sub__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __sub__(self, other: object, /) -> NAType: ... + @overload + def __rsub__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __rsub__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rsub__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __rsub__(self, other: object, /) -> NAType: ... + @overload + def __mul__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __mul__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __mul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __mul__(self, other: object, /) -> NAType: ... + @overload + def __rmul__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __rmul__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rmul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __rmul__(self, other: object, /) -> NAType: ... + @overload + def __matmul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + @overload + def __matmul__(self, other: object, /) -> NAType: ... + @overload + def __rmatmul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + @overload + def __rmatmul__(self, other: object, /) -> NAType: ... + @overload + def __truediv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __truediv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __truediv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __truediv__(self, other: object, /) -> NAType: ... + @overload + def __rtruediv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __rtruediv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rtruediv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __rtruediv__(self, other: object, /) -> NAType: ... + @overload + def __floordiv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __floordiv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __floordiv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __floordiv__(self, other: object, /) -> NAType: ... + @overload + def __rfloordiv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __rfloordiv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rfloordiv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __rfloordiv__(self, other: object, /) -> NAType: ... + @overload + def __mod__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __mod__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __mod__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __mod__(self, other: object, /) -> NAType: ... + @overload + def __rmod__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __rmod__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rmod__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __rmod__(self, other: object, /) -> NAType: ... + @overload + def __divmod__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> tuple[Series, Series]: ... + @overload + def __divmod__(self, other: Index, /) -> tuple[Index, Index]: ... # type: ignore[overload-overlap] + @overload + def __divmod__(self, other: npt.NDArray, /) -> tuple[npt.NDArray, npt.NDArray]: ... # type: ignore[overload-overlap] + @overload + def __divmod__(self, other: object, /) -> tuple[NAType, NAType]: ... + @overload + def __rdivmod__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> tuple[Series, Series]: ... + @overload + def __rdivmod__(self, other: Index, /) -> tuple[Index, Index]: ... # type: ignore[overload-overlap] + @overload + def __rdivmod__(self, other: npt.NDArray, /) -> tuple[npt.NDArray, npt.NDArray]: ... # type: ignore[overload-overlap] + @overload + def __rdivmod__(self, other: object, /) -> tuple[NAType, NAType]: ... + @overload # type: ignore[override] + def __eq__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __eq__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __eq__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __eq__( + self, other: object, / + ) -> NAType: ... # pyright: ignore[reportIncompatibleMethodOverride] + @overload # type: ignore[override] + def __ne__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __ne__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __ne__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __ne__( + self, other: object, / + ) -> NAType: ... # pyright: ignore[reportIncompatibleMethodOverride] + @overload + def __le__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __le__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __le__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __le__(self, other: object, /) -> NAType: ... + @overload + def __lt__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __lt__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __lt__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __lt__(self, other: object, /) -> NAType: ... + @overload + def __gt__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __gt__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __gt__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __gt__(self, other: object, /) -> NAType: ... + @overload + def __ge__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __ge__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __ge__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __ge__(self, other: object, /) -> NAType: ... + def __neg__(self) -> NAType: ... + def __pos__(self) -> NAType: ... + def __abs__(self) -> NAType: ... + def __invert__(self) -> NAType: ... + @overload + def __pow__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __pow__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __pow__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __pow__(self, other: object, /) -> NAType: ... + @overload + def __rpow__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __rpow__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rpow__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __rpow__(self, other: object, /) -> NAType: ... + @overload + def __and__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __and__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __and__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __and__(self, other: object, /) -> Literal[False] | NAType: ... + @overload + def __rand__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __rand__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rand__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __rand__(self, other: object, /) -> Literal[False] | NAType: ... + @overload + def __or__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __or__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __or__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __or__(self, other: object, /) -> Literal[True] | NAType: ... + @overload + def __ror__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __ror__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __ror__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __ror__(self, other: object, /) -> Literal[True] | NAType: ... + @overload + def __xor__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __xor__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __xor__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __xor__(self, other: object, /) -> NAType: ... + @overload + def __rxor__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] + self, other: Series, / + ) -> Series: ... + @overload + def __rxor__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + @overload + def __rxor__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + @overload + def __rxor__(self, other: object, /) -> NAType: ... __array_priority__: int - def __array_ufunc__(self, ufunc, method, *inputs, **kwargs): ... + def __array_ufunc__( + self, ufunc: Callable[..., Any], method: str, *inputs: Any, **kwargs: Any + ) -> Any: ... NA: NAType = ... From 1e15cb92f57359985888f514f6da3632912f5a1c Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:23:00 +0100 Subject: [PATCH 03/18] wip tests --- pandas-stubs/_libs/missing.pyi | 8 +-- tests/test_natype.py | 109 +++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 tests/test_natype.py diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index ac51c46d2..7203cf4e3 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -175,9 +175,9 @@ class NAType: @overload def __eq__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload - def __eq__( + def __eq__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: object, / - ) -> NAType: ... # pyright: ignore[reportIncompatibleMethodOverride] + ) -> NAType: ... @overload # type: ignore[override] def __ne__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / @@ -187,9 +187,9 @@ class NAType: @overload def __ne__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload - def __ne__( + def __ne__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: object, / - ) -> NAType: ... # pyright: ignore[reportIncompatibleMethodOverride] + ) -> NAType: ... @overload def __le__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / diff --git a/tests/test_natype.py b/tests/test_natype.py new file mode 100644 index 000000000..884b1bbc5 --- /dev/null +++ b/tests/test_natype.py @@ -0,0 +1,109 @@ +import numpy as np +import numpy.typing as npt +import pandas as pd +from pandas.api.typing import NAType +from typing_extensions import assert_type + +from tests import check + + +def test_arithmetic() -> None: + na = pd.NA + s_int = pd.Series([1, 2, 3]) + idx_int = pd.Index([1, 2, 3]) + arr_int = np.array([1, 2, 3]) + + # __add__ + check(assert_type(na + s_int, pd.Series), pd.Series) + check(assert_type(na + idx_int, pd.Index), pd.Index) + check(assert_type(na + arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na + 1, NAType), NAType) + + # __sub__ + check(assert_type(na - s_int, pd.Series), pd.Series) + check(assert_type(na - idx_int, pd.Index), pd.Index) + check(assert_type(na - arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na - 1, NAType), NAType) + + # __mul__ + check(assert_type(na * s_int, pd.Series), pd.Series) + check(assert_type(na * idx_int, pd.Index), pd.Index) + check(assert_type(na * arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na * 1, NAType), NAType) + + # __floordiv__ + check(assert_type(na // s_int, pd.Series), pd.Series) + check(assert_type(na // idx_int, pd.Index), pd.Index) + check(assert_type(na // arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na // 1, NAType), NAType) + + # __truediv__ + check(assert_type(na / s_int, pd.Series), pd.Series) + check(assert_type(na / idx_int, pd.Index), pd.Index) + check(assert_type(na / arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na / 1, NAType), NAType) + + # __mod__ + check(assert_type(na % s_int, pd.Series), pd.Series) + check(assert_type(na % idx_int, pd.Index), pd.Index) + check(assert_type(na % arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na % 1, NAType), NAType) + + # __eq__ + check(assert_type(na == s_int, pd.Series), pd.Series) + check(assert_type(na == idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na == arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na == 1, NAType), NAType) + + # __ne__ + check(assert_type(na != s_int, pd.Series), pd.Series) + check(assert_type(na != idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na != arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na != 1, NAType), NAType) + + # __le__ + check(assert_type(na <= s_int, pd.Series), pd.Series) + check(assert_type(na <= idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na <= arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na <= 1, NAType), NAType) + + # __lt__ + check(assert_type(na < s_int, pd.Series), pd.Series) + check(assert_type(na < idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na < arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na < 1, NAType), NAType) + + # __ge__ + check(assert_type(na >= s_int, pd.Series), pd.Series) + check(assert_type(na >= idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na >= arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na >= 1, NAType), NAType) + + # __gt__ + check(assert_type(na > s_int, pd.Series), pd.Series) + check(assert_type(na > idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na > arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na > 1, NAType), NAType) + + # __pow__ + check(assert_type(na**s_int, pd.Series), pd.Series) + check(assert_type(na**idx_int, pd.Index), pd.Index) + check(assert_type(na**arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na**2, NAType), NAType) + + # __and__ + check(assert_type(na & s_int, pd.Series), pd.Series) + check(assert_type(na & idx_int, pd.Index), pd.Index) + check(assert_type(na & arr_int, npt.NDArray), npt.NDArray) + # check(assert_type(na & True, NAType), NAType) + + # __or__ + check(assert_type(na | s_int, pd.Series), pd.Series) + check(assert_type(na | idx_int, pd.Index), pd.Index) + check(assert_type(na | arr_int, npt.NDArray), npt.NDArray) + # check(assert_type(na | True, NAType), NAType) + + # __xor__ + check(assert_type(na ^ s_int, pd.Series), pd.Series) + check(assert_type(na ^ idx_int, pd.Index), pd.Index) + check(assert_type(na ^ arr_int, npt.NDArray), npt.NDArray) From 517c7d4d57cd82dd06905076209a7351b8e98e7a Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:30:17 +0100 Subject: [PATCH 04/18] fixup test --- pandas-stubs/_libs/missing.pyi | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index 7203cf4e3..cbb40ac20 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -171,7 +171,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __eq__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __eq__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload def __eq__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -183,7 +183,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __ne__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __ne__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload def __ne__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -195,7 +195,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __le__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __le__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload def __le__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -205,7 +205,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __lt__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __lt__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload def __lt__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -215,7 +215,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __gt__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __gt__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload def __gt__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -225,7 +225,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __ge__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __ge__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload def __ge__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload From c54fe6346fc62f20bec83f05489ae1cbc00dcc40 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:53:49 +0100 Subject: [PATCH 05/18] appease mypy --- tests/test_natype.py | 129 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 17 deletions(-) diff --git a/tests/test_natype.py b/tests/test_natype.py index 884b1bbc5..e07d85cd6 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -1,3 +1,5 @@ +from typing import Any + import numpy as np import numpy.typing as npt import pandas as pd @@ -11,99 +13,192 @@ def test_arithmetic() -> None: na = pd.NA s_int = pd.Series([1, 2, 3]) idx_int = pd.Index([1, 2, 3]) - arr_int = np.array([1, 2, 3]) + arr_int: npt.NDArray[Any] = np.array([1, 2, 3]) # __add__ check(assert_type(na + s_int, pd.Series), pd.Series) check(assert_type(na + idx_int, pd.Index), pd.Index) - check(assert_type(na + arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na + arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na + 1, NAType), NAType) + # __radd__ + check(assert_type(s_int + na, pd.Series), pd.Series) + # https://github.com/pandas-dev/pandas-stubs/issues/1347 + check(assert_type(idx_int + na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(arr_int + na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(1 + na, NAType), NAType) + # __sub__ check(assert_type(na - s_int, pd.Series), pd.Series) check(assert_type(na - idx_int, pd.Index), pd.Index) - check(assert_type(na - arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na - arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na - 1, NAType), NAType) + # __rsub__ + check(assert_type(s_int - na, pd.Series), pd.Series) + check(assert_type(idx_int - na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(arr_int - na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(1 - na, NAType), NAType) + # __mul__ check(assert_type(na * s_int, pd.Series), pd.Series) check(assert_type(na * idx_int, pd.Index), pd.Index) - check(assert_type(na * arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na * arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na * 1, NAType), NAType) + # __rmul__ + check(assert_type(s_int * na, pd.Series), pd.Series) + check(assert_type(idx_int * na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(arr_int * na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(1 * na, NAType), NAType) + # __floordiv__ check(assert_type(na // s_int, pd.Series), pd.Series) check(assert_type(na // idx_int, pd.Index), pd.Index) - check(assert_type(na // arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na // arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na // 1, NAType), NAType) + # __rfloordiv__ + # check(assert_type(/ s_int/na, pd.Series), pd.Series) + # check(assert_type(/ idx_int/na, pd.Index), pd.Index) + # check(assert_type(/ arr_int/na, npt.NDArray), npt.NDArray) + # check(assert_type(/ 1/na, NAType), NAType) + # __truediv__ check(assert_type(na / s_int, pd.Series), pd.Series) check(assert_type(na / idx_int, pd.Index), pd.Index) - check(assert_type(na / arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na / arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na / 1, NAType), NAType) + # __rtruediv__ + check(assert_type(s_int / na, pd.Series), pd.Series) + check(assert_type(idx_int / na, pd.Index), pd.Index) + check(assert_type(arr_int / na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(1 / na, NAType), NAType) + # __mod__ check(assert_type(na % s_int, pd.Series), pd.Series) check(assert_type(na % idx_int, pd.Index), pd.Index) - check(assert_type(na % arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na % arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na % 1, NAType), NAType) + # __rmod__ + check(assert_type(s_int % na, pd.Series), pd.Series) + check(assert_type(idx_int % na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(arr_int % na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(1 % na, NAType), NAType) + # __eq__ check(assert_type(na == s_int, pd.Series), pd.Series) check(assert_type(na == idx_int, npt.NDArray), npt.NDArray) - check(assert_type(na == arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na == arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na == 1, NAType), NAType) + # __req__ + # check(assert_type(= s_int=na, pd.Series), pd.Series) + # check(assert_type(= idx_int=na, npt.NDArray), npt.NDArray) + # check(assert_type(= arr_int=na, npt.NDArray), npt.NDArray) + # check(assert_type(= 1=na, NAType), NAType) + # __ne__ check(assert_type(na != s_int, pd.Series), pd.Series) check(assert_type(na != idx_int, npt.NDArray), npt.NDArray) - check(assert_type(na != arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na != arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na != 1, NAType), NAType) + # __rne__ + # check(assert_type(= s_int!na, pd.Series), pd.Series) + # check(assert_type(= idx_int!na, npt.NDArray), npt.NDArray) + # check(assert_type(= arr_int!na, npt.NDArray), npt.NDArray) + # check(assert_type(= 1!na, NAType), NAType) + # __le__ check(assert_type(na <= s_int, pd.Series), pd.Series) check(assert_type(na <= idx_int, npt.NDArray), npt.NDArray) - check(assert_type(na <= arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na <= arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na <= 1, NAType), NAType) + # __rle__ + # check(assert_type(= s_int= s_int, pd.Series), pd.Series) check(assert_type(na >= idx_int, npt.NDArray), npt.NDArray) - check(assert_type(na >= arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na >= arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na >= 1, NAType), NAType) + # __rge__ + # check(assert_type(= s_int>na, pd.Series), pd.Series) + # check(assert_type(= idx_int>na, npt.NDArray), npt.NDArray) + # check(assert_type(= arr_int>na, npt.NDArray), npt.NDArray) + # check(assert_type(= 1>na, NAType), NAType) + # __gt__ check(assert_type(na > s_int, pd.Series), pd.Series) check(assert_type(na > idx_int, npt.NDArray), npt.NDArray) - check(assert_type(na > arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na > arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na > 1, NAType), NAType) + # __rgt__ + check(assert_type(s_int > na, pd.Series), pd.Series) + check(assert_type(idx_int > na, npt.NDArray), npt.NDArray) + check(assert_type(arr_int > na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(1 > na, NAType), NAType) + # __pow__ check(assert_type(na**s_int, pd.Series), pd.Series) check(assert_type(na**idx_int, pd.Index), pd.Index) - check(assert_type(na**arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na**arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na**2, NAType), NAType) + # __rpow__ + check(assert_type(s_int * na, pd.Series), pd.Series) + check(assert_type(idx_int * na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(arr_int * na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(2 * na, NAType), NAType) + # __and__ check(assert_type(na & s_int, pd.Series), pd.Series) check(assert_type(na & idx_int, pd.Index), pd.Index) - check(assert_type(na & arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na & arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine # check(assert_type(na & True, NAType), NAType) + # __rand__ + check(assert_type(s_int & na, pd.Series), pd.Series) + check(assert_type(idx_int & na, pd.Index), pd.Index) + check(assert_type(arr_int & na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + # check(ssert_typa & Trueana, NAType), NAType) + # __or__ check(assert_type(na | s_int, pd.Series), pd.Series) check(assert_type(na | idx_int, pd.Index), pd.Index) - check(assert_type(na | arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na | arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine # check(assert_type(na | True, NAType), NAType) + # __ror__ + check(assert_type(s_int | na, pd.Series), pd.Series) + check(assert_type(idx_int | na, pd.Index), pd.Index) + check(assert_type(arr_int | na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + # check(ssert_typa | Trueana, NAType), NAType) + # __xor__ check(assert_type(na ^ s_int, pd.Series), pd.Series) check(assert_type(na ^ idx_int, pd.Index), pd.Index) - check(assert_type(na ^ arr_int, npt.NDArray), npt.NDArray) + check(assert_type(na ^ arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine + + # rxor From 527f00fa7dc0fc4840910d4d1e850398f5757a21 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:20:14 +0100 Subject: [PATCH 06/18] wip --- pandas-stubs/_libs/missing.pyi | 5 +---- tests/test_natype.py | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index cbb40ac20..383c38f7c 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -82,9 +82,6 @@ class NAType: def __matmul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload def __matmul__(self, other: object, /) -> NAType: ... - @overload - def __rmatmul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - @overload def __rmatmul__(self, other: object, /) -> NAType: ... @overload def __truediv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -121,7 +118,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __rfloordiv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __rfloordiv__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload def __rfloordiv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload diff --git a/tests/test_natype.py b/tests/test_natype.py index e07d85cd6..7b3865eff 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -14,6 +14,7 @@ def test_arithmetic() -> None: s_int = pd.Series([1, 2, 3]) idx_int = pd.Index([1, 2, 3]) arr_int: npt.NDArray[Any] = np.array([1, 2, 3]) + ma_int: npt.NDArray[Any] = np.array([[1, 2, 3], [4, 5, 6]]) # __add__ check(assert_type(na + s_int, pd.Series), pd.Series) @@ -52,17 +53,12 @@ def test_arithmetic() -> None: check(assert_type(arr_int * na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 * na, NAType), NAType) - # __floordiv__ - check(assert_type(na // s_int, pd.Series), pd.Series) - check(assert_type(na // idx_int, pd.Index), pd.Index) - check(assert_type(na // arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine - check(assert_type(na // 1, NAType), NAType) + # __matmul__ + check(assert_type(na @ ma_int, npt.NDArray), npt.NDArray) + check(assert_type(na @ 1, NAType), NAType) - # __rfloordiv__ - # check(assert_type(/ s_int/na, pd.Series), pd.Series) - # check(assert_type(/ idx_int/na, pd.Index), pd.Index) - # check(assert_type(/ arr_int/na, npt.NDArray), npt.NDArray) - # check(assert_type(/ 1/na, NAType), NAType) + # __rmatmul__ + check(assert_type(1 @ na, NAType), NAType) # __truediv__ check(assert_type(na / s_int, pd.Series), pd.Series) @@ -76,6 +72,18 @@ def test_arithmetic() -> None: check(assert_type(arr_int / na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 / na, NAType), NAType) + # __floordiv__ + check(assert_type(na // s_int, pd.Series), pd.Series) + check(assert_type(na // idx_int, pd.Index), pd.Index) + check(assert_type(na // arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine + check(assert_type(na // 1, NAType), NAType) + + # __rfloordiv__ + check(assert_type(s_int // na, pd.Series), pd.Series) + check(assert_type(idx_int // na, npt.NDArray), npt.NDArray) + check(assert_type(arr_int // na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(1 // na, NAType), NAType) + # __mod__ check(assert_type(na % s_int, pd.Series), pd.Series) check(assert_type(na % idx_int, pd.Index), pd.Index) From e5c8df7a73f386fe5ff282d9d1592810ff0cfc8f Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 16:56:00 +0100 Subject: [PATCH 07/18] fixup --- pandas-stubs/_libs/missing.pyi | 37 +++++++----- tests/test_natype.py | 102 ++++++++++++++------------------- 2 files changed, 64 insertions(+), 75 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index 383c38f7c..4bad46c5f 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -10,6 +10,7 @@ from pandas import ( Index, Series, ) +from pandas.core.arrays.boolean import BooleanArray from typing_extensions import Self class NAType: @@ -25,7 +26,7 @@ class NAType: @overload def __add__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __add__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + def __add__(self, other: npt.NDArray[Any], /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload def __add__(self, other: object, /) -> NAType: ... @overload @@ -35,8 +36,6 @@ class NAType: @overload def __radd__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __radd__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __radd__(self, other: object, /) -> NAType: ... @overload def __sub__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -118,7 +117,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __rfloordiv__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + def __rfloordiv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload def __rfloordiv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -166,9 +165,9 @@ class NAType: @overload # type: ignore[override] def __eq__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / - ) -> Series: ... + ) -> BooleanArray: ... @overload - def __eq__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + def __eq__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload def __eq__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -180,7 +179,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __ne__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + def __ne__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload def __ne__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -192,7 +191,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __le__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + def __le__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload def __le__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -202,7 +201,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __lt__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + def __lt__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload def __lt__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -212,7 +211,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __gt__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + def __gt__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload def __gt__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -222,7 +221,7 @@ class NAType: self, other: Series, / ) -> Series: ... @overload - def __ge__(self, other: Index, /) -> npt.NDArray: ... # type: ignore[overload-overlap] + def __ge__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload def __ge__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload @@ -260,7 +259,9 @@ class NAType: @overload def __and__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload - def __and__(self, other: object, /) -> Literal[False] | NAType: ... + def __and__(self, other: Literal[False], /) -> Literal[False]: ... + @overload + def __and__(self, other: object, /) -> NAType: ... @overload def __rand__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / @@ -270,7 +271,9 @@ class NAType: @overload def __rand__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload - def __rand__(self, other: object, /) -> Literal[False] | NAType: ... + def __rand__(self, other: Literal[False], /) -> Literal[False]: ... + @overload + def __rand__(self, other: object, /) -> NAType: ... @overload def __or__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / @@ -280,7 +283,9 @@ class NAType: @overload def __or__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload - def __or__(self, other: object, /) -> Literal[True] | NAType: ... + def __or__(self, other: Literal[True], /) -> Literal[True]: ... + @overload + def __or__(self, other: object, /) -> NAType: ... @overload def __ror__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / @@ -290,7 +295,9 @@ class NAType: @overload def __ror__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] @overload - def __ror__(self, other: object, /) -> Literal[True] | NAType: ... + def __ror__(self, other: Literal[True], /) -> Literal[True]: ... + @overload + def __ror__(self, other: object, /) -> NAType: ... @overload def __xor__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / diff --git a/tests/test_natype.py b/tests/test_natype.py index 7b3865eff..4ff0176b5 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -1,9 +1,13 @@ -from typing import Any +from typing import ( + Any, + Literal, +) import numpy as np import numpy.typing as npt import pandas as pd from pandas.api.typing import NAType +from pandas.core.arrays.boolean import BooleanArray from typing_extensions import assert_type from tests import check @@ -11,8 +15,10 @@ def test_arithmetic() -> None: na = pd.NA - s_int = pd.Series([1, 2, 3]) - idx_int = pd.Index([1, 2, 3]) + + s_int: pd.Series[int] = pd.Series([1, 2, 3], dtype="Int64") + idx_int: pd.Index[int] = pd.Index([1, 2, 3], dtype="Int64") + arr_int: npt.NDArray[Any] = np.array([1, 2, 3]) ma_int: npt.NDArray[Any] = np.array([[1, 2, 3], [4, 5, 6]]) @@ -25,8 +31,7 @@ def test_arithmetic() -> None: # __radd__ check(assert_type(s_int + na, pd.Series), pd.Series) # https://github.com/pandas-dev/pandas-stubs/issues/1347 - check(assert_type(idx_int + na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - check(assert_type(arr_int + na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(idx_int + na, pd.Index), pd.Index) # type: ignore[assert-type]# pyright: ignore[reportAssertTypeFailure] check(assert_type(1 + na, NAType), NAType) # __sub__ @@ -37,7 +42,8 @@ def test_arithmetic() -> None: # __rsub__ check(assert_type(s_int - na, pd.Series), pd.Series) - check(assert_type(idx_int - na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + # https://github.com/pandas-dev/pandas-stubs/issues/1347 + check(assert_type(idx_int - na, pd.Index), pd.Index) # type: ignore[assert-type]# pyright: ignore[reportAssertTypeFailure] check(assert_type(arr_int - na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 - na, NAType), NAType) @@ -49,12 +55,13 @@ def test_arithmetic() -> None: # __rmul__ check(assert_type(s_int * na, pd.Series), pd.Series) - check(assert_type(idx_int * na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + # https://github.com/pandas-dev/pandas-stubs/issues/1347 + check(assert_type(idx_int * na, pd.Index), pd.Index) # type: ignore[assert-type]# pyright: ignore[reportAssertTypeFailure] check(assert_type(arr_int * na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 * na, NAType), NAType) # __matmul__ - check(assert_type(na @ ma_int, npt.NDArray), npt.NDArray) + check(assert_type(na @ ma_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na @ 1, NAType), NAType) # __rmatmul__ @@ -79,8 +86,9 @@ def test_arithmetic() -> None: check(assert_type(na // 1, NAType), NAType) # __rfloordiv__ + # TODO: put these back but use nullable series to test it check(assert_type(s_int // na, pd.Series), pd.Series) - check(assert_type(idx_int // na, npt.NDArray), npt.NDArray) + check(assert_type(idx_int // na, pd.Index), pd.Index) check(assert_type(arr_int // na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 // na, NAType), NAType) @@ -92,82 +100,47 @@ def test_arithmetic() -> None: # __rmod__ check(assert_type(s_int % na, pd.Series), pd.Series) - check(assert_type(idx_int % na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + # https://github.com/pandas-dev/pandas-stubs/issues/1347 + check(assert_type(idx_int % na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(arr_int % na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 % na, NAType), NAType) # __eq__ check(assert_type(na == s_int, pd.Series), pd.Series) - check(assert_type(na == idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na == idx_int, BooleanArray), BooleanArray) check(assert_type(na == arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na == 1, NAType), NAType) - # __req__ - # check(assert_type(= s_int=na, pd.Series), pd.Series) - # check(assert_type(= idx_int=na, npt.NDArray), npt.NDArray) - # check(assert_type(= arr_int=na, npt.NDArray), npt.NDArray) - # check(assert_type(= 1=na, NAType), NAType) - # __ne__ check(assert_type(na != s_int, pd.Series), pd.Series) - check(assert_type(na != idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na != idx_int, BooleanArray), BooleanArray) check(assert_type(na != arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na != 1, NAType), NAType) - # __rne__ - # check(assert_type(= s_int!na, pd.Series), pd.Series) - # check(assert_type(= idx_int!na, npt.NDArray), npt.NDArray) - # check(assert_type(= arr_int!na, npt.NDArray), npt.NDArray) - # check(assert_type(= 1!na, NAType), NAType) - # __le__ check(assert_type(na <= s_int, pd.Series), pd.Series) - check(assert_type(na <= idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na <= idx_int, BooleanArray), BooleanArray) check(assert_type(na <= arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na <= 1, NAType), NAType) - # __rle__ - # check(assert_type(= s_int= s_int, pd.Series), pd.Series) - check(assert_type(na >= idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na >= idx_int, BooleanArray), BooleanArray) check(assert_type(na >= arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na >= 1, NAType), NAType) - # __rge__ - # check(assert_type(= s_int>na, pd.Series), pd.Series) - # check(assert_type(= idx_int>na, npt.NDArray), npt.NDArray) - # check(assert_type(= arr_int>na, npt.NDArray), npt.NDArray) - # check(assert_type(= 1>na, NAType), NAType) - # __gt__ check(assert_type(na > s_int, pd.Series), pd.Series) - check(assert_type(na > idx_int, npt.NDArray), npt.NDArray) + check(assert_type(na > idx_int, BooleanArray), BooleanArray) check(assert_type(na > arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na > 1, NAType), NAType) - # __rgt__ - check(assert_type(s_int > na, pd.Series), pd.Series) - check(assert_type(idx_int > na, npt.NDArray), npt.NDArray) - check(assert_type(arr_int > na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - check(assert_type(1 > na, NAType), NAType) - # __pow__ check(assert_type(na**s_int, pd.Series), pd.Series) check(assert_type(na**idx_int, pd.Index), pd.Index) @@ -175,34 +148,40 @@ def test_arithmetic() -> None: check(assert_type(na**2, NAType), NAType) # __rpow__ - check(assert_type(s_int * na, pd.Series), pd.Series) - check(assert_type(idx_int * na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - check(assert_type(arr_int * na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - check(assert_type(2 * na, NAType), NAType) + check(assert_type(s_int**na, pd.Series), pd.Series) + # https://github.com/pandas-dev/pandas-stubs/issues/1347 + check(assert_type(idx_int**na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(arr_int**na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + check(assert_type(2**na, NAType), NAType) # __and__ check(assert_type(na & s_int, pd.Series), pd.Series) check(assert_type(na & idx_int, pd.Index), pd.Index) check(assert_type(na & arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine - # check(assert_type(na & True, NAType), NAType) + check(assert_type(na & False, Literal[False]), bool) + check(assert_type(na & True, NAType), NAType) + check(assert_type(na & na, NAType), NAType) # __rand__ check(assert_type(s_int & na, pd.Series), pd.Series) check(assert_type(idx_int & na, pd.Index), pd.Index) check(assert_type(arr_int & na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - # check(ssert_typa & Trueana, NAType), NAType) + check(assert_type(False & na, Literal[False]), bool) + check(assert_type(True & na, NAType), NAType) # __or__ check(assert_type(na | s_int, pd.Series), pd.Series) check(assert_type(na | idx_int, pd.Index), pd.Index) check(assert_type(na | arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine - # check(assert_type(na | True, NAType), NAType) + check(assert_type(na | False, NAType), NAType) + check(assert_type(na | True, Literal[True]), bool) # __ror__ check(assert_type(s_int | na, pd.Series), pd.Series) check(assert_type(idx_int | na, pd.Index), pd.Index) check(assert_type(arr_int | na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - # check(ssert_typa | Trueana, NAType), NAType) + check(assert_type(False | na, NAType), NAType) + check(assert_type(True | na, Literal[True]), bool) # __xor__ check(assert_type(na ^ s_int, pd.Series), pd.Series) @@ -210,3 +189,6 @@ def test_arithmetic() -> None: check(assert_type(na ^ arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine # rxor + check(assert_type(s_int ^ na, pd.Series), pd.Series) + check(assert_type(idx_int ^ na, pd.Index), pd.Index) + check(assert_type(arr_int ^ na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] From 2ae0638363007fb08ab013435e71ba9eff1f7cc0 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 16:57:16 +0100 Subject: [PATCH 08/18] fixup --- pandas-stubs/_libs/missing.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index 4bad46c5f..c8b30280b 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -165,7 +165,7 @@ class NAType: @overload # type: ignore[override] def __eq__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / - ) -> BooleanArray: ... + ) -> Series: ... @overload def __eq__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload From bc73767c6a9c0dc331861aed347e6db5619d3d56 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 17:28:59 +0100 Subject: [PATCH 09/18] remove ndarray overloads as they dont really make sense for a nullable-only object --- pandas-stubs/_libs/missing.pyi | 57 ------------------------------- tests/test_natype.py | 61 +++++++++++++++------------------- 2 files changed, 27 insertions(+), 91 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index c8b30280b..8c5b06765 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -5,7 +5,6 @@ from typing import ( overload, ) -import numpy.typing as npt from pandas import ( Index, Series, @@ -26,8 +25,6 @@ class NAType: @overload def __add__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __add__(self, other: npt.NDArray[Any], /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __add__(self, other: object, /) -> NAType: ... @overload def __radd__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -44,8 +41,6 @@ class NAType: @overload def __sub__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __sub__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __sub__(self, other: object, /) -> NAType: ... @overload def __rsub__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -54,8 +49,6 @@ class NAType: @overload def __rsub__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rsub__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __rsub__(self, other: object, /) -> NAType: ... @overload def __mul__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -64,8 +57,6 @@ class NAType: @overload def __mul__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __mul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __mul__(self, other: object, /) -> NAType: ... @overload def __rmul__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -74,12 +65,8 @@ class NAType: @overload def __rmul__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rmul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __rmul__(self, other: object, /) -> NAType: ... @overload - def __matmul__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - @overload def __matmul__(self, other: object, /) -> NAType: ... def __rmatmul__(self, other: object, /) -> NAType: ... @overload @@ -89,8 +76,6 @@ class NAType: @overload def __truediv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __truediv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __truediv__(self, other: object, /) -> NAType: ... @overload def __rtruediv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -99,8 +84,6 @@ class NAType: @overload def __rtruediv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rtruediv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __rtruediv__(self, other: object, /) -> NAType: ... @overload def __floordiv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -109,8 +92,6 @@ class NAType: @overload def __floordiv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __floordiv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __floordiv__(self, other: object, /) -> NAType: ... @overload def __rfloordiv__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -119,8 +100,6 @@ class NAType: @overload def __rfloordiv__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rfloordiv__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __rfloordiv__(self, other: object, /) -> NAType: ... @overload def __mod__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -129,8 +108,6 @@ class NAType: @overload def __mod__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __mod__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __mod__(self, other: object, /) -> NAType: ... @overload def __rmod__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -139,8 +116,6 @@ class NAType: @overload def __rmod__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rmod__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __rmod__(self, other: object, /) -> NAType: ... @overload def __divmod__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -149,8 +124,6 @@ class NAType: @overload def __divmod__(self, other: Index, /) -> tuple[Index, Index]: ... # type: ignore[overload-overlap] @overload - def __divmod__(self, other: npt.NDArray, /) -> tuple[npt.NDArray, npt.NDArray]: ... # type: ignore[overload-overlap] - @overload def __divmod__(self, other: object, /) -> tuple[NAType, NAType]: ... @overload def __rdivmod__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -159,8 +132,6 @@ class NAType: @overload def __rdivmod__(self, other: Index, /) -> tuple[Index, Index]: ... # type: ignore[overload-overlap] @overload - def __rdivmod__(self, other: npt.NDArray, /) -> tuple[npt.NDArray, npt.NDArray]: ... # type: ignore[overload-overlap] - @overload def __rdivmod__(self, other: object, /) -> tuple[NAType, NAType]: ... @overload # type: ignore[override] def __eq__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -169,8 +140,6 @@ class NAType: @overload def __eq__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload - def __eq__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __eq__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: object, / ) -> NAType: ... @@ -181,8 +150,6 @@ class NAType: @overload def __ne__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload - def __ne__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __ne__( # pyright: ignore[reportIncompatibleMethodOverride] self, other: object, / ) -> NAType: ... @@ -193,8 +160,6 @@ class NAType: @overload def __le__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload - def __le__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __le__(self, other: object, /) -> NAType: ... @overload def __lt__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -203,8 +168,6 @@ class NAType: @overload def __lt__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload - def __lt__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __lt__(self, other: object, /) -> NAType: ... @overload def __gt__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -213,8 +176,6 @@ class NAType: @overload def __gt__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload - def __gt__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __gt__(self, other: object, /) -> NAType: ... @overload def __ge__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -223,8 +184,6 @@ class NAType: @overload def __ge__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload - def __ge__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __ge__(self, other: object, /) -> NAType: ... def __neg__(self) -> NAType: ... def __pos__(self) -> NAType: ... @@ -237,8 +196,6 @@ class NAType: @overload def __pow__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __pow__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __pow__(self, other: object, /) -> NAType: ... @overload def __rpow__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -247,8 +204,6 @@ class NAType: @overload def __rpow__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rpow__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __rpow__(self, other: object, /) -> NAType: ... @overload def __and__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -257,8 +212,6 @@ class NAType: @overload def __and__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __and__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __and__(self, other: Literal[False], /) -> Literal[False]: ... @overload def __and__(self, other: object, /) -> NAType: ... @@ -269,8 +222,6 @@ class NAType: @overload def __rand__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rand__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __rand__(self, other: Literal[False], /) -> Literal[False]: ... @overload def __rand__(self, other: object, /) -> NAType: ... @@ -281,8 +232,6 @@ class NAType: @overload def __or__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __or__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __or__(self, other: Literal[True], /) -> Literal[True]: ... @overload def __or__(self, other: object, /) -> NAType: ... @@ -293,8 +242,6 @@ class NAType: @overload def __ror__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __ror__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __ror__(self, other: Literal[True], /) -> Literal[True]: ... @overload def __ror__(self, other: object, /) -> NAType: ... @@ -305,8 +252,6 @@ class NAType: @overload def __xor__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __xor__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __xor__(self, other: object, /) -> NAType: ... @overload def __rxor__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @@ -315,8 +260,6 @@ class NAType: @overload def __rxor__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rxor__(self, other: npt.NDArray, /) -> npt.NDArray: ... # type: ignore[overload-overlap] - @overload def __rxor__(self, other: object, /) -> NAType: ... __array_priority__: int def __array_ufunc__( diff --git a/tests/test_natype.py b/tests/test_natype.py index 4ff0176b5..fb04bf64b 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -1,13 +1,11 @@ from typing import ( - Any, Literal, ) -import numpy as np -import numpy.typing as npt import pandas as pd from pandas.api.typing import NAType from pandas.core.arrays.boolean import BooleanArray +import pytest from typing_extensions import assert_type from tests import check @@ -19,49 +17,40 @@ def test_arithmetic() -> None: s_int: pd.Series[int] = pd.Series([1, 2, 3], dtype="Int64") idx_int: pd.Index[int] = pd.Index([1, 2, 3], dtype="Int64") - arr_int: npt.NDArray[Any] = np.array([1, 2, 3]) - ma_int: npt.NDArray[Any] = np.array([[1, 2, 3], [4, 5, 6]]) - # __add__ check(assert_type(na + s_int, pd.Series), pd.Series) check(assert_type(na + idx_int, pd.Index), pd.Index) - check(assert_type(na + arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na + 1, NAType), NAType) # __radd__ check(assert_type(s_int + na, pd.Series), pd.Series) # https://github.com/pandas-dev/pandas-stubs/issues/1347 - check(assert_type(idx_int + na, pd.Index), pd.Index) # type: ignore[assert-type]# pyright: ignore[reportAssertTypeFailure] + check(assert_type(idx_int + na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 + na, NAType), NAType) # __sub__ check(assert_type(na - s_int, pd.Series), pd.Series) check(assert_type(na - idx_int, pd.Index), pd.Index) - check(assert_type(na - arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na - 1, NAType), NAType) # __rsub__ check(assert_type(s_int - na, pd.Series), pd.Series) # https://github.com/pandas-dev/pandas-stubs/issues/1347 check(assert_type(idx_int - na, pd.Index), pd.Index) # type: ignore[assert-type]# pyright: ignore[reportAssertTypeFailure] - check(assert_type(arr_int - na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 - na, NAType), NAType) # __mul__ check(assert_type(na * s_int, pd.Series), pd.Series) check(assert_type(na * idx_int, pd.Index), pd.Index) - check(assert_type(na * arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na * 1, NAType), NAType) # __rmul__ check(assert_type(s_int * na, pd.Series), pd.Series) # https://github.com/pandas-dev/pandas-stubs/issues/1347 check(assert_type(idx_int * na, pd.Index), pd.Index) # type: ignore[assert-type]# pyright: ignore[reportAssertTypeFailure] - check(assert_type(arr_int * na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 * na, NAType), NAType) # __matmul__ - check(assert_type(na @ ma_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na @ 1, NAType), NAType) # __rmatmul__ @@ -70,94 +59,103 @@ def test_arithmetic() -> None: # __truediv__ check(assert_type(na / s_int, pd.Series), pd.Series) check(assert_type(na / idx_int, pd.Index), pd.Index) - check(assert_type(na / arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na / 1, NAType), NAType) # __rtruediv__ check(assert_type(s_int / na, pd.Series), pd.Series) check(assert_type(idx_int / na, pd.Index), pd.Index) - check(assert_type(arr_int / na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 / na, NAType), NAType) # __floordiv__ check(assert_type(na // s_int, pd.Series), pd.Series) check(assert_type(na // idx_int, pd.Index), pd.Index) - check(assert_type(na // arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na // 1, NAType), NAType) # __rfloordiv__ - # TODO: put these back but use nullable series to test it check(assert_type(s_int // na, pd.Series), pd.Series) check(assert_type(idx_int // na, pd.Index), pd.Index) - check(assert_type(arr_int // na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 // na, NAType), NAType) # __mod__ check(assert_type(na % s_int, pd.Series), pd.Series) check(assert_type(na % idx_int, pd.Index), pd.Index) - check(assert_type(na % arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na % 1, NAType), NAType) # __rmod__ check(assert_type(s_int % na, pd.Series), pd.Series) # https://github.com/pandas-dev/pandas-stubs/issues/1347 check(assert_type(idx_int % na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - check(assert_type(arr_int % na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(1 % na, NAType), NAType) + # __divmod__ + with pytest.raises(RuntimeError): + # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 + check( + assert_type(divmod(na, s_int), tuple[pd.Series, pd.Series]), tuple + ) # pyright: ignore[reportAssertTypeFailure] + with pytest.raises(RuntimeError): + check( + assert_type(divmod(na, idx_int), tuple[pd.Index, pd.Index]), tuple + ) # pyright: ignore[reportAssertTypeFailure] + check(assert_type(divmod(na, 1), tuple[NAType, NAType]), tuple) + + # __rdivmod__ + with pytest.raises(RuntimeError): + # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 + check( + assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), tuple + ) # pyright: ignore[reportAssertTypeFailure] + with pytest.raises(RuntimeError): + # https://github.com/pandas-dev/pandas-stubs/issues/1347 + check( + assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), tuple + ) # pyright: ignore[reportAssertTypeFailure] + check(assert_type(divmod(1, na), tuple[NAType, NAType]), tuple) + # __eq__ check(assert_type(na == s_int, pd.Series), pd.Series) check(assert_type(na == idx_int, BooleanArray), BooleanArray) - check(assert_type(na == arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na == 1, NAType), NAType) # __ne__ check(assert_type(na != s_int, pd.Series), pd.Series) check(assert_type(na != idx_int, BooleanArray), BooleanArray) - check(assert_type(na != arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na != 1, NAType), NAType) # __le__ check(assert_type(na <= s_int, pd.Series), pd.Series) check(assert_type(na <= idx_int, BooleanArray), BooleanArray) - check(assert_type(na <= arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na <= 1, NAType), NAType) # __lt__ check(assert_type(na < s_int, pd.Series), pd.Series) check(assert_type(na < idx_int, BooleanArray), BooleanArray) - check(assert_type(na < arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na < 1, NAType), NAType) # __ge__ check(assert_type(na >= s_int, pd.Series), pd.Series) check(assert_type(na >= idx_int, BooleanArray), BooleanArray) - check(assert_type(na >= arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na >= 1, NAType), NAType) # __gt__ check(assert_type(na > s_int, pd.Series), pd.Series) check(assert_type(na > idx_int, BooleanArray), BooleanArray) - check(assert_type(na > arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na > 1, NAType), NAType) # __pow__ check(assert_type(na**s_int, pd.Series), pd.Series) check(assert_type(na**idx_int, pd.Index), pd.Index) - check(assert_type(na**arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na**2, NAType), NAType) # __rpow__ check(assert_type(s_int**na, pd.Series), pd.Series) # https://github.com/pandas-dev/pandas-stubs/issues/1347 check(assert_type(idx_int**na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - check(assert_type(arr_int**na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(2**na, NAType), NAType) # __and__ check(assert_type(na & s_int, pd.Series), pd.Series) check(assert_type(na & idx_int, pd.Index), pd.Index) - check(assert_type(na & arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na & False, Literal[False]), bool) check(assert_type(na & True, NAType), NAType) check(assert_type(na & na, NAType), NAType) @@ -165,30 +163,25 @@ def test_arithmetic() -> None: # __rand__ check(assert_type(s_int & na, pd.Series), pd.Series) check(assert_type(idx_int & na, pd.Index), pd.Index) - check(assert_type(arr_int & na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(False & na, Literal[False]), bool) check(assert_type(True & na, NAType), NAType) # __or__ check(assert_type(na | s_int, pd.Series), pd.Series) check(assert_type(na | idx_int, pd.Index), pd.Index) - check(assert_type(na | arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine check(assert_type(na | False, NAType), NAType) check(assert_type(na | True, Literal[True]), bool) # __ror__ check(assert_type(s_int | na, pd.Series), pd.Series) check(assert_type(idx_int | na, pd.Index), pd.Index) - check(assert_type(arr_int | na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] check(assert_type(False | na, NAType), NAType) check(assert_type(True | na, Literal[True]), bool) # __xor__ check(assert_type(na ^ s_int, pd.Series), pd.Series) check(assert_type(na ^ idx_int, pd.Index), pd.Index) - check(assert_type(na ^ arr_int, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # mypy bug? pyright fine # rxor check(assert_type(s_int ^ na, pd.Series), pd.Series) check(assert_type(idx_int ^ na, pd.Index), pd.Index) - check(assert_type(arr_int ^ na, npt.NDArray), npt.NDArray) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] From 2527f5dd2ad84d8c05ccbaf2c2718db6c6ac0983 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:01:51 +0100 Subject: [PATCH 10/18] fixup --- pandas-stubs/_libs/missing.pyi | 1 - tests/test_natype.py | 30 +++++++++++++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index 8c5b06765..830ade34c 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -66,7 +66,6 @@ class NAType: def __rmul__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload def __rmul__(self, other: object, /) -> NAType: ... - @overload def __matmul__(self, other: object, /) -> NAType: ... def __rmatmul__(self, other: object, /) -> NAType: ... @overload diff --git a/tests/test_natype.py b/tests/test_natype.py index fb04bf64b..21490797a 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -91,25 +91,29 @@ def test_arithmetic() -> None: with pytest.raises(RuntimeError): # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 check( - assert_type(divmod(na, s_int), tuple[pd.Series, pd.Series]), tuple - ) # pyright: ignore[reportAssertTypeFailure] + assert_type(divmod(na, s_int), tuple[pd.Series, pd.Series]), + tuple, # pyright: ignore[reportAssertTypeFailure] + ) with pytest.raises(RuntimeError): check( - assert_type(divmod(na, idx_int), tuple[pd.Index, pd.Index]), tuple - ) # pyright: ignore[reportAssertTypeFailure] + assert_type(divmod(na, idx_int), tuple[pd.Index, pd.Index]), + tuple, # pyright: ignore[reportAssertTypeFailure] + ) check(assert_type(divmod(na, 1), tuple[NAType, NAType]), tuple) # __rdivmod__ with pytest.raises(RuntimeError): # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 check( - assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), tuple - ) # pyright: ignore[reportAssertTypeFailure] + assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), + tuple, # pyright: ignore[reportAssertTypeFailure] + ) with pytest.raises(RuntimeError): # https://github.com/pandas-dev/pandas-stubs/issues/1347 check( - assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), tuple - ) # pyright: ignore[reportAssertTypeFailure] + assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), + tuple, # pyright: ignore[reportAssertTypeFailure] + ) check(assert_type(divmod(1, na), tuple[NAType, NAType]), tuple) # __eq__ @@ -132,16 +136,16 @@ def test_arithmetic() -> None: check(assert_type(na < idx_int, BooleanArray), BooleanArray) check(assert_type(na < 1, NAType), NAType) - # __ge__ - check(assert_type(na >= s_int, pd.Series), pd.Series) - check(assert_type(na >= idx_int, BooleanArray), BooleanArray) - check(assert_type(na >= 1, NAType), NAType) - # __gt__ check(assert_type(na > s_int, pd.Series), pd.Series) check(assert_type(na > idx_int, BooleanArray), BooleanArray) check(assert_type(na > 1, NAType), NAType) + # __ge__ + check(assert_type(na >= s_int, pd.Series), pd.Series) + check(assert_type(na >= idx_int, BooleanArray), BooleanArray) + check(assert_type(na >= 1, NAType), NAType) + # __pow__ check(assert_type(na**s_int, pd.Series), pd.Series) check(assert_type(na**idx_int, pd.Index), pd.Index) From 6760c3dfb79ebd5d2329b3362306abdefe8c5c77 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:05:24 +0100 Subject: [PATCH 11/18] fixup --- tests/test_natype.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/test_natype.py b/tests/test_natype.py index 21490797a..c7a035524 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -91,13 +91,17 @@ def test_arithmetic() -> None: with pytest.raises(RuntimeError): # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 check( - assert_type(divmod(na, s_int), tuple[pd.Series, pd.Series]), - tuple, # pyright: ignore[reportAssertTypeFailure] + assert_type( + divmod(na, s_int), tuple[pd.Series, pd.Series] + ), # pyright: ignore[reportAssertTypeFailure] + tuple, ) with pytest.raises(RuntimeError): check( - assert_type(divmod(na, idx_int), tuple[pd.Index, pd.Index]), - tuple, # pyright: ignore[reportAssertTypeFailure] + assert_type( + divmod(na, idx_int), tuple[pd.Index, pd.Index] + ), # pyright: ignore[reportAssertTypeFailure] + tuple, ) check(assert_type(divmod(na, 1), tuple[NAType, NAType]), tuple) @@ -105,14 +109,14 @@ def test_arithmetic() -> None: with pytest.raises(RuntimeError): # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 check( - assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), - tuple, # pyright: ignore[reportAssertTypeFailure] + assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + tuple, ) with pytest.raises(RuntimeError): # https://github.com/pandas-dev/pandas-stubs/issues/1347 check( - assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), - tuple, # pyright: ignore[reportAssertTypeFailure] + assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + tuple, ) check(assert_type(divmod(1, na), tuple[NAType, NAType]), tuple) From a686ae9db49d9c10c8549b76c2225a0d4af6725e Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:08:51 +0100 Subject: [PATCH 12/18] fixup --- tests/test_natype.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_natype.py b/tests/test_natype.py index c7a035524..ad3744218 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -92,15 +92,17 @@ def test_arithmetic() -> None: # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 check( assert_type( - divmod(na, s_int), tuple[pd.Series, pd.Series] - ), # pyright: ignore[reportAssertTypeFailure] + divmod(na, s_int), # pyright: ignore[reportAssertTypeFailure] + tuple[pd.Series, pd.Series], + ), tuple, ) with pytest.raises(RuntimeError): check( assert_type( - divmod(na, idx_int), tuple[pd.Index, pd.Index] - ), # pyright: ignore[reportAssertTypeFailure] + divmod(na, idx_int), # pyright: ignore[reportAssertTypeFailure] + tuple[pd.Index, pd.Index], + ), tuple, ) check(assert_type(divmod(na, 1), tuple[NAType, NAType]), tuple) From 08e604c5d1ec30bf66b090aa302af71d654d5997 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Tue, 26 Aug 2025 18:31:10 +0100 Subject: [PATCH 13/18] mypy fixup --- pandas-stubs/_libs/missing.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index 830ade34c..af599dc16 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -211,7 +211,7 @@ class NAType: @overload def __and__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __and__(self, other: Literal[False], /) -> Literal[False]: ... + def __and__(self, other: Literal[False], /) -> Literal[False]: ... # type: ignore[overload-overlap] @overload def __and__(self, other: object, /) -> NAType: ... @overload @@ -221,7 +221,7 @@ class NAType: @overload def __rand__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __rand__(self, other: Literal[False], /) -> Literal[False]: ... + def __rand__(self, other: Literal[False], /) -> Literal[False]: ... # type: ignore[overload-overlap] @overload def __rand__(self, other: object, /) -> NAType: ... @overload @@ -231,7 +231,7 @@ class NAType: @overload def __or__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __or__(self, other: Literal[True], /) -> Literal[True]: ... + def __or__(self, other: Literal[True], /) -> Literal[True]: ... # type: ignore[overload-overlap] @overload def __or__(self, other: object, /) -> NAType: ... @overload @@ -241,7 +241,7 @@ class NAType: @overload def __ror__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] @overload - def __ror__(self, other: Literal[True], /) -> Literal[True]: ... + def __ror__(self, other: Literal[True], /) -> Literal[True]: ... # type: ignore[overload-overlap] @overload def __ror__(self, other: object, /) -> NAType: ... @overload From a094e3e3294bae9496daa251a242f173a94e2cbf Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 27 Aug 2025 12:39:19 +0100 Subject: [PATCH 14/18] remove `__bool__`, and comparisons (eq/ne/gt/lt/...) with `Series`/`Index` as they return `NotImplemented` --- pandas-stubs/_libs/missing.pyi | 53 +++++++++------------------------- tests/test_natype.py | 20 ++++--------- 2 files changed, 20 insertions(+), 53 deletions(-) diff --git a/pandas-stubs/_libs/missing.pyi b/pandas-stubs/_libs/missing.pyi index af599dc16..c06bf3616 100644 --- a/pandas-stubs/_libs/missing.pyi +++ b/pandas-stubs/_libs/missing.pyi @@ -15,7 +15,6 @@ from typing_extensions import Self class NAType: def __new__(cls, *args: Any, **kwargs: Any) -> Self: ... def __format__(self, format_spec: str) -> str: ... - def __bool__(self) -> None: ... def __hash__(self) -> int: ... def __reduce__(self) -> str: ... @overload @@ -135,7 +134,7 @@ class NAType: @overload # type: ignore[override] def __eq__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / - ) -> Series: ... + ) -> Series[bool]: ... @overload def __eq__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload @@ -145,7 +144,7 @@ class NAType: @overload # type: ignore[override] def __ne__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / - ) -> Series: ... + ) -> Series[bool]: ... @overload def __ne__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload @@ -155,7 +154,7 @@ class NAType: @overload def __le__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / - ) -> Series: ... + ) -> Series[bool]: ... @overload def __le__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload @@ -163,7 +162,7 @@ class NAType: @overload def __lt__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / - ) -> Series: ... + ) -> Series[bool]: ... @overload def __lt__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload @@ -171,7 +170,7 @@ class NAType: @overload def __gt__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / - ) -> Series: ... + ) -> Series[bool]: ... @overload def __gt__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload @@ -179,7 +178,7 @@ class NAType: @overload def __ge__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / - ) -> Series: ... + ) -> Series[bool]: ... @overload def __ge__(self, other: Index, /) -> BooleanArray: ... # type: ignore[overload-overlap] @overload @@ -205,45 +204,21 @@ class NAType: @overload def __rpow__(self, other: object, /) -> NAType: ... @overload - def __and__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - self, other: Series, / - ) -> Series: ... - @overload - def __and__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] - @overload - def __and__(self, other: Literal[False], /) -> Literal[False]: ... # type: ignore[overload-overlap] - @overload - def __and__(self, other: object, /) -> NAType: ... + def __and__(self, other: Literal[False], /) -> Literal[False]: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload - def __rand__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - self, other: Series, / - ) -> Series: ... - @overload - def __rand__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __and__(self, other: bool | NAType, /) -> NAType: ... @overload - def __rand__(self, other: Literal[False], /) -> Literal[False]: ... # type: ignore[overload-overlap] + def __rand__(self, other: Literal[False], /) -> Literal[False]: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload - def __rand__(self, other: object, /) -> NAType: ... - @overload - def __or__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - self, other: Series, / - ) -> Series: ... + def __rand__(self, other: bool, /) -> NAType: ... @overload - def __or__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] - @overload - def __or__(self, other: Literal[True], /) -> Literal[True]: ... # type: ignore[overload-overlap] - @overload - def __or__(self, other: object, /) -> NAType: ... - @overload - def __ror__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] - self, other: Series, / - ) -> Series: ... + def __or__(self, other: Literal[True], /) -> Literal[True]: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload - def __ror__(self, other: Index, /) -> Index: ... # type: ignore[overload-overlap] + def __or__(self, other: bool | NAType, /) -> NAType: ... @overload - def __ror__(self, other: Literal[True], /) -> Literal[True]: ... # type: ignore[overload-overlap] + def __ror__(self, other: Literal[True], /) -> Literal[True]: ... # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] @overload - def __ror__(self, other: object, /) -> NAType: ... + def __ror__(self, other: bool | NAType, /) -> NAType: ... @overload def __xor__( # type: ignore[overload-overlap] # pyright: ignore[reportOverlappingOverload] self, other: Series, / diff --git a/tests/test_natype.py b/tests/test_natype.py index ad3744218..89f80e96b 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -123,32 +123,32 @@ def test_arithmetic() -> None: check(assert_type(divmod(1, na), tuple[NAType, NAType]), tuple) # __eq__ - check(assert_type(na == s_int, pd.Series), pd.Series) + check(assert_type(na == s_int, "pd.Series[bool]"), pd.Series) check(assert_type(na == idx_int, BooleanArray), BooleanArray) check(assert_type(na == 1, NAType), NAType) # __ne__ - check(assert_type(na != s_int, pd.Series), pd.Series) + check(assert_type(na != s_int, "pd.Series[bool]"), pd.Series) check(assert_type(na != idx_int, BooleanArray), BooleanArray) check(assert_type(na != 1, NAType), NAType) # __le__ - check(assert_type(na <= s_int, pd.Series), pd.Series) + check(assert_type(na <= s_int, "pd.Series[bool]"), pd.Series) check(assert_type(na <= idx_int, BooleanArray), BooleanArray) check(assert_type(na <= 1, NAType), NAType) # __lt__ - check(assert_type(na < s_int, pd.Series), pd.Series) + check(assert_type(na < s_int, "pd.Series[bool]"), pd.Series) check(assert_type(na < idx_int, BooleanArray), BooleanArray) check(assert_type(na < 1, NAType), NAType) # __gt__ - check(assert_type(na > s_int, pd.Series), pd.Series) + check(assert_type(na > s_int, "pd.Series[bool]"), pd.Series) check(assert_type(na > idx_int, BooleanArray), BooleanArray) check(assert_type(na > 1, NAType), NAType) # __ge__ - check(assert_type(na >= s_int, pd.Series), pd.Series) + check(assert_type(na >= s_int, "pd.Series[bool]"), pd.Series) check(assert_type(na >= idx_int, BooleanArray), BooleanArray) check(assert_type(na >= 1, NAType), NAType) @@ -164,27 +164,19 @@ def test_arithmetic() -> None: check(assert_type(2**na, NAType), NAType) # __and__ - check(assert_type(na & s_int, pd.Series), pd.Series) - check(assert_type(na & idx_int, pd.Index), pd.Index) check(assert_type(na & False, Literal[False]), bool) check(assert_type(na & True, NAType), NAType) check(assert_type(na & na, NAType), NAType) # __rand__ - check(assert_type(s_int & na, pd.Series), pd.Series) - check(assert_type(idx_int & na, pd.Index), pd.Index) check(assert_type(False & na, Literal[False]), bool) check(assert_type(True & na, NAType), NAType) # __or__ - check(assert_type(na | s_int, pd.Series), pd.Series) - check(assert_type(na | idx_int, pd.Index), pd.Index) check(assert_type(na | False, NAType), NAType) check(assert_type(na | True, Literal[True]), bool) # __ror__ - check(assert_type(s_int | na, pd.Series), pd.Series) - check(assert_type(idx_int | na, pd.Index), pd.Index) check(assert_type(False | na, NAType), NAType) check(assert_type(True | na, Literal[True]), bool) From cb1da481ccccf64b5ec1e45609ee818fd3f71f9e Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 27 Aug 2025 12:42:41 +0100 Subject: [PATCH 15/18] remove redundant annotation --- tests/test_natype.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_natype.py b/tests/test_natype.py index 89f80e96b..09099df82 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -14,7 +14,7 @@ def test_arithmetic() -> None: na = pd.NA - s_int: pd.Series[int] = pd.Series([1, 2, 3], dtype="Int64") + s_int = pd.Series([1, 2, 3], dtype="Int64") idx_int: pd.Index[int] = pd.Index([1, 2, 3], dtype="Int64") # __add__ From 340582cbfe9f07976caa6f345b62451c91d6e3f8 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:55:23 +0100 Subject: [PATCH 16/18] comment cases which require other fixes --- tests/test_natype.py | 75 +++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/tests/test_natype.py b/tests/test_natype.py index 09099df82..68de6242c 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -5,7 +5,6 @@ import pandas as pd from pandas.api.typing import NAType from pandas.core.arrays.boolean import BooleanArray -import pytest from typing_extensions import assert_type from tests import check @@ -24,8 +23,8 @@ def test_arithmetic() -> None: # __radd__ check(assert_type(s_int + na, pd.Series), pd.Series) - # https://github.com/pandas-dev/pandas-stubs/issues/1347 - check(assert_type(idx_int + na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + # requires orthogonal fix: https://github.com/pandas-dev/pandas-stubs/issues/1347 + # check(assert_type(idx_int + na, pd.Index), pd.Index) check(assert_type(1 + na, NAType), NAType) # __sub__ @@ -35,8 +34,8 @@ def test_arithmetic() -> None: # __rsub__ check(assert_type(s_int - na, pd.Series), pd.Series) - # https://github.com/pandas-dev/pandas-stubs/issues/1347 - check(assert_type(idx_int - na, pd.Index), pd.Index) # type: ignore[assert-type]# pyright: ignore[reportAssertTypeFailure] + # requires orthogonal fix: https://github.com/pandas-dev/pandas-stubs/issues/1347 + # check(assert_type(idx_int - na, pd.Index), pd.Index) check(assert_type(1 - na, NAType), NAType) # __mul__ @@ -46,8 +45,8 @@ def test_arithmetic() -> None: # __rmul__ check(assert_type(s_int * na, pd.Series), pd.Series) - # https://github.com/pandas-dev/pandas-stubs/issues/1347 - check(assert_type(idx_int * na, pd.Index), pd.Index) # type: ignore[assert-type]# pyright: ignore[reportAssertTypeFailure] + # requires orthogonal fix: https://github.com/pandas-dev/pandas-stubs/issues/1347 + # check(assert_type(idx_int * na, pd.Index), pd.Index) check(assert_type(1 * na, NAType), NAType) # __matmul__ @@ -83,43 +82,39 @@ def test_arithmetic() -> None: # __rmod__ check(assert_type(s_int % na, pd.Series), pd.Series) - # https://github.com/pandas-dev/pandas-stubs/issues/1347 - check(assert_type(idx_int % na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + # requires orthogonal fix: https://github.com/pandas-dev/pandas-stubs/issues/1347 + # check(assert_type(idx_int % na, pd.Index), pd.Index) check(assert_type(1 % na, NAType), NAType) # __divmod__ - with pytest.raises(RuntimeError): - # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 - check( - assert_type( - divmod(na, s_int), # pyright: ignore[reportAssertTypeFailure] - tuple[pd.Series, pd.Series], - ), - tuple, - ) - with pytest.raises(RuntimeError): - check( - assert_type( - divmod(na, idx_int), # pyright: ignore[reportAssertTypeFailure] - tuple[pd.Index, pd.Index], - ), - tuple, - ) + # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 + # check( + # assert_type( + # divmod(na, s_int), + # tuple[pd.Series, pd.Series], + # ), + # tuple, + # ) + # check( + # assert_type( + # divmod(na, idx_int), + # tuple[pd.Index, pd.Index], + # ), + # tuple, + # ) check(assert_type(divmod(na, 1), tuple[NAType, NAType]), tuple) # __rdivmod__ - with pytest.raises(RuntimeError): - # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 - check( - assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - tuple, - ) - with pytest.raises(RuntimeError): - # https://github.com/pandas-dev/pandas-stubs/issues/1347 - check( - assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] - tuple, - ) + # bug upstream: https://github.com/pandas-dev/pandas/issues/62196 + # check( + # assert_type(divmod(s_int, na), tuple[pd.Series, pd.Series]), + # tuple, + # ) + # https://github.com/pandas-dev/pandas-stubs/issues/1347 + # check( + # assert_type(divmod(idx_int, na), tuple[pd.Index, pd.Index]), + # tuple, + # ) check(assert_type(divmod(1, na), tuple[NAType, NAType]), tuple) # __eq__ @@ -159,8 +154,8 @@ def test_arithmetic() -> None: # __rpow__ check(assert_type(s_int**na, pd.Series), pd.Series) - # https://github.com/pandas-dev/pandas-stubs/issues/1347 - check(assert_type(idx_int**na, pd.Index), pd.Index) # type: ignore[assert-type] # pyright: ignore[reportAssertTypeFailure] + # requires orthogonal fix: https://github.com/pandas-dev/pandas-stubs/issues/1347 + # check(assert_type(idx_int**na, pd.Index), pd.Index) check(assert_type(2**na, NAType), NAType) # __and__ From 8c1eced834202c3643a1b8b5fe5858202f0bdc28 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Wed, 27 Aug 2025 17:11:16 +0100 Subject: [PATCH 17/18] note pyright bug --- tests/test_natype.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_natype.py b/tests/test_natype.py index 68de6242c..1d80c1856 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -97,6 +97,8 @@ def test_arithmetic() -> None: # ) # check( # assert_type( + # # pyright bug: https://github.com/microsoft/pyright/issues/10849, will + # # require `pyright: ignore[reportAssertTypeFailure]` until fixed. # divmod(na, idx_int), # tuple[pd.Index, pd.Index], # ), From ce16ae2cdec058e7015952f39784156e47b6de18 Mon Sep 17 00:00:00 2001 From: Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> Date: Fri, 5 Sep 2025 17:12:06 +0100 Subject: [PATCH 18/18] update pyright --- pyproject.toml | 2 +- tests/test_natype.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 048fe96ae..b31546c85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ mypy = "1.17.1" pandas = "2.3.2" pyarrow = ">=10.0.1" pytest = ">=7.1.2" -pyright = ">=1.1.404" +pyright = ">=1.1.405" ty = "^0.0.1a9" pyrefly = "^0.21.0" poethepoet = ">=0.16.5" diff --git a/tests/test_natype.py b/tests/test_natype.py index 1d80c1856..098cfe28f 100644 --- a/tests/test_natype.py +++ b/tests/test_natype.py @@ -97,14 +97,12 @@ def test_arithmetic() -> None: # ) # check( # assert_type( - # # pyright bug: https://github.com/microsoft/pyright/issues/10849, will - # # require `pyright: ignore[reportAssertTypeFailure]` until fixed. # divmod(na, idx_int), # tuple[pd.Index, pd.Index], # ), # tuple, # ) - check(assert_type(divmod(na, 1), tuple[NAType, NAType]), tuple) + check(assert_type(na.__divmod__(1), tuple[NAType, NAType]), tuple) # __rdivmod__ # bug upstream: https://github.com/pandas-dev/pandas/issues/62196