From 9f52ec579d61203a04807a05954a3ee58873b7b6 Mon Sep 17 00:00:00 2001 From: Bas van Beek Date: Sun, 27 Dec 2020 04:38:19 +0100 Subject: [PATCH 1/5] ENH: Added `_ArrayLikeNumber` --- numpy/typing/__init__.py | 1 + numpy/typing/_array_like.py | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/numpy/typing/__init__.py b/numpy/typing/__init__.py index a1d943235115..dd506987e6db 100644 --- a/numpy/typing/__init__.py +++ b/numpy/typing/__init__.py @@ -308,6 +308,7 @@ class _8Bit(_16Bit): ... # type: ignore[misc] _ArrayLikeInt_co, _ArrayLikeFloat_co, _ArrayLikeComplex_co, + _ArrayLikeNumber_co, _ArrayLikeTD64_co, _ArrayLikeDT64_co, _ArrayLikeObject_co, diff --git a/numpy/typing/_array_like.py b/numpy/typing/_array_like.py index 35413393c33a..d40cb31936e7 100644 --- a/numpy/typing/_array_like.py +++ b/numpy/typing/_array_like.py @@ -12,6 +12,7 @@ integer, floating, complexfloating, + number, timedelta64, datetime64, object_, @@ -100,6 +101,10 @@ def __array__(self, dtype: None = ...) -> ndarray[Any, _DType]: ... "dtype[Union[bool_, integer[Any], floating[Any], complexfloating[Any, Any]]]", Union[bool, int, float, complex], ] +_ArrayLikeNumber_co = _ArrayLike[ + "dtype[Union[bool_, number[Any]]]", + Union[bool, int, float, complex], +] _ArrayLikeTD64_co = _ArrayLike[ "dtype[Union[bool_, integer[Any], timedelta64]]", Union[bool, int], From f3dd737525c85825e47f7d92fbabccaa7102b6d5 Mon Sep 17 00:00:00 2001 From: Bas van Beek Date: Sun, 27 Dec 2020 06:15:08 +0100 Subject: [PATCH 2/5] ENH: Added dtype support to the array comparison ops --- numpy/__init__.pyi | 116 +++++++++++++++++++++++++++++------- numpy/typing/__init__.py | 4 ++ numpy/typing/_array_like.py | 8 +++ numpy/typing/_callable.py | 16 +++-- 4 files changed, 118 insertions(+), 26 deletions(-) diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index dbf8077831e1..3a85952e8b62 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -9,8 +9,16 @@ from numpy.core._internal import _ctypes from numpy.typing import ( # Arrays ArrayLike, + _ArrayND, + _ArrayOrScalar, + _NestedSequence, + _RecursiveSequence, + _ArrayLikeNumber_co, + _ArrayLikeTD64_co, + _ArrayLikeDT64_co, # DTypes + DTypeLike, _SupportsDType, _VoidDTypeLike, @@ -127,6 +135,7 @@ from typing import ( Iterable, List, Mapping, + NoReturn, Optional, overload, Sequence, @@ -1464,10 +1473,77 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType]): def __iter__(self) -> Any: ... def __contains__(self, key) -> bool: ... def __index__(self) -> int: ... - def __lt__(self, other: ArrayLike) -> Union[ndarray, bool_]: ... - def __le__(self, other: ArrayLike) -> Union[ndarray, bool_]: ... - def __gt__(self, other: ArrayLike) -> Union[ndarray, bool_]: ... - def __ge__(self, other: ArrayLike) -> Union[ndarray, bool_]: ... + + # The last overload is for catching recursive objects whose + # nesting is too deep. + # The first overload is for catching `bytes` (as they are a subtype of + # `Sequence[int]`) and `str`. As `str` is a recusive sequence of + # strings, it will pass through the final overload otherwise + + @overload + def __lt__(self: _ArrayND[Any], other: _NestedSequence[Union[str, bytes]]) -> NoReturn: ... + @overload + def __lt__(self: _ArrayND[Union[number[Any], bool_]], other: _ArrayLikeNumber_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __lt__(self: _ArrayND[timedelta64], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __lt__(self: _ArrayND[datetime64], other: _ArrayLikeDT64_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __lt__(self: _ArrayND[object_], other: Any) -> _ArrayOrScalar[bool_]: ... + @overload + def __lt__( + self: _ArrayND[Union[number[Any], datetime64, timedelta64, bool_]], + other: _RecursiveSequence, + ) -> _ArrayOrScalar[bool_]: ... + + @overload + def __le__(self: _ArrayND[Any], other: _NestedSequence[Union[str, bytes]]) -> NoReturn: ... + @overload + def __le__(self: _ArrayND[Union[number[Any], bool_]], other: _ArrayLikeNumber_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __le__(self: _ArrayND[timedelta64], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __le__(self: _ArrayND[datetime64], other: _ArrayLikeDT64_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __le__(self: _ArrayND[object_], other: Any) -> _ArrayOrScalar[bool_]: ... + @overload + def __le__( + self: _ArrayND[Union[number[Any], datetime64, timedelta64, bool_]], + other: _RecursiveSequence, + ) -> _ArrayOrScalar[bool_]: ... + + @overload + def __gt__(self: _ArrayND[Any], other: _NestedSequence[Union[str, bytes]]) -> NoReturn: ... + @overload + def __gt__(self: _ArrayND[Union[number[Any], bool_]], other: _ArrayLikeNumber_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __gt__(self: _ArrayND[timedelta64], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __gt__(self: _ArrayND[datetime64], other: _ArrayLikeDT64_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __gt__(self: _ArrayND[object_], other: Any) -> _ArrayOrScalar[bool_]: ... + @overload + def __gt__( + self: _ArrayND[Union[number[Any], datetime64, timedelta64, bool_]], + other: _RecursiveSequence, + ) -> _ArrayOrScalar[bool_]: ... + + @overload + def __ge__(self: _ArrayND[Any], other: _NestedSequence[Union[str, bytes]]) -> NoReturn: ... + @overload + def __ge__(self: _ArrayND[Union[number[Any], bool_]], other: _ArrayLikeNumber_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __ge__(self: _ArrayND[timedelta64], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __ge__(self: _ArrayND[datetime64], other: _ArrayLikeDT64_co) -> _ArrayOrScalar[bool_]: ... + @overload + def __ge__(self: _ArrayND[object_], other: Any) -> _ArrayOrScalar[bool_]: ... + @overload + def __ge__( + self: _ArrayND[Union[number[Any], datetime64, timedelta64, bool_]], + other: _RecursiveSequence, + ) -> _ArrayOrScalar[bool_]: ... + def __matmul__(self, other: ArrayLike) -> Any: ... # NOTE: `ndarray` does not implement `__imatmul__` def __rmatmul__(self, other: ArrayLike) -> Any: ... @@ -1586,10 +1662,10 @@ class number(generic, Generic[_NBit1]): # type: ignore __rpow__: _NumberOp __truediv__: _NumberOp __rtruediv__: _NumberOp - __lt__: _ComparisonOp[_NumberLike_co] - __le__: _ComparisonOp[_NumberLike_co] - __gt__: _ComparisonOp[_NumberLike_co] - __ge__: _ComparisonOp[_NumberLike_co] + __lt__: _ComparisonOp[_NumberLike_co, _ArrayLikeNumber_co] + __le__: _ComparisonOp[_NumberLike_co, _ArrayLikeNumber_co] + __gt__: _ComparisonOp[_NumberLike_co, _ArrayLikeNumber_co] + __ge__: _ComparisonOp[_NumberLike_co, _ArrayLikeNumber_co] class bool_(generic): def __init__(self, __value: object = ...) -> None: ... @@ -1628,10 +1704,10 @@ class bool_(generic): __rmod__: _BoolMod __divmod__: _BoolDivMod __rdivmod__: _BoolDivMod - __lt__: _ComparisonOp[_NumberLike_co] - __le__: _ComparisonOp[_NumberLike_co] - __gt__: _ComparisonOp[_NumberLike_co] - __ge__: _ComparisonOp[_NumberLike_co] + __lt__: _ComparisonOp[_NumberLike_co, _ArrayLikeNumber_co] + __le__: _ComparisonOp[_NumberLike_co, _ArrayLikeNumber_co] + __gt__: _ComparisonOp[_NumberLike_co, _ArrayLikeNumber_co] + __ge__: _ComparisonOp[_NumberLike_co, _ArrayLikeNumber_co] class object_(generic): def __init__(self, __value: object = ...) -> None: ... @@ -1660,10 +1736,10 @@ class datetime64(generic): @overload def __sub__(self, other: _TD64Like_co) -> datetime64: ... def __rsub__(self, other: datetime64) -> timedelta64: ... - __lt__: _ComparisonOp[datetime64] - __le__: _ComparisonOp[datetime64] - __gt__: _ComparisonOp[datetime64] - __ge__: _ComparisonOp[datetime64] + __lt__: _ComparisonOp[datetime64, _ArrayLikeDT64_co] + __le__: _ComparisonOp[datetime64, _ArrayLikeDT64_co] + __gt__: _ComparisonOp[datetime64, _ArrayLikeDT64_co] + __ge__: _ComparisonOp[datetime64, _ArrayLikeDT64_co] # Support for `__index__` was added in python 3.8 (bpo-20092) if sys.version_info >= (3, 8): @@ -1762,10 +1838,10 @@ class timedelta64(generic): def __rmod__(self, other: timedelta64) -> timedelta64: ... def __divmod__(self, other: timedelta64) -> Tuple[int64, timedelta64]: ... def __rdivmod__(self, other: timedelta64) -> Tuple[int64, timedelta64]: ... - __lt__: _ComparisonOp[Union[timedelta64, _IntLike_co, _BoolLike_co]] - __le__: _ComparisonOp[Union[timedelta64, _IntLike_co, _BoolLike_co]] - __gt__: _ComparisonOp[Union[timedelta64, _IntLike_co, _BoolLike_co]] - __ge__: _ComparisonOp[Union[timedelta64, _IntLike_co, _BoolLike_co]] + __lt__: _ComparisonOp[_TD64Like_co, _ArrayLikeTD64_co] + __le__: _ComparisonOp[_TD64Like_co, _ArrayLikeTD64_co] + __gt__: _ComparisonOp[_TD64Like_co, _ArrayLikeTD64_co] + __ge__: _ComparisonOp[_TD64Like_co, _ArrayLikeTD64_co] class unsignedinteger(integer[_NBit1]): # NOTE: `uint64 + signedinteger -> float64` diff --git a/numpy/typing/__init__.py b/numpy/typing/__init__.py index dd506987e6db..4ec1f4b2fcae 100644 --- a/numpy/typing/__init__.py +++ b/numpy/typing/__init__.py @@ -302,7 +302,10 @@ class _8Bit(_16Bit): ... # type: ignore[misc] ArrayLike as ArrayLike, _ArrayLike, _NestedSequence, + _RecursiveSequence, _SupportsArray, + _ArrayND, + _ArrayOrScalar, _ArrayLikeBool_co, _ArrayLikeUInt_co, _ArrayLikeInt_co, @@ -315,6 +318,7 @@ class _8Bit(_16Bit): ... # type: ignore[misc] _ArrayLikeVoid_co, _ArrayLikeStr_co, _ArrayLikeBytes_co, + ) if __doc__ is not None: diff --git a/numpy/typing/_array_like.py b/numpy/typing/_array_like.py index d40cb31936e7..8871d7478efb 100644 --- a/numpy/typing/_array_like.py +++ b/numpy/typing/_array_like.py @@ -34,6 +34,7 @@ HAVE_PROTOCOL = True _T = TypeVar("_T") +_ScalarType = TypeVar("_ScalarType", bound=generic) _DType = TypeVar("_DType", bound="dtype[Any]") if TYPE_CHECKING or HAVE_PROTOCOL: @@ -121,3 +122,10 @@ def __array__(self, dtype: None = ...) -> ndarray[Any, _DType]: ... "dtype[bytes_]", bytes, ] + +if TYPE_CHECKING: + _ArrayND = ndarray[Any, dtype[_ScalarType]] + _ArrayOrScalar = Union[_ScalarType, _ArrayND[_ScalarType]] +else: + _ArrayND = Any + _ArrayOrScalar = Any diff --git a/numpy/typing/_callable.py b/numpy/typing/_callable.py index e1fdee3ba194..1591ca144591 100644 --- a/numpy/typing/_callable.py +++ b/numpy/typing/_callable.py @@ -8,6 +8,8 @@ """ +from __future__ import annotations + import sys from typing import ( Union, @@ -21,6 +23,7 @@ from numpy import ( ndarray, + dtype, generic, bool_, timedelta64, @@ -44,7 +47,7 @@ _NumberLike_co, ) from . import NBitBase -from ._array_like import ArrayLike +from ._array_like import ArrayLike, _ArrayOrScalar if sys.version_info >= (3, 8): from typing import Protocol @@ -58,8 +61,9 @@ HAVE_PROTOCOL = True if TYPE_CHECKING or HAVE_PROTOCOL: - _T = TypeVar("_T") - _2Tuple = Tuple[_T, _T] + _T1 = TypeVar("_T1") + _T2 = TypeVar("_T2") + _2Tuple = Tuple[_T1, _T1] _NBit1 = TypeVar("_NBit1", bound=NBitBase) _NBit2 = TypeVar("_NBit2", bound=NBitBase) @@ -316,11 +320,11 @@ def __call__( class _NumberOp(Protocol): def __call__(self, __other: _NumberLike_co) -> Any: ... - class _ComparisonOp(Protocol[_T]): + class _ComparisonOp(Protocol[_T1, _T2]): @overload - def __call__(self, __other: _T) -> bool_: ... + def __call__(self, __other: _T1) -> bool_: ... @overload - def __call__(self, __other: ArrayLike) -> Union[ndarray, bool_]: ... + def __call__(self, __other: _T2) -> _ArrayOrScalar[bool_]: ... else: _BoolOp = Any From 04fddcc121d42545da5c92ace2ebd976c2bcc33e Mon Sep 17 00:00:00 2001 From: Bas van Beek Date: Tue, 5 Jan 2021 01:56:06 +0100 Subject: [PATCH 3/5] MAINT: Made `dtype` and `ndarray` covariant The dtypes scalar-type and ndarrays' dtype are now covariant instead of invariant. This change is necasary in order to ensure that all generic subclasses can be used as underlying scalar type. --- numpy/__init__.pyi | 21 +++++++++++---------- numpy/typing/_array_like.py | 5 +++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index 3a85952e8b62..98b835091a6c 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -593,19 +593,19 @@ where: Any who: Any _NdArraySubClass = TypeVar("_NdArraySubClass", bound=ndarray) -_DTypeScalar = TypeVar("_DTypeScalar", bound=generic) +_DTypeScalar_co = TypeVar("_DTypeScalar_co", covariant=True, bound=generic) _ByteOrder = Literal["S", "<", ">", "=", "|", "L", "B", "N", "I"] -class dtype(Generic[_DTypeScalar]): +class dtype(Generic[_DTypeScalar_co]): names: Optional[Tuple[str, ...]] # Overload for subclass of generic @overload def __new__( cls, - dtype: Type[_DTypeScalar], + dtype: Type[_DTypeScalar_co], align: bool = ..., copy: bool = ..., - ) -> dtype[_DTypeScalar]: ... + ) -> dtype[_DTypeScalar_co]: ... # Overloads for string aliases, Python types, and some assorted # other special cases. Order is sometimes important because of the # subtype relationships @@ -720,10 +720,10 @@ class dtype(Generic[_DTypeScalar]): @overload def __new__( cls, - dtype: dtype[_DTypeScalar], + dtype: dtype[_DTypeScalar_co], align: bool = ..., copy: bool = ..., - ) -> dtype[_DTypeScalar]: ... + ) -> dtype[_DTypeScalar_co]: ... # TODO: handle _SupportsDType better @overload def __new__( @@ -800,7 +800,7 @@ class dtype(Generic[_DTypeScalar]): @property def str(self) -> builtins.str: ... @property - def type(self) -> Type[_DTypeScalar]: ... + def type(self) -> Type[_DTypeScalar_co]: ... class _flagsobj: aligned: bool @@ -1328,6 +1328,7 @@ class _ArrayOrScalarCommon: ) -> _NdArraySubClass: ... _DType = TypeVar("_DType", bound=dtype[Any]) +_DType_co = TypeVar("_DType_co", covariant=True, bound=dtype[Any]) # TODO: Set the `bound` to something more suitable once we # have proper shape support @@ -1336,7 +1337,7 @@ _ShapeType = TypeVar("_ShapeType", bound=Any) _BufferType = Union[ndarray, bytes, bytearray, memoryview] _Casting = Literal["no", "equiv", "safe", "same_kind", "unsafe"] -class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType]): +class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]): @property def base(self) -> Optional[ndarray]: ... @property @@ -1361,7 +1362,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType]): order: _OrderKACF = ..., ) -> _ArraySelf: ... @overload - def __array__(self, __dtype: None = ...) -> ndarray[Any, _DType]: ... + def __array__(self, __dtype: None = ...) -> ndarray[Any, _DType_co]: ... @overload def __array__(self, __dtype: DTypeLike) -> ndarray[Any, dtype[Any]]: ... @property @@ -1592,7 +1593,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType]): def __ior__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ... # Keep `dtype` at the bottom to avoid name conflicts with `np.dtype` @property - def dtype(self) -> _DType: ... + def dtype(self) -> _DType_co: ... # NOTE: while `np.generic` is not technically an instance of `ABCMeta`, # the `@abstractmethod` decorator is herein used to (forcefully) deny diff --git a/numpy/typing/_array_like.py b/numpy/typing/_array_like.py index 8871d7478efb..133f38800591 100644 --- a/numpy/typing/_array_like.py +++ b/numpy/typing/_array_like.py @@ -36,14 +36,15 @@ _T = TypeVar("_T") _ScalarType = TypeVar("_ScalarType", bound=generic) _DType = TypeVar("_DType", bound="dtype[Any]") +_DType_co = TypeVar("_DType_co", covariant=True, bound="dtype[Any]") if TYPE_CHECKING or HAVE_PROTOCOL: # The `_SupportsArray` protocol only cares about the default dtype # (i.e. `dtype=None`) of the to-be returned array. # Concrete implementations of the protocol are responsible for adding # any and all remaining overloads - class _SupportsArray(Protocol[_DType]): - def __array__(self, dtype: None = ...) -> ndarray[Any, _DType]: ... + class _SupportsArray(Protocol[_DType_co]): + def __array__(self, dtype: None = ...) -> ndarray[Any, _DType_co]: ... else: _SupportsArray = Any From 3aa0bf67e0c2b900bdf9767c2e298d96b34cd350 Mon Sep 17 00:00:00 2001 From: Bas van Beek Date: Tue, 5 Jan 2021 02:11:37 +0100 Subject: [PATCH 4/5] TST: Updated the comparison typing tests --- numpy/typing/tests/data/fail/comparisons.py | 28 ++++++ numpy/typing/tests/data/pass/comparisons.py | 96 +++++++++++++++---- numpy/typing/tests/data/reveal/comparisons.py | 72 +++++++------- 3 files changed, 139 insertions(+), 57 deletions(-) create mode 100644 numpy/typing/tests/data/fail/comparisons.py diff --git a/numpy/typing/tests/data/fail/comparisons.py b/numpy/typing/tests/data/fail/comparisons.py new file mode 100644 index 000000000000..cad1c6555de3 --- /dev/null +++ b/numpy/typing/tests/data/fail/comparisons.py @@ -0,0 +1,28 @@ +from typing import Any +import numpy as np + +AR_i: np.ndarray[Any, np.dtype[np.int64]] +AR_f: np.ndarray[Any, np.dtype[np.float64]] +AR_c: np.ndarray[Any, np.dtype[np.complex128]] +AR_m: np.ndarray[Any, np.dtype[np.timedelta64]] +AR_M: np.ndarray[Any, np.dtype[np.datetime64]] + +AR_f > AR_m # E: Unsupported operand types +AR_c > AR_m # E: Unsupported operand types + +AR_m > AR_f # E: Unsupported operand types +AR_m > AR_c # E: Unsupported operand types + +AR_i > AR_M # E: Unsupported operand types +AR_f > AR_M # E: Unsupported operand types +AR_m > AR_M # E: Unsupported operand types + +AR_M > AR_i # E: Unsupported operand types +AR_M > AR_f # E: Unsupported operand types +AR_M > AR_m # E: Unsupported operand types + +# Unfortunately `NoReturn` errors are not the most descriptive +_1 = AR_i > str() # E: Need type annotation +_2 = AR_i > bytes() # E: Need type annotation +_3 = str() > AR_M # E: Need type annotation +_4 = bytes() > AR_M # E: Need type annotation diff --git a/numpy/typing/tests/data/pass/comparisons.py b/numpy/typing/tests/data/pass/comparisons.py index b298117a62af..ce41de43596e 100644 --- a/numpy/typing/tests/data/pass/comparisons.py +++ b/numpy/typing/tests/data/pass/comparisons.py @@ -1,3 +1,6 @@ +from __future__ import annotations + +from typing import Any import numpy as np c16 = np.complex128() @@ -20,11 +23,62 @@ f = float() i = int() -AR = np.array([0], dtype=np.int64) -AR.setflags(write=False) - SEQ = (0, 1, 2, 3, 4) +AR_b: np.ndarray[Any, np.dtype[np.bool_]] = np.array([True]) +AR_u: np.ndarray[Any, np.dtype[np.uint32]] = np.array([1], dtype=np.uint32) +AR_i: np.ndarray[Any, np.dtype[np.int_]] = np.array([1]) +AR_f: np.ndarray[Any, np.dtype[np.float_]] = np.array([1.0]) +AR_c: np.ndarray[Any, np.dtype[np.complex_]] = np.array([1.0j]) +AR_m: np.ndarray[Any, np.dtype[np.timedelta64]] = np.array([np.timedelta64("1")]) +AR_M: np.ndarray[Any, np.dtype[np.datetime64]] = np.array([np.datetime64("1")]) +AR_O: np.ndarray[Any, np.dtype[np.object_]] = np.array([1], dtype=object) + +# Arrays + +AR_b > AR_b +AR_b > AR_u +AR_b > AR_i +AR_b > AR_f +AR_b > AR_c + +AR_u > AR_b +AR_u > AR_u +AR_u > AR_i +AR_u > AR_f +AR_u > AR_c + +AR_i > AR_b +AR_i > AR_u +AR_i > AR_i +AR_i > AR_f +AR_i > AR_c + +AR_f > AR_b +AR_f > AR_u +AR_f > AR_i +AR_f > AR_f +AR_f > AR_c + +AR_c > AR_b +AR_c > AR_u +AR_c > AR_i +AR_c > AR_f +AR_c > AR_c + +AR_m > AR_b +AR_m > AR_u +AR_m > AR_i +AR_b > AR_m +AR_u > AR_m +AR_i > AR_m + +AR_M > AR_M + +AR_O > AR_O +1 > AR_O +AR_O > 1 + # Time structures dt > dt @@ -33,7 +87,7 @@ td > i td > i4 td > i8 -td > AR +td > AR_i td > SEQ # boolean @@ -51,7 +105,7 @@ b_ > c b_ > c16 b_ > c8 -b_ > AR +b_ > AR_i b_ > SEQ # Complex @@ -67,7 +121,7 @@ c16 > c c16 > f c16 > i -c16 > AR +c16 > AR_i c16 > SEQ c16 > c16 @@ -81,7 +135,7 @@ c > c16 f > c16 i > c16 -AR > c16 +AR_i > c16 SEQ > c16 c8 > c16 @@ -95,7 +149,7 @@ c8 > c c8 > f c8 > i -c8 > AR +c8 > AR_i c8 > SEQ c16 > c8 @@ -109,7 +163,7 @@ c > c8 f > c8 i > c8 -AR > c8 +AR_i > c8 SEQ > c8 # Float @@ -123,7 +177,7 @@ f8 > c f8 > f f8 > i -f8 > AR +f8 > AR_i f8 > SEQ f8 > f8 @@ -135,7 +189,7 @@ c > f8 f > f8 i > f8 -AR > f8 +AR_i > f8 SEQ > f8 f4 > f8 @@ -147,7 +201,7 @@ f4 > c f4 > f f4 > i -f4 > AR +f4 > AR_i f4 > SEQ f8 > f4 @@ -159,7 +213,7 @@ c > f4 f > f4 i > f4 -AR > f4 +AR_i > f4 SEQ > f4 # Int @@ -173,7 +227,7 @@ i8 > c i8 > f i8 > i -i8 > AR +i8 > AR_i i8 > SEQ u8 > u8 @@ -184,7 +238,7 @@ u8 > c u8 > f u8 > i -u8 > AR +u8 > AR_i u8 > SEQ i8 > i8 @@ -196,7 +250,7 @@ c > i8 f > i8 i > i8 -AR > i8 +AR_i > i8 SEQ > i8 u8 > u8 @@ -207,7 +261,7 @@ c > u8 f > u8 i > u8 -AR > u8 +AR_i > u8 SEQ > u8 i4 > i8 @@ -215,7 +269,7 @@ i4 > i i4 > b_ i4 > b -i4 > AR +i4 > AR_i i4 > SEQ u4 > i8 @@ -225,7 +279,7 @@ u4 > i u4 > b_ u4 > b -u4 > AR +u4 > AR_i u4 > SEQ i8 > i4 @@ -233,7 +287,7 @@ i > i4 b_ > i4 b > i4 -AR > i4 +AR_i > i4 SEQ > i4 i8 > u4 @@ -243,5 +297,5 @@ b_ > u4 b > u4 i > u4 -AR > u4 +AR_i > u4 SEQ > u4 diff --git a/numpy/typing/tests/data/reveal/comparisons.py b/numpy/typing/tests/data/reveal/comparisons.py index 507f713c7d5d..d3608af21e8e 100644 --- a/numpy/typing/tests/data/reveal/comparisons.py +++ b/numpy/typing/tests/data/reveal/comparisons.py @@ -33,8 +33,8 @@ reveal_type(td > i) # E: numpy.bool_ reveal_type(td > i4) # E: numpy.bool_ reveal_type(td > i8) # E: numpy.bool_ -reveal_type(td > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(td > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(td > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(td > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] # boolean @@ -51,8 +51,8 @@ reveal_type(b_ > c) # E: numpy.bool_ reveal_type(b_ > c16) # E: numpy.bool_ reveal_type(b_ > c8) # E: numpy.bool_ -reveal_type(b_ > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(b_ > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(b_ > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(b_ > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] # Complex @@ -67,8 +67,8 @@ reveal_type(c16 > c) # E: numpy.bool_ reveal_type(c16 > f) # E: numpy.bool_ reveal_type(c16 > i) # E: numpy.bool_ -reveal_type(c16 > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(c16 > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(c16 > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(c16 > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(c16 > c16) # E: numpy.bool_ reveal_type(f8 > c16) # E: numpy.bool_ @@ -81,8 +81,8 @@ reveal_type(c > c16) # E: numpy.bool_ reveal_type(f > c16) # E: numpy.bool_ reveal_type(i > c16) # E: numpy.bool_ -reveal_type(AR > c16) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(SEQ > c16) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(AR > c16) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > c16) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(c8 > c16) # E: numpy.bool_ reveal_type(c8 > f8) # E: numpy.bool_ @@ -95,8 +95,8 @@ reveal_type(c8 > c) # E: numpy.bool_ reveal_type(c8 > f) # E: numpy.bool_ reveal_type(c8 > i) # E: numpy.bool_ -reveal_type(c8 > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(c8 > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(c8 > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(c8 > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(c16 > c8) # E: numpy.bool_ reveal_type(f8 > c8) # E: numpy.bool_ @@ -109,8 +109,8 @@ reveal_type(c > c8) # E: numpy.bool_ reveal_type(f > c8) # E: numpy.bool_ reveal_type(i > c8) # E: numpy.bool_ -reveal_type(AR > c8) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(SEQ > c8) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(AR > c8) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > c8) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] # Float @@ -123,8 +123,8 @@ reveal_type(f8 > c) # E: numpy.bool_ reveal_type(f8 > f) # E: numpy.bool_ reveal_type(f8 > i) # E: numpy.bool_ -reveal_type(f8 > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(f8 > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(f8 > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(f8 > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(f8 > f8) # E: numpy.bool_ reveal_type(i8 > f8) # E: numpy.bool_ @@ -135,8 +135,8 @@ reveal_type(c > f8) # E: numpy.bool_ reveal_type(f > f8) # E: numpy.bool_ reveal_type(i > f8) # E: numpy.bool_ -reveal_type(AR > f8) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(SEQ > f8) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(AR > f8) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > f8) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(f4 > f8) # E: numpy.bool_ reveal_type(f4 > i8) # E: numpy.bool_ @@ -147,8 +147,8 @@ reveal_type(f4 > c) # E: numpy.bool_ reveal_type(f4 > f) # E: numpy.bool_ reveal_type(f4 > i) # E: numpy.bool_ -reveal_type(f4 > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(f4 > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(f4 > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(f4 > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(f8 > f4) # E: numpy.bool_ reveal_type(i8 > f4) # E: numpy.bool_ @@ -159,8 +159,8 @@ reveal_type(c > f4) # E: numpy.bool_ reveal_type(f > f4) # E: numpy.bool_ reveal_type(i > f4) # E: numpy.bool_ -reveal_type(AR > f4) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(SEQ > f4) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(AR > f4) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > f4) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] # Int @@ -173,8 +173,8 @@ reveal_type(i8 > c) # E: numpy.bool_ reveal_type(i8 > f) # E: numpy.bool_ reveal_type(i8 > i) # E: numpy.bool_ -reveal_type(i8 > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(i8 > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(i8 > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(i8 > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(u8 > u8) # E: numpy.bool_ reveal_type(u8 > i4) # E: numpy.bool_ @@ -184,8 +184,8 @@ reveal_type(u8 > c) # E: numpy.bool_ reveal_type(u8 > f) # E: numpy.bool_ reveal_type(u8 > i) # E: numpy.bool_ -reveal_type(u8 > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(u8 > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(u8 > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(u8 > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(i8 > i8) # E: numpy.bool_ reveal_type(u8 > i8) # E: numpy.bool_ @@ -196,8 +196,8 @@ reveal_type(c > i8) # E: numpy.bool_ reveal_type(f > i8) # E: numpy.bool_ reveal_type(i > i8) # E: numpy.bool_ -reveal_type(AR > i8) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(SEQ > i8) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(AR > i8) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > i8) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(u8 > u8) # E: numpy.bool_ reveal_type(i4 > u8) # E: numpy.bool_ @@ -207,16 +207,16 @@ reveal_type(c > u8) # E: numpy.bool_ reveal_type(f > u8) # E: numpy.bool_ reveal_type(i > u8) # E: numpy.bool_ -reveal_type(AR > u8) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(SEQ > u8) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(AR > u8) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > u8) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(i4 > i8) # E: numpy.bool_ reveal_type(i4 > i4) # E: numpy.bool_ reveal_type(i4 > i) # E: numpy.bool_ reveal_type(i4 > b_) # E: numpy.bool_ reveal_type(i4 > b) # E: numpy.bool_ -reveal_type(i4 > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(i4 > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(i4 > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(i4 > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(u4 > i8) # E: numpy.bool_ reveal_type(u4 > i4) # E: numpy.bool_ @@ -225,16 +225,16 @@ reveal_type(u4 > i) # E: numpy.bool_ reveal_type(u4 > b_) # E: numpy.bool_ reveal_type(u4 > b) # E: numpy.bool_ -reveal_type(u4 > AR) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(u4 > SEQ) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(u4 > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(u4 > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(i8 > i4) # E: numpy.bool_ reveal_type(i4 > i4) # E: numpy.bool_ reveal_type(i > i4) # E: numpy.bool_ reveal_type(b_ > i4) # E: numpy.bool_ reveal_type(b > i4) # E: numpy.bool_ -reveal_type(AR > i4) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(SEQ > i4) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(AR > i4) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > i4) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(i8 > u4) # E: numpy.bool_ reveal_type(i4 > u4) # E: numpy.bool_ @@ -243,5 +243,5 @@ reveal_type(b_ > u4) # E: numpy.bool_ reveal_type(b > u4) # E: numpy.bool_ reveal_type(i > u4) # E: numpy.bool_ -reveal_type(AR > u4) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] -reveal_type(SEQ > u4) # E: Union[numpy.ndarray[Any, Any], numpy.bool_] +reveal_type(AR > u4) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > u4) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] From 6e848559be8a927411795669ec891603bd01b0d3 Mon Sep 17 00:00:00 2001 From: Bas van Beek Date: Wed, 13 Jan 2021 15:20:32 +0100 Subject: [PATCH 5/5] MAINT: Fixed an issue where certain `array > arraylike` operations where neglected More specifically operations between array-likes of `timedelta64` and `ndarray`s that can be cast into `timedelta64`. For example: ar_i = np.array([1]) seq_m = [np.timedelta64()] ar_i > seq_m --- numpy/__init__.pyi | 8 ++++---- numpy/typing/tests/data/reveal/comparisons.py | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index 98b835091a6c..3d92a543b32c 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -1486,7 +1486,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]): @overload def __lt__(self: _ArrayND[Union[number[Any], bool_]], other: _ArrayLikeNumber_co) -> _ArrayOrScalar[bool_]: ... @overload - def __lt__(self: _ArrayND[timedelta64], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... + def __lt__(self: _ArrayND[Union[bool_, integer[Any], timedelta64]], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... @overload def __lt__(self: _ArrayND[datetime64], other: _ArrayLikeDT64_co) -> _ArrayOrScalar[bool_]: ... @overload @@ -1502,7 +1502,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]): @overload def __le__(self: _ArrayND[Union[number[Any], bool_]], other: _ArrayLikeNumber_co) -> _ArrayOrScalar[bool_]: ... @overload - def __le__(self: _ArrayND[timedelta64], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... + def __le__(self: _ArrayND[Union[bool_, integer[Any], timedelta64]], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... @overload def __le__(self: _ArrayND[datetime64], other: _ArrayLikeDT64_co) -> _ArrayOrScalar[bool_]: ... @overload @@ -1518,7 +1518,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]): @overload def __gt__(self: _ArrayND[Union[number[Any], bool_]], other: _ArrayLikeNumber_co) -> _ArrayOrScalar[bool_]: ... @overload - def __gt__(self: _ArrayND[timedelta64], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... + def __gt__(self: _ArrayND[Union[bool_, integer[Any], timedelta64]], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... @overload def __gt__(self: _ArrayND[datetime64], other: _ArrayLikeDT64_co) -> _ArrayOrScalar[bool_]: ... @overload @@ -1534,7 +1534,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]): @overload def __ge__(self: _ArrayND[Union[number[Any], bool_]], other: _ArrayLikeNumber_co) -> _ArrayOrScalar[bool_]: ... @overload - def __ge__(self: _ArrayND[timedelta64], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... + def __ge__(self: _ArrayND[Union[bool_, integer[Any], timedelta64]], other: _ArrayLikeTD64_co) -> _ArrayOrScalar[bool_]: ... @overload def __ge__(self: _ArrayND[datetime64], other: _ArrayLikeDT64_co) -> _ArrayOrScalar[bool_]: ... @overload diff --git a/numpy/typing/tests/data/reveal/comparisons.py b/numpy/typing/tests/data/reveal/comparisons.py index d3608af21e8e..5053a9e8215e 100644 --- a/numpy/typing/tests/data/reveal/comparisons.py +++ b/numpy/typing/tests/data/reveal/comparisons.py @@ -33,8 +33,13 @@ reveal_type(td > i) # E: numpy.bool_ reveal_type(td > i4) # E: numpy.bool_ reveal_type(td > i8) # E: numpy.bool_ + reveal_type(td > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] reveal_type(td > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(AR > SEQ) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(AR > td) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > td) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] +reveal_type(SEQ > AR) # E: Union[numpy.bool_, numpy.ndarray[Any, numpy.dtype[numpy.bool_]]] # boolean