From be5b2bb4e675935771ccb6b0065171b352aef92e Mon Sep 17 00:00:00 2001 From: jorenham Date: Wed, 24 Dec 2025 22:46:15 +0100 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=91=BD=EF=B8=8F=20gradual=20`timedelt?= =?UTF-8?q?a64`=20and=20`datetime64`=20generic=20type=20parameter=20defaul?= =?UTF-8?q?ts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/numpy-stubs/__init__.pyi | 66 ++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/src/numpy-stubs/__init__.pyi b/src/numpy-stubs/__init__.pyi index 1bbc4627..67e92a25 100644 --- a/src/numpy-stubs/__init__.pyi +++ b/src/numpy-stubs/__init__.pyi @@ -658,10 +658,8 @@ _FlexItemT_co = TypeVar( "_FlexItemT_co", bound=bytes | str | tuple[object, ...], default=bytes | str | tuple[Any, ...], covariant=True ) _CharacterItemT_co = TypeVar("_CharacterItemT_co", bound=bytes | str, default=bytes | str, covariant=True) -_TD64ItemT_co = TypeVar( - "_TD64ItemT_co", bound=dt.timedelta | int | None, default=dt.timedelta | int | None, covariant=True -) -_DT64ItemT_co = TypeVar("_DT64ItemT_co", bound=dt.date | int | None, default=dt.date | int | None, covariant=True) +_TD64ItemT_co = TypeVar("_TD64ItemT_co", bound=dt.timedelta | int | None, default=Any, covariant=True) +_DT64ItemT_co = TypeVar("_DT64ItemT_co", bound=dt.date | int | None, default=Any, covariant=True) _TD64UnitT = TypeVar("_TD64UnitT", bound=_TD64Unit, default=_TD64Unit) _IntSizeT_co = TypeVar("_IntSizeT_co", bound=L[1, 2, 4, 8], covariant=True) @@ -2023,7 +2021,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeT_co, _DTypeT_co]): def __sub__(self: _nt.Array[object_], x: object, /) -> _nt.Array[object_]: ... @overload def __sub__( - self: _nt.Array[generic[_AnyNumberItemT]], x: _nt.Sequence1ND[_nt.op.CanRSub[_AnyNumberItemT]], / + self: _nt.Array[number[_AnyNumberItemT]], x: _nt.Sequence1ND[_nt.op.CanRSub[_AnyNumberItemT]], / ) -> _nt.Array[Incomplete]: ... # @@ -2047,7 +2045,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeT_co, _DTypeT_co]): def __rsub__(self: _nt.Array[object_], x: object, /) -> _nt.Array[object_]: ... @overload def __rsub__( - self: _nt.Array[generic[_AnyNumberItemT]], x: _nt.Sequence1ND[_nt.op.CanSub[_AnyNumberItemT]], / + self: _nt.Array[number[_AnyNumberItemT]], x: _nt.Sequence1ND[_nt.op.CanSub[_AnyNumberItemT]], / ) -> _nt.Array[Incomplete]: ... # @@ -2065,7 +2063,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeT_co, _DTypeT_co]): def __isub__(self: _nt.Array[object_], x: object, /) -> ndarray[_ShapeT_co, _DTypeT_co]: ... @overload def __isub__( - self: _nt.Array[generic[_AnyNumberItemT]], + self: _nt.Array[number[_AnyNumberItemT]], x: _nt.Sequence1ND[_nt.op.CanRSub[_AnyNumberItemT, _AnyNumberItemT]], /, ) -> ndarray[_ShapeT_co, _DTypeT_co]: ... @@ -2365,7 +2363,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeT_co, _DTypeT_co]): ) -> _nt.Array[timedelta64]: ... @overload def __floordiv__( - self: _nt.Array[generic[_AnyItemT]], x: _nt.Sequence1ND[_nt.op.CanRFloordiv[_AnyItemT]], / + self: _nt.Array[generic[_AnyNumberItemT]], x: _nt.Sequence1ND[_nt.op.CanRFloordiv[_AnyNumberItemT]], / ) -> _nt.Array[Incomplete]: ... @overload def __floordiv__(self: _nt.Array[object_], x: object, /) -> _nt.Array[object_]: ... @@ -2391,7 +2389,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeT_co, _DTypeT_co]): def __rfloordiv__(self: _nt.Array[integer | floating], x: _nt.ToTimeDelta_nd, /) -> _nt.Array[timedelta64]: ... @overload def __rfloordiv__( - self: _nt.Array[generic[_AnyItemT]], x: _nt.Sequence1ND[_nt.op.CanFloordiv[_AnyItemT]], / + self: _nt.Array[generic[_AnyNumberItemT]], x: _nt.Sequence1ND[_nt.op.CanFloordiv[_AnyNumberItemT]], / ) -> _nt.Array[Incomplete]: ... @overload def __rfloordiv__(self: _nt.Array[object_], x: object, /) -> _nt.Array[object_]: ... @@ -5087,7 +5085,7 @@ class datetime64( # @property @override - def dtype(self) -> dtypes.DateTime64DType: ... # type: ignore[override] + def dtype(self) -> dtypes.DateTime64DType: ... @property @override def itemsize(self) -> L[8]: ... @@ -5099,8 +5097,12 @@ class datetime64( @overload def __add__(self, x: int | _nt.co_integer, /) -> Self: ... @overload + def __add__(self: datetime64[Never], x: timedelta64[Never], /) -> datetime64[Any]: ... + @overload def __add__(self, x: timedelta64[None], /) -> datetime64[None]: ... @overload + def __add__(self: datetime64[Never], x: timedelta64, /) -> datetime64[Any]: ... + @overload def __add__(self: datetime64[None], x: timedelta64, /) -> datetime64[None]: ... @overload def __add__(self: datetime64[int], x: timedelta64[int | dt.timedelta], /) -> datetime64[int]: ... @@ -5117,8 +5119,12 @@ class datetime64( @overload def __radd__(self, x: int | _nt.co_integer, /) -> Self: ... @overload + def __radd__(self, x: timedelta64[Never], /) -> datetime64[Any]: ... + @overload def __radd__(self, x: timedelta64[None], /) -> datetime64[None]: ... @overload + def __radd__(self: datetime64[Never], x: timedelta64, /) -> datetime64[Any]: ... + @overload def __radd__(self: datetime64[None], x: timedelta64, /) -> datetime64[None]: ... @overload def __radd__(self: datetime64[int], x: timedelta64[int | dt.timedelta], /) -> datetime64[int]: ... @@ -5135,14 +5141,22 @@ class datetime64( @overload def __sub__(self, x: int | _nt.co_integer, /) -> Self: ... @overload + def __sub__(self: datetime64[Never], x: datetime64[Never], /) -> timedelta64[Any]: ... + @overload + def __sub__(self: datetime64[Never], x: timedelta64[Never], /) -> datetime64[Any]: ... + @overload def __sub__(self, x: datetime64[None], /) -> timedelta64[None]: ... @overload + def __sub__(self: datetime64[None], x: datetime64[Never], /) -> timedelta64[None]: ... + @overload def __sub__(self, x: timedelta64[None], /) -> datetime64[None]: ... @overload def __sub__(self: datetime64[dt.date], x: dt.date, /) -> dt.timedelta: ... @overload def __sub__(self: datetime64[None], x: datetime64, /) -> timedelta64[None]: ... @overload + def __sub__(self: datetime64[Never], x: timedelta64, /) -> datetime64[Any]: ... + @overload def __sub__(self: datetime64[None], x: timedelta64, /) -> datetime64[None]: ... @overload def __sub__(self: datetime64[int], x: datetime64[int | dt.date], /) -> timedelta64[int]: ... @@ -5201,7 +5215,7 @@ class timedelta64( # @property @override - def dtype(self) -> dtypes.TimeDelta64DType: ... # type: ignore[override] + def dtype(self) -> dtypes.TimeDelta64DType: ... @property @override def itemsize(self) -> L[8]: ... @@ -5229,8 +5243,12 @@ class timedelta64( @overload def __add__(self, x: Self | _nt.CoInteger_0d, /) -> Self: ... @overload + def __add__(self, x: timedelta64[Never], /) -> timedelta64[Any]: ... # type: ignore[overload-cannot-match] + @overload def __add__(self, x: timedelta64[None], /) -> timedelta64[None]: ... @overload + def __add__(self: timedelta64[Never], x: _TD64Like_co, /) -> timedelta64[Any]: ... + @overload def __add__(self: timedelta64[None], x: _TD64Like_co, /) -> timedelta64[None]: ... @overload def __add__(self: timedelta64[int], x: timedelta64[int | dt.timedelta], /) -> timedelta64[int]: ... @@ -5257,22 +5275,30 @@ class timedelta64( @overload def __mul__(self, x: int | _nt.co_integer, /) -> Self: ... @overload + def __mul__(self: timedelta64[Never], x: _nt.JustFloat | floating, /) -> timedelta64[Any]: ... + @overload def __mul__(self, x: _nt.JustFloat | floating, /) -> timedelta64[_TD64ItemT_co | None]: ... # @overload def __rmul__(self, x: int | _nt.co_integer, /) -> Self: ... @overload + def __rmul__(self: timedelta64[Never], x: _nt.JustFloat | floating, /) -> timedelta64[Any]: ... + @overload def __rmul__(self, x: _nt.JustFloat | floating, /) -> timedelta64[_TD64ItemT_co | None]: ... # @overload def __sub__(self, b: Self | _nt.CoInteger_0d, /) -> Self: ... @overload + def __sub__(self, b: timedelta64[Never], /) -> timedelta64[Any]: ... # type: ignore[overload-cannot-match] + @overload def __sub__(self, b: timedelta64[None], /) -> timedelta64[None]: ... @overload def __sub__(self: timedelta64[dt.timedelta], b: dt.timedelta, /) -> dt.timedelta: ... @overload + def __sub__(self: timedelta64[Never], b: _TD64Like_co, /) -> timedelta64[Any]: ... + @overload def __sub__(self: timedelta64[None], b: _TD64Like_co, /) -> timedelta64[None]: ... @overload def __sub__(self: timedelta64[int], b: timedelta64[int | dt.timedelta], /) -> timedelta64[int]: ... @@ -5283,6 +5309,8 @@ class timedelta64( @overload def __rsub__(self, a: _nt.CoInteger_0d, /) -> Self: ... @overload + def __rsub__(self, a: timedelta64[Never], /) -> timedelta64[Any]: ... + @overload def __rsub__(self, a: timedelta64[None], /) -> timedelta64[None]: ... @overload def __rsub__(self: timedelta64[dt.timedelta], a: dt.timedelta, /) -> dt.timedelta: ... @@ -5297,6 +5325,8 @@ class timedelta64( @overload def __truediv__(self, b: _nt.JustInt | integer, /) -> Self: ... @overload + def __truediv__(self: timedelta64[Never], b: _nt.JustFloat | floating, /) -> timedelta64[Any]: ... + @overload def __truediv__(self, b: _nt.JustFloat | floating, /) -> timedelta64[_TD64ItemT_co | None]: ... @overload def __truediv__(self: timedelta64[dt.timedelta], b: dt.timedelta, /) -> float: ... @@ -5313,6 +5343,8 @@ class timedelta64( @overload def __floordiv__(self, b: _nt.JustInt | integer, /) -> Self: ... @overload + def __floordiv__(self: timedelta64[Never], b: _nt.JustFloat | floating, /) -> timedelta64[Any]: ... + @overload def __floordiv__(self, b: _nt.JustFloat | floating, /) -> timedelta64[_TD64ItemT_co | None]: ... @overload def __floordiv__(self: timedelta64[dt.timedelta], b: dt.timedelta, /) -> int: ... @@ -5325,8 +5357,12 @@ class timedelta64( # @overload + def __mod__(self: timedelta64[Never], x: timedelta64[Never], /) -> timedelta64[Any]: ... + @overload def __mod__(self, x: timedelta64[L[0] | None], /) -> timedelta64[None]: ... @overload + def __mod__(self: timedelta64[Never], x: timedelta64, /) -> timedelta64[Any]: ... + @overload def __mod__(self: timedelta64[None], x: timedelta64, /) -> timedelta64[None]: ... @overload def __mod__(self, x: timedelta64[int], /) -> timedelta64[int | None]: ... @@ -5343,6 +5379,8 @@ class timedelta64( # the L[0] makes __mod__ non-commutative, which the first two overloads reflect @overload + def __rmod__(self, x: timedelta64[Never], /) -> timedelta64[Any]: ... + @overload def __rmod__(self, x: timedelta64[None], /) -> timedelta64[None]: ... # type: ignore[misc] @overload def __rmod__(self: timedelta64[L[0] | None], x: timedelta64, /) -> timedelta64[None]: ... @@ -5351,8 +5389,12 @@ class timedelta64( # keep in sync with __mod__ @overload + def __divmod__(self: timedelta64[Never], x: timedelta64[Never], /) -> tuple[int64, timedelta64[Any]]: ... + @overload def __divmod__(self, x: timedelta64[L[0] | None], /) -> tuple[int64, timedelta64[None]]: ... @overload + def __divmod__(self: timedelta64[Never], x: timedelta64, /) -> tuple[int64, timedelta64[Any]]: ... + @overload def __divmod__(self: timedelta64[None], x: timedelta64, /) -> tuple[int64, timedelta64[None]]: ... @overload def __divmod__(self, x: timedelta64[int], /) -> tuple[int64, timedelta64[int | None]]: ... @@ -5369,6 +5411,8 @@ class timedelta64( # keep in sync with __rmod__ @overload + def __rdivmod__(self, x: timedelta64[Never], /) -> tuple[int64, timedelta64[Any]]: ... + @overload def __rdivmod__(self, x: timedelta64[None], /) -> tuple[int64, timedelta64[None]]: ... # type: ignore[misc] @overload def __rdivmod__(self: timedelta64[L[0] | None], x: timedelta64, /) -> tuple[int64, timedelta64[None]]: ... From 04bd0c22f6be04920a594a0a3a40d4db4f5144eb Mon Sep 17 00:00:00 2001 From: jorenham Date: Wed, 24 Dec 2025 22:49:15 +0100 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=90=B4=20ignore=20many=20incorrect=20?= =?UTF-8?q?mypy=20errors=20in=20the=20static=20type=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../@test/runtime/legacy/arithmetic.py | 20 ++++++++-------- .../@test/static/accept/arithmetic.pyi | 23 +++++++++++-------- .../static/accept/array_constructors.pyi | 3 ++- .../@test/static/accept/arraysetops.pyi | 12 ++++++---- .../@test/static/accept/comparisons.pyi | 3 ++- .../@test/static/accept/fromnumeric.pyi | 3 ++- .../@test/static/accept/lib_function_base.pyi | 7 ++++-- src/numpy-stubs/@test/static/accept/mod.pyi | 22 ++++++++++-------- .../@test/static/accept/multiarray.pyi | 7 +++--- .../@test/static/accept/numeric.pyi | 9 +++++--- .../@test/static/accept/ufuncs.pyi | 9 ++++---- .../@test/static/reject/arithmetic.pyi | 6 ----- 12 files changed, 70 insertions(+), 54 deletions(-) diff --git a/src/numpy-stubs/@test/runtime/legacy/arithmetic.py b/src/numpy-stubs/@test/runtime/legacy/arithmetic.py index 330168ff..f7e9dcc0 100644 --- a/src/numpy-stubs/@test/runtime/legacy/arithmetic.py +++ b/src/numpy-stubs/@test/runtime/legacy/arithmetic.py @@ -1,4 +1,4 @@ -from typing import Self +from typing import Any, Self import pytest @@ -34,28 +34,28 @@ def __array__( ret[()] = self return ret - def __sub__(self, value: object) -> Self: + def __sub__(self, value: Any) -> Self: return self - def __rsub__(self, value: object) -> Self: + def __rsub__(self, value: Any) -> Self: return self - def __floordiv__(self, value: object) -> Self: + def __floordiv__(self, value: Any) -> Self: return self - def __rfloordiv__(self, value: object) -> Self: + def __rfloordiv__(self, value: Any) -> Self: return self - def __mul__(self, value: object) -> Self: + def __mul__(self, value: Any) -> Self: return self - def __rmul__(self, value: object) -> Self: + def __rmul__(self, value: Any) -> Self: return self - def __pow__(self, value: object) -> Self: + def __pow__(self, value: Any) -> Self: return self - def __rpow__(self, value: object) -> Self: + def __rpow__(self, value: Any) -> Self: return self @@ -84,7 +84,6 @@ def __rpow__(self, value: object) -> Self: AR_b - AR_LIKE_f AR_b - AR_LIKE_c AR_b - AR_LIKE_m -AR_b - AR_LIKE_O AR_LIKE_u - AR_b AR_LIKE_i - AR_b @@ -92,7 +91,6 @@ def __rpow__(self, value: object) -> Self: AR_LIKE_c - AR_b AR_LIKE_m - AR_b AR_LIKE_M - AR_b -AR_LIKE_O - AR_b AR_u - AR_LIKE_b AR_u - AR_LIKE_u diff --git a/src/numpy-stubs/@test/static/accept/arithmetic.pyi b/src/numpy-stubs/@test/static/accept/arithmetic.pyi index 65c5507b..098fa55b 100644 --- a/src/numpy-stubs/@test/static/accept/arithmetic.pyi +++ b/src/numpy-stubs/@test/static/accept/arithmetic.pyi @@ -27,28 +27,33 @@ AR_Any: _nt.Array assert_type(m8 // m8, np.int64) assert_type(m8 % m8, np.timedelta64) -assert_type(divmod(m8, m8), tuple[np.int64, np.timedelta64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue] +# mypy incorrectly infers this as "tuple[Any, ...]" but pyright behaves correctly +assert_type(divmod(m8, m8), tuple[np.int64, np.timedelta64]) # type: ignore[assert-type] -assert_type(M8_none + m8, np.datetime64[None]) +# mypy incorrectly infers this as "timedelta64[Any]" but pyright behaves correctly +assert_type(M8_none - M8, np.timedelta64[None]) # type: ignore[assert-type] +# mypy incorrectly infers this as "datetime64[Any]" but pyright behaves correctly +assert_type(M8_none + m8, np.datetime64[None]) # type: ignore[assert-type] +assert_type(M8_none - m8, np.datetime64[None]) # type: ignore[assert-type] assert_type(M8_none + i, np.datetime64[None]) -assert_type(M8_none + i8, np.datetime64[None]) -assert_type(M8_none - M8, np.timedelta64[None]) -assert_type(M8_none - m8, np.datetime64[None]) assert_type(M8_none - i, np.datetime64[None]) +assert_type(M8_none + i8, np.datetime64[None]) assert_type(M8_none - i8, np.datetime64[None]) -assert_type(m8_none + m8, np.timedelta64[None]) +# mypy incorrectly infers this as "timedelta64[Any]" but pyright behaves correctly +assert_type(m8_none + m8, np.timedelta64[None]) # type: ignore[assert-type] assert_type(m8_none + i, np.timedelta64[None]) assert_type(m8_none + i8, np.timedelta64[None]) assert_type(m8_none - i, np.timedelta64[None]) assert_type(m8_none - i8, np.timedelta64[None]) assert_type(m8_int + i, np.timedelta64[int]) -assert_type(m8_int + m8_delta, np.timedelta64[int]) -assert_type(m8_int + m8, np.timedelta64[int | None]) assert_type(m8_int - i, np.timedelta64[int]) +assert_type(m8_int + m8_delta, np.timedelta64[int]) assert_type(m8_int - m8_delta, np.timedelta64[int]) -assert_type(m8_int - m8, np.timedelta64[int | None]) +# mypy incorrectly infers this as "timedelta64[Any]" but pyright behaves correctly +assert_type(m8_int + m8, np.timedelta64[int]) # type: ignore[assert-type] +assert_type(m8_int - m8, np.timedelta64[int]) # type: ignore[assert-type] assert_type(m8_delta + date, dt.date) assert_type(m8_delta + time, dt.datetime) diff --git a/src/numpy-stubs/@test/static/accept/array_constructors.pyi b/src/numpy-stubs/@test/static/accept/array_constructors.pyi index da95966d..e8556bce 100644 --- a/src/numpy-stubs/@test/static/accept/array_constructors.pyi +++ b/src/numpy-stubs/@test/static/accept/array_constructors.pyi @@ -106,7 +106,8 @@ assert_type(np.arange(10.0), _nt.Array1D[np.float64 | Any]) assert_type(np.arange(0, stop=10.0), _nt.Array1D[np.float64 | Any]) assert_type(np.arange(np.timedelta64(0)), _nt.Array1D[np.timedelta64[Any]]) assert_type(np.arange(0, np.timedelta64(10)), _nt.Array1D[np.timedelta64[Any]]) -assert_type(np.arange(np.datetime64("0"), np.datetime64("10")), _nt.Array1D[np.datetime64[Any]]) +# mypy incorrectly infers this as "ndarray[Any, Any]" but pyright behaves correctly +assert_type(np.arange(np.datetime64("0"), np.datetime64("10")), _nt.Array1D[np.datetime64[Any]]) # type: ignore[assert-type] assert_type(np.arange(10, dtype=np.float64), _nt.Array1D[np.float64 | Any]) assert_type(np.arange(0, 10, step=2, dtype=np.int16), _nt.Array1D[np.int16]) assert_type(np.arange(10, dtype=int), _nt.Array1D[np.int_]) diff --git a/src/numpy-stubs/@test/static/accept/arraysetops.pyi b/src/numpy-stubs/@test/static/accept/arraysetops.pyi index 5d6112ef..fa11328c 100644 --- a/src/numpy-stubs/@test/static/accept/arraysetops.pyi +++ b/src/numpy-stubs/@test/static/accept/arraysetops.pyi @@ -15,7 +15,8 @@ AR_LIKE_i_: list[int] assert_type(np.intersect1d(AR_i_, AR_i_), _nt.Array1D[np.intp]) assert_type(np.intersect1d(AR_f8, AR_i_), _nt.Array1D[np.float64]) -assert_type(np.intersect1d(AR_M, AR_M, assume_unique=True), _nt.Array1D[np.datetime64]) +# mypy incorrectly infers this as "ndarray[Any, Any]" but pyright behaves correctly +assert_type(np.intersect1d(AR_M, AR_M, assume_unique=True), _nt.Array1D[np.datetime64]) # type: ignore[assert-type] assert_type( np.intersect1d(AR_f8, AR_f8, return_indices=True), tuple[_nt.Array1D[np.float64], _nt.Array1D[np.intp], _nt.Array1D[np.intp]], @@ -23,7 +24,8 @@ assert_type( assert_type(np.union1d(AR_i_, AR_i_), _nt.Array1D[np.intp]) assert_type(np.union1d(AR_f8, AR_i_), _nt.Array1D[np.float64]) -assert_type(np.union1d(AR_M, AR_M), _nt.Array1D[np.datetime64]) +# mypy incorrectly infers this as "ndarray[Any, Any]" but pyright behaves correctly +assert_type(np.union1d(AR_M, AR_M), _nt.Array1D[np.datetime64]) # type: ignore[assert-type] assert_type(np.ediff1d(AR_b), _nt.Array1D[np.int8]) assert_type(np.ediff1d(AR_M), _nt.Array1D[np.timedelta64]) @@ -33,11 +35,13 @@ assert_type(np.ediff1d(AR_LIKE_i_, to_begin=[0, 1]), _nt.Array1D[np.intp]) assert_type(np.setxor1d(AR_i_, AR_i_), _nt.Array1D[np.intp]) assert_type(np.setxor1d(AR_f8, AR_i_), _nt.Array1D[np.float64]) -assert_type(np.setxor1d(AR_M, AR_M, assume_unique=True), _nt.Array1D[np.datetime64]) +# mypy incorrectly infers this as "ndarray[Any, Any]" but pyright behaves correctly +assert_type(np.setxor1d(AR_M, AR_M, assume_unique=True), _nt.Array1D[np.datetime64]) # type: ignore[assert-type] assert_type(np.setdiff1d(AR_i_, AR_i_), _nt.Array1D[np.intp]) assert_type(np.setdiff1d(AR_f8, AR_i_), _nt.Array1D[np.float64]) -assert_type(np.setdiff1d(AR_M, AR_M, assume_unique=True), _nt.Array1D[np.datetime64]) +# mypy incorrectly infers this as "ndarray[Any, Any]" but pyright behaves correctly +assert_type(np.setdiff1d(AR_M, AR_M, assume_unique=True), _nt.Array1D[np.datetime64]) # type: ignore[assert-type] assert_type(np.isin(AR_i_, AR_i_), _nt.Array[np.bool]) assert_type(np.isin(AR_f8, AR_i_), _nt.Array[np.bool]) diff --git a/src/numpy-stubs/@test/static/accept/comparisons.pyi b/src/numpy-stubs/@test/static/accept/comparisons.pyi index 933351f1..0ef7674d 100644 --- a/src/numpy-stubs/@test/static/accept/comparisons.pyi +++ b/src/numpy-stubs/@test/static/accept/comparisons.pyi @@ -45,7 +45,8 @@ assert_type(i8 > [decimal.Decimal("1.5")], BoolND) ### # Time structures -assert_type(dt > dt, np.bool) +# mypy incorrectly infers this as "Any" but pyright behaves correctly +assert_type(dt > dt, np.bool) # type: ignore[assert-type] assert_type(td > td, np.bool) assert_type(td > i, np.bool) diff --git a/src/numpy-stubs/@test/static/accept/fromnumeric.pyi b/src/numpy-stubs/@test/static/accept/fromnumeric.pyi index e0801cae..e7c3f558 100644 --- a/src/numpy-stubs/@test/static/accept/fromnumeric.pyi +++ b/src/numpy-stubs/@test/static/accept/fromnumeric.pyi @@ -317,7 +317,8 @@ assert_type(np.around(AR_f4, out=AR_subclass), NDArraySubclass) assert_type(np.mean(AR_b1), np.floating) assert_type(np.mean(AR_i8), np.floating) assert_type(np.mean(AR_f4), np.floating) -assert_type(np.mean(AR_m), np.timedelta64) +# mypy incorrectly infers this as "Any" but pyright behaves correctly +assert_type(np.mean(AR_m), np.timedelta64) # type: ignore[assert-type] assert_type(np.mean(AR_c16), np.complexfloating) assert_type(np.mean(AR_O), Any) assert_type(np.mean(AR_f4, axis=0), Any) diff --git a/src/numpy-stubs/@test/static/accept/lib_function_base.pyi b/src/numpy-stubs/@test/static/accept/lib_function_base.pyi index 81b02da7..197f884b 100644 --- a/src/numpy-stubs/@test/static/accept/lib_function_base.pyi +++ b/src/numpy-stubs/@test/static/accept/lib_function_base.pyi @@ -139,7 +139,9 @@ assert_type(np.sinc(AR_c16), _nt.Array[np.complexfloating]) assert_type(np.median(AR_f8, keepdims=False), np.floating) assert_type(np.median(AR_c16, overwrite_input=True), np.complexfloating) -assert_type(np.median(AR_m), np.timedelta64) + +# mypy incorrectly infers this as "Any" but pyright behaves correctly +assert_type(np.median(AR_m), np.timedelta64) # type: ignore[assert-type] assert_type(np.median(AR_O), Any) assert_type(np.median(AR_f8, keepdims=True), Any) assert_type(np.median(AR_c16, axis=0), Any) @@ -204,7 +206,8 @@ assert_type(np.trapezoid(AR_i8, AR_f8), np.float64 | _nt.Array[np.float64]) assert_type(np.trapezoid(AR_f8, AR_i8), np.float64 | _nt.Array[np.float64]) assert_type(np.trapezoid(AR_c16), np.complex128 | _nt.Array[np.complex128]) assert_type(np.trapezoid(AR_c16, AR_c16), np.complex128 | _nt.Array[np.complex128]) -assert_type(np.trapezoid(AR_m), np.timedelta64 | _nt.Array[np.timedelta64]) +# mypy incorrectly infers this as "Any" but pyright behaves correctly +assert_type(np.trapezoid(AR_m), np.timedelta64 | _nt.Array[np.timedelta64]) # type: ignore[assert-type] assert_type(np.trapezoid(AR_O), Any) assert_type(np.trapezoid(AR_O, AR_LIKE_f), Any) diff --git a/src/numpy-stubs/@test/static/accept/mod.pyi b/src/numpy-stubs/@test/static/accept/mod.pyi index 876ed6b1..bed5f49f 100644 --- a/src/numpy-stubs/@test/static/accept/mod.pyi +++ b/src/numpy-stubs/@test/static/accept/mod.pyi @@ -32,8 +32,9 @@ AR_m: _nt.Array[np.timedelta64] assert_type(m % m, np.timedelta64) assert_type(m % m_nat, np.timedelta64[None]) assert_type(m % m_int0, np.timedelta64[None]) -assert_type(m % m_int, np.timedelta64[int | None]) -assert_type(m_nat % m, np.timedelta64[None]) +assert_type(m % m_int, np.timedelta64) +# mypy incorrectly infers this as "timedelta64[Any]", but pyright behaves correctly +assert_type(m_nat % m, np.timedelta64[None]) # type: ignore[assert-type] assert_type(m_int % m_nat, np.timedelta64[None]) assert_type(m_int % m_int0, np.timedelta64[None]) assert_type(m_int % m_int, np.timedelta64[int | None]) @@ -46,19 +47,22 @@ assert_type(m_td % m_td, np.timedelta64[dt.timedelta | None]) assert_type(AR_m % m, _nt.Array[np.timedelta64]) assert_type(m % AR_m, _nt.Array[np.timedelta64]) +# mypy incorrectly infers this as "tuple[Any, ...]", but pyright behaves correctly (surprisingly) +assert_type(divmod(m, m), tuple[np.int64, np.timedelta64]) # type: ignore[assert-type] +assert_type(divmod(m, m_nat), tuple[np.int64, np.timedelta64]) # type: ignore[assert-type] +assert_type(divmod(m, m_int0), tuple[np.int64, np.timedelta64]) # type: ignore[assert-type] +assert_type(divmod(m, m_int), tuple[np.int64, np.timedelta64]) +# mypy incorrectly infers this as "tuple[Any, ...]" but pyright behaves correctly +assert_type(divmod(m_nat, m), tuple[np.int64, np.timedelta64[None]]) # type: ignore[assert-type] +assert_type(divmod(m_int, m_nat), tuple[np.int64, np.timedelta64[None]]) +assert_type(divmod(m_int, m_int0), tuple[np.int64, np.timedelta64[None]]) + # NOTE: The pyright ignores are the consequence of a pernicious bug in pyright # (microsoft/pyright#9896, microsoft/pyright#10849, microsoft/pyright#10899) that # causes incorrect behavior in certain functions that accept generic protocols with # overloaded methods. Even though mypy also isn't fully correct here, it will at least # not falsely reject valid calls, and has no problems with any of the following tests. -assert_type(divmod(m, m), tuple[np.int64, np.timedelta64]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue] -assert_type(divmod(m, m_nat), tuple[np.int64, np.timedelta64[None]]) -assert_type(divmod(m, m_int0), tuple[np.int64, np.timedelta64[None]]) -assert_type(divmod(m, m_int), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue] -assert_type(divmod(m_nat, m), tuple[np.int64, np.timedelta64[None]]) -assert_type(divmod(m_int, m_nat), tuple[np.int64, np.timedelta64[None]]) -assert_type(divmod(m_int, m_int0), tuple[np.int64, np.timedelta64[None]]) assert_type(divmod(m_int, m_int), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue] assert_type(divmod(m_int, m_td), tuple[np.int64, np.timedelta64[int | None]]) # pyright: ignore[reportArgumentType, reportAssertTypeFailure, reportCallIssue] assert_type(divmod(m_td, m_nat), tuple[np.int64, np.timedelta64[None]]) diff --git a/src/numpy-stubs/@test/static/accept/multiarray.pyi b/src/numpy-stubs/@test/static/accept/multiarray.pyi index d2c5db78..5b34540c 100644 --- a/src/numpy-stubs/@test/static/accept/multiarray.pyi +++ b/src/numpy-stubs/@test/static/accept/multiarray.pyi @@ -157,9 +157,10 @@ assert_type(np.busday_count("2011-01", "2011-02"), np.int_) assert_type(np.busday_count(["2011-01"], "2011-02"), _nt.Array[np.int_]) assert_type(np.busday_count(["2011-01"], date_scalar), _nt.Array[np.int_]) -assert_type(np.busday_offset(date_scalar, m), np.datetime64[dt.datetime]) -assert_type(np.busday_offset(M, m), np.datetime64[dt.datetime]) -assert_type(np.busday_offset(M, 5), np.datetime64[dt.datetime]) +# mypy incorrectly infers this as "Any" but pyright behaves correctly +assert_type(np.busday_offset(date_scalar, m), np.datetime64[dt.datetime]) # type: ignore[assert-type] +assert_type(np.busday_offset(M, m), np.datetime64[dt.datetime]) # type: ignore[assert-type] +assert_type(np.busday_offset(M, 5), np.datetime64[dt.datetime]) # type: ignore[assert-type] assert_type(np.busday_offset(AR_M, m), _nt.Array[np.datetime64[dt.datetime]]) assert_type(np.busday_offset(M, timedelta_seq), _nt.Array[np.datetime64[dt.datetime]]) assert_type(np.busday_offset("2011-01", 1, roll="forward"), np.datetime64[dt.datetime]) diff --git a/src/numpy-stubs/@test/static/accept/numeric.pyi b/src/numpy-stubs/@test/static/accept/numeric.pyi index bfff3261..94ca4187 100644 --- a/src/numpy-stubs/@test/static/accept/numeric.pyi +++ b/src/numpy-stubs/@test/static/accept/numeric.pyi @@ -44,7 +44,8 @@ assert_type(np.correlate(AR_b, AR_u8), _nt.Array1D[np.unsignedinteger]) assert_type(np.correlate(AR_i8, AR_b), _nt.Array1D[np.signedinteger]) assert_type(np.correlate(AR_i8, AR_f8), _nt.Array1D[np.floating]) assert_type(np.correlate(AR_i8, AR_c16), _nt.Array1D[np.complexfloating]) -assert_type(np.correlate(AR_i8, AR_m), _nt.Array1D[np.timedelta64]) +# mypy incorrectly infers this as "ndarray[Any, Any]", but pyright behaves correctly +assert_type(np.correlate(AR_i8, AR_m), _nt.Array1D[np.timedelta64]) # type: ignore[assert-type] assert_type(np.correlate(AR_O, AR_O), _nt.Array1D[np.object_]) assert_type(np.convolve(ints, AR_i8, mode="valid"), _nt.Array1D[np.signedinteger]) @@ -54,7 +55,8 @@ assert_type(np.convolve(AR_b, AR_u8), _nt.Array1D[np.unsignedinteger]) assert_type(np.convolve(AR_i8, AR_b), _nt.Array1D[np.signedinteger]) assert_type(np.convolve(AR_i8, AR_f8), _nt.Array1D[np.floating]) assert_type(np.convolve(AR_i8, AR_c16), _nt.Array1D[np.complexfloating]) -assert_type(np.convolve(AR_i8, AR_m), _nt.Array1D[np.timedelta64]) +# mypy incorrectly infers this as "ndarray[Any, Any]", but pyright behaves correctly +assert_type(np.convolve(AR_i8, AR_m), _nt.Array1D[np.timedelta64]) # type: ignore[assert-type] assert_type(np.convolve(AR_O, AR_O), _nt.Array1D[np.object_]) assert_type(np.outer(i8, AR_i8), _nt.Array2D[np.signedinteger]) @@ -78,7 +80,8 @@ assert_type(np.tensordot(AR_b, AR_u8), _nt.Array[np.unsignedinteger]) assert_type(np.tensordot(AR_i8, AR_b), _nt.Array[np.signedinteger]) assert_type(np.tensordot(AR_i8, AR_f8), _nt.Array[np.floating]) assert_type(np.tensordot(AR_i8, AR_c16), _nt.Array[np.complexfloating]) -assert_type(np.tensordot(AR_i8, AR_m), _nt.Array[np.timedelta64]) +# mypy incorrectly infers this as "ndarray[Any, Any]", but pyright behaves correctly +assert_type(np.tensordot(AR_i8, AR_m), _nt.Array[np.timedelta64]) # type: ignore[assert-type] assert_type(np.tensordot(AR_O, AR_O), _nt.Array[np.object_]) assert_type(np.isscalar(i8), bool) diff --git a/src/numpy-stubs/@test/static/accept/ufuncs.pyi b/src/numpy-stubs/@test/static/accept/ufuncs.pyi index 95ec5a11..83ab9c2c 100644 --- a/src/numpy-stubs/@test/static/accept/ufuncs.pyi +++ b/src/numpy-stubs/@test/static/accept/ufuncs.pyi @@ -51,10 +51,11 @@ assert_type(np.isnat(dt64), np.bool_) assert_type(np.isnat(td64), np.bool_) assert_type(np.isnat([td64, td64]), _nt.Array[np.bool_]) assert_type(np.isnat([td64, td64], out=AR_bool), _nt.Array[np.bool_]) -assert_type(np.isnat(AR_dt64), _nt.Array[np.bool_]) -assert_type(np.isnat(AR_td64), _nt.Array[np.bool_]) -assert_type(np.isnat(AR_dt64, out=AR_bool), _nt.Array[np.bool_]) -assert_type(np.isnat(AR_td64, out=AR_bool), _nt.Array[np.bool_]) +# mypy incorrectly infers the return type as "Any" here, but pyright is correct +assert_type(np.isnat(AR_dt64), _nt.Array[np.bool_]) # type: ignore[assert-type] +assert_type(np.isnat(AR_td64), _nt.Array[np.bool_]) # type: ignore[assert-type] +assert_type(np.isnat(AR_dt64, out=AR_bool), _nt.Array[np.bool_]) # type: ignore[assert-type] +assert_type(np.isnat(AR_td64, out=AR_bool), _nt.Array[np.bool_]) # type: ignore[assert-type] assert_type(np.isinf(f8), np.bool_) assert_type(np.isinf(AR_f8), _nt.Array[np.bool_]) diff --git a/src/numpy-stubs/@test/static/reject/arithmetic.pyi b/src/numpy-stubs/@test/static/reject/arithmetic.pyi index 401dfc35..187e374e 100644 --- a/src/numpy-stubs/@test/static/reject/arithmetic.pyi +++ b/src/numpy-stubs/@test/static/reject/arithmetic.pyi @@ -43,12 +43,7 @@ AR_LIKE_m - AR_M # type: ignore[operator] # pyright: ignore[reportOperatorIssu # array floor division -AR_M // AR_LIKE_b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] -AR_M // AR_LIKE_u # type: ignore[operator] # pyright: ignore[reportOperatorIssue] -AR_M // AR_LIKE_i # type: ignore[operator] # pyright: ignore[reportOperatorIssue] -AR_M // AR_LIKE_f # type: ignore[operator] # pyright: ignore[reportOperatorIssue] AR_M // AR_LIKE_c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] -AR_M // AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue] AR_M // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue] AR_b // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue] @@ -59,7 +54,6 @@ AR_c // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIss AR_m // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue] AR_M // AR_LIKE_M # type: ignore[operator] # pyright: ignore[reportOperatorIssue] -AR_m // AR_LIKE_b # type: ignore[operator] # pyright: ignore[reportOperatorIssue] AR_m // AR_LIKE_c # type: ignore[operator] # pyright: ignore[reportOperatorIssue] AR_b // AR_LIKE_m # type: ignore[operator] # pyright: ignore[reportOperatorIssue] From 987a7aea6db9b0f19a3fe308141e53d94429b856 Mon Sep 17 00:00:00 2001 From: jorenham Date: Wed, 24 Dec 2025 23:24:35 +0100 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=90=B4=20workarounds=20for=20mypy=20b?= =?UTF-8?q?ugs=20in=20the=20generated=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../@test/generated/scalar_ops_comparison.pyi | 108 ++++++++++++------ tool/testgen.py | 15 ++- 2 files changed, 88 insertions(+), 35 deletions(-) diff --git a/src/numpy-stubs/@test/generated/scalar_ops_comparison.pyi b/src/numpy-stubs/@test/generated/scalar_ops_comparison.pyi index 24a012c0..4dbdd43b 100644 --- a/src/numpy-stubs/@test/generated/scalar_ops_comparison.pyi +++ b/src/numpy-stubs/@test/generated/scalar_ops_comparison.pyi @@ -1,4 +1,4 @@ -# @generated 2025-05-03T21:24:40Z with tool/testgen.py +# @generated 2025-12-24T22:19:45Z with tool/testgen.py from typing import assert_type import numpy as np @@ -497,7 +497,7 @@ assert_type(c128l < iu, np.bool) assert_type(c128l < fc, np.bool) assert_type(c128l < iufc, np.bool) -assert_type(M64 < M64, np.bool) +assert_type(M64 < M64, np.bool) # type: ignore[assert-type] assert_type(m64 < b_py, np.bool) assert_type(m64 < i_py, np.bool) @@ -1168,7 +1168,7 @@ assert_type(c128l <= iu, np.bool) assert_type(c128l <= fc, np.bool) assert_type(c128l <= iufc, np.bool) -assert_type(M64 <= M64, np.bool) +assert_type(M64 <= M64, np.bool) # type: ignore[assert-type] assert_type(m64 <= b_py, np.bool) assert_type(m64 <= i_py, np.bool) @@ -1839,7 +1839,7 @@ assert_type(c128l >= iu, np.bool) assert_type(c128l >= fc, np.bool) assert_type(c128l >= iufc, np.bool) -assert_type(M64 >= M64, np.bool) +assert_type(M64 >= M64, np.bool) # type: ignore[assert-type] assert_type(m64 >= b_py, np.bool) assert_type(m64 >= i_py, np.bool) @@ -2510,7 +2510,7 @@ assert_type(c128l > iu, np.bool) assert_type(c128l > fc, np.bool) assert_type(c128l > iufc, np.bool) -assert_type(M64 > M64, np.bool) +assert_type(M64 > M64, np.bool) # type: ignore[assert-type] assert_type(m64 > b_py, np.bool) assert_type(m64 > i_py, np.bool) @@ -2745,7 +2745,7 @@ assert_type(b1 == f64l, np.bool) assert_type(b1 == c64, np.bool) assert_type(b1 == c128, np.bool) assert_type(b1 == c128l, np.bool) -assert_type(b1 == m64, np.bool) +assert_type(b1 == m64, np.bool) # type: ignore[assert-type] assert_type(i8 == b_py, np.bool) assert_type(i8 == i_py, np.bool) @@ -2767,7 +2767,7 @@ assert_type(i8 == f64l, np.bool) assert_type(i8 == c64, np.bool) assert_type(i8 == c128, np.bool) assert_type(i8 == c128l, np.bool) -assert_type(i8 == m64, np.bool) +assert_type(i8 == m64, np.bool) # type: ignore[assert-type] assert_type(i16 == b_py, np.bool) assert_type(i16 == i_py, np.bool) @@ -2789,7 +2789,7 @@ assert_type(i16 == f64l, np.bool) assert_type(i16 == c64, np.bool) assert_type(i16 == c128, np.bool) assert_type(i16 == c128l, np.bool) -assert_type(i16 == m64, np.bool) +assert_type(i16 == m64, np.bool) # type: ignore[assert-type] assert_type(i32 == b_py, np.bool) assert_type(i32 == i_py, np.bool) @@ -2811,7 +2811,7 @@ assert_type(i32 == f64l, np.bool) assert_type(i32 == c64, np.bool) assert_type(i32 == c128, np.bool) assert_type(i32 == c128l, np.bool) -assert_type(i32 == m64, np.bool) +assert_type(i32 == m64, np.bool) # type: ignore[assert-type] assert_type(i64 == b_py, np.bool) assert_type(i64 == i_py, np.bool) @@ -2833,7 +2833,7 @@ assert_type(i64 == f64l, np.bool) assert_type(i64 == c64, np.bool) assert_type(i64 == c128, np.bool) assert_type(i64 == c128l, np.bool) -assert_type(i64 == m64, np.bool) +assert_type(i64 == m64, np.bool) # type: ignore[assert-type] assert_type(u8 == b_py, np.bool) assert_type(u8 == i_py, np.bool) @@ -2855,7 +2855,7 @@ assert_type(u8 == f64l, np.bool) assert_type(u8 == c64, np.bool) assert_type(u8 == c128, np.bool) assert_type(u8 == c128l, np.bool) -assert_type(u8 == m64, np.bool) +assert_type(u8 == m64, np.bool) # type: ignore[assert-type] assert_type(u16 == b_py, np.bool) assert_type(u16 == i_py, np.bool) @@ -2877,7 +2877,7 @@ assert_type(u16 == f64l, np.bool) assert_type(u16 == c64, np.bool) assert_type(u16 == c128, np.bool) assert_type(u16 == c128l, np.bool) -assert_type(u16 == m64, np.bool) +assert_type(u16 == m64, np.bool) # type: ignore[assert-type] assert_type(u32 == b_py, np.bool) assert_type(u32 == i_py, np.bool) @@ -2899,7 +2899,7 @@ assert_type(u32 == f64l, np.bool) assert_type(u32 == c64, np.bool) assert_type(u32 == c128, np.bool) assert_type(u32 == c128l, np.bool) -assert_type(u32 == m64, np.bool) +assert_type(u32 == m64, np.bool) # type: ignore[assert-type] assert_type(u64 == b_py, np.bool) assert_type(u64 == i_py, np.bool) @@ -2921,6 +2921,7 @@ assert_type(u64 == f64l, np.bool) assert_type(u64 == c64, np.bool) assert_type(u64 == c128, np.bool) assert_type(u64 == c128l, np.bool) +assert_type(u64 == m64, np.bool) # type: ignore[assert-type] assert_type(f16 == b_py, np.bool) assert_type(f16 == i_py, np.bool) @@ -2942,6 +2943,7 @@ assert_type(f16 == f64l, np.bool) assert_type(f16 == c64, np.bool) assert_type(f16 == c128, np.bool) assert_type(f16 == c128l, np.bool) +assert_type(f16 == m64, np.bool) # type: ignore[assert-type] assert_type(f32 == b_py, np.bool) assert_type(f32 == i_py, np.bool) @@ -2963,6 +2965,7 @@ assert_type(f32 == f64l, np.bool) assert_type(f32 == c64, np.bool) assert_type(f32 == c128, np.bool) assert_type(f32 == c128l, np.bool) +assert_type(f32 == m64, np.bool) # type: ignore[assert-type] assert_type(f64 == b_py, np.bool) assert_type(f64 == i_py, np.bool) @@ -2984,6 +2987,7 @@ assert_type(f64 == f64l, np.bool) assert_type(f64 == c64, np.bool) assert_type(f64 == c128, np.bool) assert_type(f64 == c128l, np.bool) +assert_type(f64 == m64, np.bool) # type: ignore[assert-type] assert_type(f64l == b_py, np.bool) assert_type(f64l == i_py, np.bool) @@ -3005,6 +3009,7 @@ assert_type(f64l == f64l, np.bool) assert_type(f64l == c64, np.bool) assert_type(f64l == c128, np.bool) assert_type(f64l == c128l, np.bool) +assert_type(f64l == m64, np.bool) # type: ignore[assert-type] assert_type(c64 == b_py, np.bool) assert_type(c64 == i_py, np.bool) @@ -3026,6 +3031,7 @@ assert_type(c64 == f64l, np.bool) assert_type(c64 == c64, np.bool) assert_type(c64 == c128, np.bool) assert_type(c64 == c128l, np.bool) +assert_type(c64 == m64, np.bool) # type: ignore[assert-type] assert_type(c128 == b_py, np.bool) assert_type(c128 == i_py, np.bool) @@ -3047,6 +3053,7 @@ assert_type(c128 == f64l, np.bool) assert_type(c128 == c64, np.bool) assert_type(c128 == c128, np.bool) assert_type(c128 == c128l, np.bool) +assert_type(c128 == m64, np.bool) # type: ignore[assert-type] assert_type(c128l == b_py, np.bool) assert_type(c128l == i_py, np.bool) @@ -3068,11 +3075,14 @@ assert_type(c128l == f64l, np.bool) assert_type(c128l == c64, np.bool) assert_type(c128l == c128, np.bool) assert_type(c128l == c128l, np.bool) +assert_type(c128l == m64, np.bool) # type: ignore[assert-type] -assert_type(M64 == M64, np.bool) +assert_type(M64 == M64, np.bool) # type: ignore[assert-type] assert_type(m64 == b_py, np.bool) assert_type(m64 == i_py, np.bool) +assert_type(m64 == f_py, np.bool) +assert_type(m64 == c_py, np.bool) assert_type(m64 == b1, np.bool) assert_type(m64 == i8, np.bool) assert_type(m64 == i16, np.bool) @@ -3081,7 +3091,15 @@ assert_type(m64 == i64, np.bool) assert_type(m64 == u8, np.bool) assert_type(m64 == u16, np.bool) assert_type(m64 == u32, np.bool) -assert_type(m64 == m64, np.bool) +assert_type(m64 == u64, np.bool) +assert_type(m64 == f16, np.bool) +assert_type(m64 == f32, np.bool) +assert_type(m64 == f64, np.bool) +assert_type(m64 == f64l, np.bool) +assert_type(m64 == c64, np.bool) +assert_type(m64 == c128, np.bool) +assert_type(m64 == c128l, np.bool) +assert_type(m64 == m64, np.bool) # type: ignore[assert-type] assert_type(i == b_py, np.bool) assert_type(i == i_py, np.bool) @@ -3103,7 +3121,7 @@ assert_type(i == f64l, np.bool) assert_type(i == c64, np.bool) assert_type(i == c128, np.bool) assert_type(i == c128l, np.bool) -assert_type(i == m64, np.bool) +assert_type(i == m64, np.bool) # type: ignore[assert-type] assert_type(u == b_py, np.bool) assert_type(u == i_py, np.bool) @@ -3125,7 +3143,7 @@ assert_type(u == f64l, np.bool) assert_type(u == c64, np.bool) assert_type(u == c128, np.bool) assert_type(u == c128l, np.bool) -assert_type(u == m64, np.bool) +assert_type(u == m64, np.bool) # type: ignore[assert-type] assert_type(f == b_py, np.bool) assert_type(f == i_py, np.bool) @@ -3147,6 +3165,7 @@ assert_type(f == f64l, np.bool) assert_type(f == c64, np.bool) assert_type(f == c128, np.bool) assert_type(f == c128l, np.bool) +assert_type(f == m64, np.bool) # type: ignore[assert-type] assert_type(c == b_py, np.bool) assert_type(c == i_py, np.bool) @@ -3168,6 +3187,7 @@ assert_type(c == f64l, np.bool) assert_type(c == c64, np.bool) assert_type(c == c128, np.bool) assert_type(c == c128l, np.bool) +assert_type(c == m64, np.bool) # type: ignore[assert-type] assert_type(iu == b_py, np.bool) assert_type(iu == i_py, np.bool) @@ -3189,7 +3209,7 @@ assert_type(iu == f64l, np.bool) assert_type(iu == c64, np.bool) assert_type(iu == c128, np.bool) assert_type(iu == c128l, np.bool) -assert_type(iu == m64, np.bool) +assert_type(iu == m64, np.bool) # type: ignore[assert-type] assert_type(fc == b_py, np.bool) assert_type(fc == i_py, np.bool) @@ -3211,6 +3231,7 @@ assert_type(fc == f64l, np.bool) assert_type(fc == c64, np.bool) assert_type(fc == c128, np.bool) assert_type(fc == c128l, np.bool) +assert_type(fc == m64, np.bool) # type: ignore[assert-type] assert_type(iufc == b_py, np.bool) assert_type(iufc == i_py, np.bool) @@ -3232,7 +3253,7 @@ assert_type(iufc == f64l, np.bool) assert_type(iufc == c64, np.bool) assert_type(iufc == c128, np.bool) assert_type(iufc == c128l, np.bool) -assert_type(iufc == m64, np.bool) +assert_type(iufc == m64, np.bool) # type: ignore[assert-type] ### # __[r]ne__ @@ -3257,7 +3278,7 @@ assert_type(b1 != f64l, np.bool) assert_type(b1 != c64, np.bool) assert_type(b1 != c128, np.bool) assert_type(b1 != c128l, np.bool) -assert_type(b1 != m64, np.bool) +assert_type(b1 != m64, np.bool) # type: ignore[assert-type] assert_type(i8 != b_py, np.bool) assert_type(i8 != i_py, np.bool) @@ -3279,7 +3300,7 @@ assert_type(i8 != f64l, np.bool) assert_type(i8 != c64, np.bool) assert_type(i8 != c128, np.bool) assert_type(i8 != c128l, np.bool) -assert_type(i8 != m64, np.bool) +assert_type(i8 != m64, np.bool) # type: ignore[assert-type] assert_type(i16 != b_py, np.bool) assert_type(i16 != i_py, np.bool) @@ -3301,7 +3322,7 @@ assert_type(i16 != f64l, np.bool) assert_type(i16 != c64, np.bool) assert_type(i16 != c128, np.bool) assert_type(i16 != c128l, np.bool) -assert_type(i16 != m64, np.bool) +assert_type(i16 != m64, np.bool) # type: ignore[assert-type] assert_type(i32 != b_py, np.bool) assert_type(i32 != i_py, np.bool) @@ -3323,7 +3344,7 @@ assert_type(i32 != f64l, np.bool) assert_type(i32 != c64, np.bool) assert_type(i32 != c128, np.bool) assert_type(i32 != c128l, np.bool) -assert_type(i32 != m64, np.bool) +assert_type(i32 != m64, np.bool) # type: ignore[assert-type] assert_type(i64 != b_py, np.bool) assert_type(i64 != i_py, np.bool) @@ -3345,7 +3366,7 @@ assert_type(i64 != f64l, np.bool) assert_type(i64 != c64, np.bool) assert_type(i64 != c128, np.bool) assert_type(i64 != c128l, np.bool) -assert_type(i64 != m64, np.bool) +assert_type(i64 != m64, np.bool) # type: ignore[assert-type] assert_type(u8 != b_py, np.bool) assert_type(u8 != i_py, np.bool) @@ -3367,7 +3388,7 @@ assert_type(u8 != f64l, np.bool) assert_type(u8 != c64, np.bool) assert_type(u8 != c128, np.bool) assert_type(u8 != c128l, np.bool) -assert_type(u8 != m64, np.bool) +assert_type(u8 != m64, np.bool) # type: ignore[assert-type] assert_type(u16 != b_py, np.bool) assert_type(u16 != i_py, np.bool) @@ -3389,7 +3410,7 @@ assert_type(u16 != f64l, np.bool) assert_type(u16 != c64, np.bool) assert_type(u16 != c128, np.bool) assert_type(u16 != c128l, np.bool) -assert_type(u16 != m64, np.bool) +assert_type(u16 != m64, np.bool) # type: ignore[assert-type] assert_type(u32 != b_py, np.bool) assert_type(u32 != i_py, np.bool) @@ -3411,7 +3432,7 @@ assert_type(u32 != f64l, np.bool) assert_type(u32 != c64, np.bool) assert_type(u32 != c128, np.bool) assert_type(u32 != c128l, np.bool) -assert_type(u32 != m64, np.bool) +assert_type(u32 != m64, np.bool) # type: ignore[assert-type] assert_type(u64 != b_py, np.bool) assert_type(u64 != i_py, np.bool) @@ -3433,6 +3454,7 @@ assert_type(u64 != f64l, np.bool) assert_type(u64 != c64, np.bool) assert_type(u64 != c128, np.bool) assert_type(u64 != c128l, np.bool) +assert_type(u64 != m64, np.bool) # type: ignore[assert-type] assert_type(f16 != b_py, np.bool) assert_type(f16 != i_py, np.bool) @@ -3454,6 +3476,7 @@ assert_type(f16 != f64l, np.bool) assert_type(f16 != c64, np.bool) assert_type(f16 != c128, np.bool) assert_type(f16 != c128l, np.bool) +assert_type(f16 != m64, np.bool) # type: ignore[assert-type] assert_type(f32 != b_py, np.bool) assert_type(f32 != i_py, np.bool) @@ -3475,6 +3498,7 @@ assert_type(f32 != f64l, np.bool) assert_type(f32 != c64, np.bool) assert_type(f32 != c128, np.bool) assert_type(f32 != c128l, np.bool) +assert_type(f32 != m64, np.bool) # type: ignore[assert-type] assert_type(f64 != b_py, np.bool) assert_type(f64 != i_py, np.bool) @@ -3496,6 +3520,7 @@ assert_type(f64 != f64l, np.bool) assert_type(f64 != c64, np.bool) assert_type(f64 != c128, np.bool) assert_type(f64 != c128l, np.bool) +assert_type(f64 != m64, np.bool) # type: ignore[assert-type] assert_type(f64l != b_py, np.bool) assert_type(f64l != i_py, np.bool) @@ -3517,6 +3542,7 @@ assert_type(f64l != f64l, np.bool) assert_type(f64l != c64, np.bool) assert_type(f64l != c128, np.bool) assert_type(f64l != c128l, np.bool) +assert_type(f64l != m64, np.bool) # type: ignore[assert-type] assert_type(c64 != b_py, np.bool) assert_type(c64 != i_py, np.bool) @@ -3538,6 +3564,7 @@ assert_type(c64 != f64l, np.bool) assert_type(c64 != c64, np.bool) assert_type(c64 != c128, np.bool) assert_type(c64 != c128l, np.bool) +assert_type(c64 != m64, np.bool) # type: ignore[assert-type] assert_type(c128 != b_py, np.bool) assert_type(c128 != i_py, np.bool) @@ -3559,6 +3586,7 @@ assert_type(c128 != f64l, np.bool) assert_type(c128 != c64, np.bool) assert_type(c128 != c128, np.bool) assert_type(c128 != c128l, np.bool) +assert_type(c128 != m64, np.bool) # type: ignore[assert-type] assert_type(c128l != b_py, np.bool) assert_type(c128l != i_py, np.bool) @@ -3580,11 +3608,14 @@ assert_type(c128l != f64l, np.bool) assert_type(c128l != c64, np.bool) assert_type(c128l != c128, np.bool) assert_type(c128l != c128l, np.bool) +assert_type(c128l != m64, np.bool) # type: ignore[assert-type] -assert_type(M64 != M64, np.bool) +assert_type(M64 != M64, np.bool) # type: ignore[assert-type] assert_type(m64 != b_py, np.bool) assert_type(m64 != i_py, np.bool) +assert_type(m64 != f_py, np.bool) +assert_type(m64 != c_py, np.bool) assert_type(m64 != b1, np.bool) assert_type(m64 != i8, np.bool) assert_type(m64 != i16, np.bool) @@ -3593,7 +3624,15 @@ assert_type(m64 != i64, np.bool) assert_type(m64 != u8, np.bool) assert_type(m64 != u16, np.bool) assert_type(m64 != u32, np.bool) -assert_type(m64 != m64, np.bool) +assert_type(m64 != u64, np.bool) +assert_type(m64 != f16, np.bool) +assert_type(m64 != f32, np.bool) +assert_type(m64 != f64, np.bool) +assert_type(m64 != f64l, np.bool) +assert_type(m64 != c64, np.bool) +assert_type(m64 != c128, np.bool) +assert_type(m64 != c128l, np.bool) +assert_type(m64 != m64, np.bool) # type: ignore[assert-type] assert_type(i != b_py, np.bool) assert_type(i != i_py, np.bool) @@ -3615,7 +3654,7 @@ assert_type(i != f64l, np.bool) assert_type(i != c64, np.bool) assert_type(i != c128, np.bool) assert_type(i != c128l, np.bool) -assert_type(i != m64, np.bool) +assert_type(i != m64, np.bool) # type: ignore[assert-type] assert_type(u != b_py, np.bool) assert_type(u != i_py, np.bool) @@ -3637,7 +3676,7 @@ assert_type(u != f64l, np.bool) assert_type(u != c64, np.bool) assert_type(u != c128, np.bool) assert_type(u != c128l, np.bool) -assert_type(u != m64, np.bool) +assert_type(u != m64, np.bool) # type: ignore[assert-type] assert_type(f != b_py, np.bool) assert_type(f != i_py, np.bool) @@ -3659,6 +3698,7 @@ assert_type(f != f64l, np.bool) assert_type(f != c64, np.bool) assert_type(f != c128, np.bool) assert_type(f != c128l, np.bool) +assert_type(f != m64, np.bool) # type: ignore[assert-type] assert_type(c != b_py, np.bool) assert_type(c != i_py, np.bool) @@ -3680,6 +3720,7 @@ assert_type(c != f64l, np.bool) assert_type(c != c64, np.bool) assert_type(c != c128, np.bool) assert_type(c != c128l, np.bool) +assert_type(c != m64, np.bool) # type: ignore[assert-type] assert_type(iu != b_py, np.bool) assert_type(iu != i_py, np.bool) @@ -3701,7 +3742,7 @@ assert_type(iu != f64l, np.bool) assert_type(iu != c64, np.bool) assert_type(iu != c128, np.bool) assert_type(iu != c128l, np.bool) -assert_type(iu != m64, np.bool) +assert_type(iu != m64, np.bool) # type: ignore[assert-type] assert_type(fc != b_py, np.bool) assert_type(fc != i_py, np.bool) @@ -3723,6 +3764,7 @@ assert_type(fc != f64l, np.bool) assert_type(fc != c64, np.bool) assert_type(fc != c128, np.bool) assert_type(fc != c128l, np.bool) +assert_type(fc != m64, np.bool) # type: ignore[assert-type] assert_type(iufc != b_py, np.bool) assert_type(iufc != i_py, np.bool) @@ -3744,4 +3786,4 @@ assert_type(iufc != f64l, np.bool) assert_type(iufc != c64, np.bool) assert_type(iufc != c128, np.bool) assert_type(iufc != c128l, np.bool) -assert_type(iufc != m64, np.bool) +assert_type(iufc != m64, np.bool) # type: ignore[assert-type] diff --git a/tool/testgen.py b/tool/testgen.py index 031a77a2..6c5c0caf 100644 --- a/tool/testgen.py +++ b/tool/testgen.py @@ -945,7 +945,7 @@ class ScalarOps(TestGen): # temporal "M": "M64", "m": "m64", - # # abstract numeric + # abstract numeric "bhil": "i", # signedinteger "BHIL": "u", # unsignedinteger "efdg": "f", # floating @@ -1103,7 +1103,18 @@ def _assert_stmt(self, op: str, lhs: str, rhs: str, /) -> str | None: if expr_type == "bool": return None - return _expr_assert_type(expr_eval, expr_type) + result = _expr_assert_type(expr_eval, expr_type) + + if "comparison" in self.testname: + # probably not needed, but for some reason this is needed + if "M" in {lhs, rhs} and lhs != rhs: + return None + + # workaround a mypy bug related to the datetime64/timedelta64[Any] defaults + if rhs == "M" or (rhs == "m" and ("==" in op or "!=" in op)): + result += " # type: ignore[assert-type]" + + return result @override def _generate_names_section(self) -> Generator[str]: From 944e2b73baedea90a6dfa69c7cf91075fd6c0c73 Mon Sep 17 00:00:00 2001 From: jorenham Date: Thu, 25 Dec 2025 11:50:03 +0100 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=90=B4=20workaround=20for=20yet=20ano?= =?UTF-8?q?ther=20mypy=20=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/numpy-stubs/@test/generated/scalar_ops_modular.pyi | 4 ++-- tool/testgen.py | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/numpy-stubs/@test/generated/scalar_ops_modular.pyi b/src/numpy-stubs/@test/generated/scalar_ops_modular.pyi index 39d25742..8d7208cf 100644 --- a/src/numpy-stubs/@test/generated/scalar_ops_modular.pyi +++ b/src/numpy-stubs/@test/generated/scalar_ops_modular.pyi @@ -1,4 +1,4 @@ -# @generated 2025-09-17T13:49:06Z with tool/testgen.py +# @generated 2025-12-25T10:48:48Z with tool/testgen.py from typing import assert_type import numpy as np @@ -1628,7 +1628,7 @@ divmod(m64, f32) # type: ignore[operator] # pyright: ignore[reportArgumentType divmod(m64, f64) # type: ignore[operator] # pyright: ignore[reportArgumentType, reportCallIssue] divmod(m64, f64l) # type: ignore[operator] # pyright: ignore[reportArgumentType, reportCallIssue] divmod(m64, c128) # type: ignore[operator] # pyright: ignore[reportArgumentType, reportCallIssue] -assert_type(m64.__divmod__(m64), tuple[np.int64, np.timedelta64]) +assert_type(m64.__divmod__(m64), tuple[np.int64, np.timedelta64]) # type: ignore[assert-type] divmod(m64, i) # type: ignore[operator] # pyright: ignore[reportArgumentType, reportCallIssue] divmod(m64, u) # type: ignore[operator] # pyright: ignore[reportArgumentType, reportCallIssue] divmod(m64, f) # type: ignore[operator] # pyright: ignore[reportArgumentType, reportCallIssue] diff --git a/tool/testgen.py b/tool/testgen.py index 6c5c0caf..5bd1bfc0 100644 --- a/tool/testgen.py +++ b/tool/testgen.py @@ -1048,7 +1048,7 @@ def _evaluate(self, op: str, lhs: str, rhs: str, /) -> str | None: return f"tuple[{', '.join(result_exprs)}]" if nout > 1 else result_exprs[0] - def _assert_stmt(self, op: str, lhs: str, rhs: str, /) -> str | None: + def _assert_stmt(self, op: str, lhs: str, rhs: str, /) -> str | None: # noqa: C901 # ugly workaround for microsoft/pyright#9896 and microsoft/pyright#10899 if ( op.startswith("divmod") @@ -1114,6 +1114,10 @@ def _assert_stmt(self, op: str, lhs: str, rhs: str, /) -> str | None: if rhs == "M" or (rhs == "m" and ("==" in op or "!=" in op)): result += " # type: ignore[assert-type]" + # yet another mypy workaround + if op.startswith("divmod") and lhs == rhs == "m": + result += " # type: ignore[assert-type]" + return result @override