From fc1de7a813ab5297932f9637a3f27927f8272872 Mon Sep 17 00:00:00 2001 From: Bas van Beek <43369155+BvB93@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:07:49 +0100 Subject: [PATCH 1/2] TYP,MAINT: Explicitly allow sequences of array-likes in `np.concatenate` --- numpy/core/multiarray.pyi | 15 +++++++++++---- .../tests/data/reveal/array_constructors.pyi | 5 +++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/numpy/core/multiarray.pyi b/numpy/core/multiarray.pyi index 3c1c37108fdf..5a8999582219 100644 --- a/numpy/core/multiarray.pyi +++ b/numpy/core/multiarray.pyi @@ -85,6 +85,8 @@ from numpy.typing import ( _TD64Like_co, ) +_T_co = TypeVar("_T_co", covariant=True) +_T_contra = TypeVar("_T_contra", contravariant=True) _SCT = TypeVar("_SCT", bound=generic) _ArrayType = TypeVar("_ArrayType", bound=NDArray[Any]) @@ -121,6 +123,10 @@ _RollKind = L[ # `raise` is deliberately excluded "modifiedpreceding", ] +class _SupportsLenAndGetItem(Protocol[_T_contra, _T_co]): + def __len__(self) -> int: ... + def __getitem__(self, __key: _T_contra) -> _T_co: ... + __all__: List[str] ALLOW_THREADS: Final[int] # 0 or 1 (system-specific) @@ -308,6 +314,7 @@ def ravel_multi_index( order: _OrderCF = ..., ) -> NDArray[intp]: ... +# NOTE: Allow any sequence of array-like objects @overload def concatenate( # type: ignore[misc] arrays: _ArrayLike[_SCT], @@ -320,7 +327,7 @@ def concatenate( # type: ignore[misc] ) -> NDArray[_SCT]: ... @overload def concatenate( # type: ignore[misc] - arrays: ArrayLike, + arrays: _SupportsLenAndGetItem[int, ArrayLike], /, axis: Optional[SupportsIndex] = ..., out: None = ..., @@ -330,7 +337,7 @@ def concatenate( # type: ignore[misc] ) -> NDArray[Any]: ... @overload def concatenate( # type: ignore[misc] - arrays: ArrayLike, + arrays: _SupportsLenAndGetItem[int, ArrayLike], /, axis: Optional[SupportsIndex] = ..., out: None = ..., @@ -340,7 +347,7 @@ def concatenate( # type: ignore[misc] ) -> NDArray[_SCT]: ... @overload def concatenate( # type: ignore[misc] - arrays: ArrayLike, + arrays: _SupportsLenAndGetItem[int, ArrayLike], /, axis: Optional[SupportsIndex] = ..., out: None = ..., @@ -350,7 +357,7 @@ def concatenate( # type: ignore[misc] ) -> NDArray[Any]: ... @overload def concatenate( - arrays: ArrayLike, + arrays: _SupportsLenAndGetItem[int, ArrayLike], /, axis: Optional[SupportsIndex] = ..., out: _ArrayType = ..., diff --git a/numpy/typing/tests/data/reveal/array_constructors.pyi b/numpy/typing/tests/data/reveal/array_constructors.pyi index dc0f107a1735..6df1c7c294af 100644 --- a/numpy/typing/tests/data/reveal/array_constructors.pyi +++ b/numpy/typing/tests/data/reveal/array_constructors.pyi @@ -38,6 +38,11 @@ reveal_type(np.empty([1, 5, 6], dtype=np.int64)) # E: ndarray[Any, dtype[{int64 reveal_type(np.empty([1, 5, 6], dtype='c16')) # E: ndarray[Any, dtype[Any]] reveal_type(np.concatenate(A)) # E: ndarray[Any, dtype[{float64}]] +reveal_type(np.concatenate([A, A])) # E: Any +reveal_type(np.concatenate([[1], A])) # E: ndarray[Any, dtype[Any]] +reveal_type(np.concatenate([[1], [1]])) # E: ndarray[Any, dtype[Any]] +reveal_type(np.concatenate((A, A))) # E: ndarray[Any, dtype[{float64}]] +reveal_type(np.concatenate(([1], [1]))) # E: ndarray[Any, dtype[Any]] reveal_type(np.concatenate([1, 1.0])) # E: ndarray[Any, dtype[Any]] reveal_type(np.concatenate(A, dtype=np.int64)) # E: ndarray[Any, dtype[{int64}]] reveal_type(np.concatenate(A, dtype='c16')) # E: ndarray[Any, dtype[Any]] From b9833cc29dce46da7673ccea805804ef4e93ef95 Mon Sep 17 00:00:00 2001 From: Bas van Beek <43369155+BvB93@users.noreply.github.com> Date: Mon, 21 Feb 2022 17:11:37 +0100 Subject: [PATCH 2/2] TYP,TST: Add tests for known mypy-related false-positives These all concern known false positives due to known mypy bugs. If one of these tests break, than that would generally be indicative of a upstream bug fix --- numpy/typing/tests/data/fail/false_positives.pyi | 11 +++++++++++ numpy/typing/tests/data/reveal/false_positives.pyi | 10 ++++++++++ 2 files changed, 21 insertions(+) create mode 100644 numpy/typing/tests/data/fail/false_positives.pyi create mode 100644 numpy/typing/tests/data/reveal/false_positives.pyi diff --git a/numpy/typing/tests/data/fail/false_positives.pyi b/numpy/typing/tests/data/fail/false_positives.pyi new file mode 100644 index 000000000000..7e79230663c2 --- /dev/null +++ b/numpy/typing/tests/data/fail/false_positives.pyi @@ -0,0 +1,11 @@ +import numpy as np +import numpy.typing as npt + +AR_f8: npt.NDArray[np.float64] + +# NOTE: Mypy bug presumably due to the special-casing of heterogeneous tuples; +# xref numpy/numpy#20901 +# +# The expected output should be no different than, e.g., when using a +# list instead of a tuple +np.concatenate(([1], AR_f8)) # E: Argument 1 to "concatenate" has incompatible type diff --git a/numpy/typing/tests/data/reveal/false_positives.pyi b/numpy/typing/tests/data/reveal/false_positives.pyi new file mode 100644 index 000000000000..2d7156642ec2 --- /dev/null +++ b/numpy/typing/tests/data/reveal/false_positives.pyi @@ -0,0 +1,10 @@ +from typing import Any +import numpy.typing as npt + +AR_Any: npt.NDArray[Any] + +# Mypy bug where overload ambiguity is ignored for `Any`-parametrized types; +# xref numpy/numpy#20099 and python/mypy#11347 +# +# The expected output would be something akin to `ndarray[Any, dtype[Any]]` +reveal_type(AR_Any + 2) # E: ndarray[Any, dtype[signedinteger[Any]]]