summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/__init__.pyi1077
-rw-r--r--numpy/core/_internal.pyi18
-rw-r--r--numpy/core/setup.py1
-rw-r--r--numpy/py.typed0
-rw-r--r--numpy/setup.py2
-rw-r--r--numpy/tests/fail/array_like.py22
-rw-r--r--numpy/tests/fail/fromnumeric.py101
-rw-r--r--numpy/tests/fail/ndarray.py11
-rw-r--r--numpy/tests/fail/numerictypes.py13
-rw-r--r--numpy/tests/fail/scalars.py67
-rw-r--r--numpy/tests/fail/simple.py10
-rw-r--r--numpy/tests/fail/ufuncs.py5
-rw-r--r--numpy/tests/fail/warnings_and_errors.py7
-rw-r--r--numpy/tests/mypy.ini8
-rw-r--r--numpy/tests/pass/array_like.py44
-rw-r--r--numpy/tests/pass/fromnumeric.py116
-rw-r--r--numpy/tests/pass/ndarray_conversion.py94
-rw-r--r--numpy/tests/pass/ndarray_shape_manipulation.py47
-rw-r--r--numpy/tests/pass/numerictypes.py29
-rw-r--r--numpy/tests/pass/scalars.py88
-rw-r--r--numpy/tests/pass/simple.py175
-rw-r--r--numpy/tests/pass/simple_py3.py6
-rw-r--r--numpy/tests/pass/ufuncs.py11
-rw-r--r--numpy/tests/pass/warnings_and_errors.py7
-rw-r--r--numpy/tests/reveal/constants.py44
-rw-r--r--numpy/tests/reveal/fromnumeric.py135
-rw-r--r--numpy/tests/reveal/ndarray_conversion.py54
-rw-r--r--numpy/tests/reveal/ndarray_shape_manipulation.py35
-rw-r--r--numpy/tests/reveal/numerictypes.py18
-rw-r--r--numpy/tests/reveal/scalars.py30
-rw-r--r--numpy/tests/reveal/warnings_and_errors.py10
-rw-r--r--numpy/tests/setup.py13
-rw-r--r--numpy/tests/test_typing.py127
-rw-r--r--numpy/typing.pyi64
34 files changed, 2489 insertions, 0 deletions
diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi
new file mode 100644
index 000000000..5031893ed
--- /dev/null
+++ b/numpy/__init__.pyi
@@ -0,0 +1,1077 @@
+import builtins
+import sys
+import datetime as dt
+from abc import abstractmethod
+
+from numpy.core._internal import _ctypes
+from numpy.typing import ArrayLike, DtypeLike, _Shape, _ShapeLike
+
+from typing import (
+ Any,
+ ByteString,
+ Callable,
+ Container,
+ Callable,
+ Dict,
+ Generic,
+ IO,
+ Iterable,
+ List,
+ Mapping,
+ Optional,
+ overload,
+ Sequence,
+ Sized,
+ SupportsAbs,
+ SupportsComplex,
+ SupportsFloat,
+ SupportsInt,
+ Text,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+)
+
+if sys.version_info[0] < 3:
+ class SupportsBytes: ...
+
+else:
+ from typing import SupportsBytes
+
+if sys.version_info >= (3, 8):
+ from typing import Literal, Protocol
+else:
+ from typing_extensions import Literal, Protocol
+
+# TODO: remove when the full numpy namespace is defined
+def __getattr__(name: str) -> Any: ...
+
+_NdArraySubClass = TypeVar("_NdArraySubClass", bound=ndarray)
+
+class dtype:
+ names: Optional[Tuple[str, ...]]
+ def __init__(self, obj: DtypeLike, align: bool = ..., copy: bool = ...) -> None: ...
+ def __eq__(self, other: DtypeLike) -> bool: ...
+ def __ne__(self, other: DtypeLike) -> bool: ...
+ def __gt__(self, other: DtypeLike) -> bool: ...
+ def __ge__(self, other: DtypeLike) -> bool: ...
+ def __lt__(self, other: DtypeLike) -> bool: ...
+ def __le__(self, other: DtypeLike) -> bool: ...
+ @property
+ def alignment(self) -> int: ...
+ @property
+ def base(self) -> dtype: ...
+ @property
+ def byteorder(self) -> str: ...
+ @property
+ def char(self) -> str: ...
+ @property
+ def descr(self) -> List[Union[Tuple[str, str], Tuple[str, str, _Shape]]]: ...
+ @property
+ def fields(
+ self,
+ ) -> Optional[Mapping[str, Union[Tuple[dtype, int], Tuple[dtype, int, Any]]]]: ...
+ @property
+ def flags(self) -> int: ...
+ @property
+ def hasobject(self) -> bool: ...
+ @property
+ def isbuiltin(self) -> int: ...
+ @property
+ def isnative(self) -> bool: ...
+ @property
+ def isalignedstruct(self) -> bool: ...
+ @property
+ def itemsize(self) -> int: ...
+ @property
+ def kind(self) -> str: ...
+ @property
+ def metadata(self) -> Optional[Mapping[str, Any]]: ...
+ @property
+ def name(self) -> str: ...
+ @property
+ def num(self) -> int: ...
+ @property
+ def shape(self) -> _Shape: ...
+ @property
+ def ndim(self) -> int: ...
+ @property
+ def subdtype(self) -> Optional[Tuple[dtype, _Shape]]: ...
+ def newbyteorder(self, new_order: str = ...) -> dtype: ...
+ # Leave str and type for end to avoid having to use `builtins.str`
+ # everywhere. See https://github.com/python/mypy/issues/3775
+ @property
+ def str(self) -> builtins.str: ...
+ @property
+ def type(self) -> Type[generic]: ...
+
+_Dtype = dtype # to avoid name conflicts with ndarray.dtype
+
+class _flagsobj:
+ aligned: bool
+ updateifcopy: bool
+ writeable: bool
+ writebackifcopy: bool
+ @property
+ def behaved(self) -> bool: ...
+ @property
+ def c_contiguous(self) -> bool: ...
+ @property
+ def carray(self) -> bool: ...
+ @property
+ def contiguous(self) -> bool: ...
+ @property
+ def f_contiguous(self) -> bool: ...
+ @property
+ def farray(self) -> bool: ...
+ @property
+ def fnc(self) -> bool: ...
+ @property
+ def forc(self) -> bool: ...
+ @property
+ def fortran(self) -> bool: ...
+ @property
+ def num(self) -> int: ...
+ @property
+ def owndata(self) -> bool: ...
+ def __getitem__(self, key: str) -> bool: ...
+ def __setitem__(self, key: str, value: bool) -> None: ...
+
+_FlatIterSelf = TypeVar("_FlatIterSelf", bound=flatiter)
+
+class flatiter(Generic[_ArraySelf]):
+ @property
+ def base(self) -> _ArraySelf: ...
+ @property
+ def coords(self) -> _Shape: ...
+ @property
+ def index(self) -> int: ...
+ def copy(self) -> _ArraySelf: ...
+ def __iter__(self: _FlatIterSelf) -> _FlatIterSelf: ...
+ def __next__(self) -> generic: ...
+
+_ArraySelf = TypeVar("_ArraySelf", bound=_ArrayOrScalarCommon)
+
+class _ArrayOrScalarCommon(
+ SupportsInt, SupportsFloat, SupportsComplex, SupportsBytes, SupportsAbs[Any]
+):
+ @property
+ def T(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def base(self) -> Optional[ndarray]: ...
+ @property
+ def dtype(self) -> _Dtype: ...
+ @property
+ def data(self) -> memoryview: ...
+ @property
+ def flags(self) -> _flagsobj: ...
+ @property
+ def size(self) -> int: ...
+ @property
+ def itemsize(self) -> int: ...
+ @property
+ def nbytes(self) -> int: ...
+ @property
+ def ndim(self) -> int: ...
+ @property
+ def shape(self) -> _Shape: ...
+ @property
+ def strides(self) -> _Shape: ...
+ def __array__(self, __dtype: DtypeLike = ...) -> ndarray: ...
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ if sys.version_info[0] < 3:
+ def __oct__(self) -> str: ...
+ def __hex__(self) -> str: ...
+ def __nonzero__(self) -> bool: ...
+ def __unicode__(self) -> Text: ...
+ else:
+ def __bool__(self) -> bool: ...
+ def __bytes__(self) -> bytes: ...
+ def __str__(self) -> str: ...
+ def __repr__(self) -> str: ...
+ def __copy__(self: _ArraySelf, order: str = ...) -> _ArraySelf: ...
+ def __deepcopy__(self: _ArraySelf, memo: dict) -> _ArraySelf: ...
+ def __lt__(self, other): ...
+ def __le__(self, other): ...
+ def __eq__(self, other): ...
+ def __ne__(self, other): ...
+ def __gt__(self, other): ...
+ def __ge__(self, other): ...
+ def __add__(self, other): ...
+ def __radd__(self, other): ...
+ def __iadd__(self, other): ...
+ def __sub__(self, other): ...
+ def __rsub__(self, other): ...
+ def __isub__(self, other): ...
+ def __mul__(self, other): ...
+ def __rmul__(self, other): ...
+ def __imul__(self, other): ...
+ if sys.version_info[0] < 3:
+ def __div__(self, other): ...
+ def __rdiv__(self, other): ...
+ def __idiv__(self, other): ...
+ def __truediv__(self, other): ...
+ def __rtruediv__(self, other): ...
+ def __itruediv__(self, other): ...
+ def __floordiv__(self, other): ...
+ def __rfloordiv__(self, other): ...
+ def __ifloordiv__(self, other): ...
+ def __mod__(self, other): ...
+ def __rmod__(self, other): ...
+ def __imod__(self, other): ...
+ def __divmod__(self, other): ...
+ def __rdivmod__(self, other): ...
+ # NumPy's __pow__ doesn't handle a third argument
+ def __pow__(self, other): ...
+ def __rpow__(self, other): ...
+ def __ipow__(self, other): ...
+ def __lshift__(self, other): ...
+ def __rlshift__(self, other): ...
+ def __ilshift__(self, other): ...
+ def __rshift__(self, other): ...
+ def __rrshift__(self, other): ...
+ def __irshift__(self, other): ...
+ def __and__(self, other): ...
+ def __rand__(self, other): ...
+ def __iand__(self, other): ...
+ def __xor__(self, other): ...
+ def __rxor__(self, other): ...
+ def __ixor__(self, other): ...
+ def __or__(self, other): ...
+ def __ror__(self, other): ...
+ def __ior__(self, other): ...
+ if sys.version_info[:2] >= (3, 5):
+ def __matmul__(self, other): ...
+ def __rmatmul__(self, other): ...
+ def __neg__(self: _ArraySelf) -> _ArraySelf: ...
+ def __pos__(self: _ArraySelf) -> _ArraySelf: ...
+ def __abs__(self: _ArraySelf) -> _ArraySelf: ...
+ def __invert__(self: _ArraySelf) -> _ArraySelf: ...
+ # TODO(shoyer): remove when all methods are defined
+ def __getattr__(self, name) -> Any: ...
+
+_BufferType = Union[ndarray, bytes, bytearray, memoryview]
+
+class ndarray(_ArrayOrScalarCommon, Iterable, Sized, Container):
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @real.setter
+ def real(self, value: ArrayLike) -> None: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ @imag.setter
+ def imag(self, value: ArrayLike) -> None: ...
+ def __new__(
+ cls: Type[_ArraySelf],
+ shape: Sequence[int],
+ dtype: DtypeLike = ...,
+ buffer: _BufferType = ...,
+ offset: int = ...,
+ strides: _ShapeLike = ...,
+ order: Optional[str] = ...,
+ ) -> _ArraySelf: ...
+ @property
+ def dtype(self) -> _Dtype: ...
+ @property
+ def ctypes(self) -> _ctypes: ...
+ @property
+ def shape(self) -> _Shape: ...
+ @shape.setter
+ def shape(self, value: _ShapeLike): ...
+ @property
+ def flat(self: _ArraySelf) -> flatiter[_ArraySelf]: ...
+ @property
+ def strides(self) -> _Shape: ...
+ @strides.setter
+ def strides(self, value: _ShapeLike): ...
+ # Array conversion
+ @overload
+ def item(self, *args: int) -> Any: ...
+ @overload
+ def item(self, args: Tuple[int, ...]) -> Any: ...
+ def tolist(self) -> List[Any]: ...
+ @overload
+ def itemset(self, __value: Any) -> None: ...
+ @overload
+ def itemset(self, __item: _ShapeLike, __value: Any) -> None: ...
+ def tobytes(self, order: Optional[str] = ...) -> bytes: ...
+ def tofile(
+ self, fid: Union[IO[bytes], str], sep: str = ..., format: str = ...
+ ) -> None: ...
+ def dump(self, file: str) -> None: ...
+ def dumps(self) -> bytes: ...
+ def astype(
+ self: _ArraySelf,
+ dtype: DtypeLike,
+ order: str = ...,
+ casting: str = ...,
+ subok: bool = ...,
+ copy: bool = ...,
+ ) -> _ArraySelf: ...
+ def byteswap(self: _ArraySelf, inplace: bool = ...) -> _ArraySelf: ...
+ def copy(self: _ArraySelf, order: str = ...) -> _ArraySelf: ...
+ @overload
+ def view(self, type: Type[_NdArraySubClass]) -> _NdArraySubClass: ...
+ @overload
+ def view(self: _ArraySelf, dtype: DtypeLike = ...) -> _ArraySelf: ...
+ @overload
+ def view(
+ self, dtype: DtypeLike, type: Type[_NdArraySubClass]
+ ) -> _NdArraySubClass: ...
+ def getfield(
+ self: _ArraySelf, dtype: DtypeLike, offset: int = ...
+ ) -> _ArraySelf: ...
+ def setflags(
+ self, write: bool = ..., align: bool = ..., uic: bool = ...
+ ) -> None: ...
+ def fill(self, value: Any) -> None: ...
+ # Shape manipulation
+ @overload
+ def reshape(
+ self: _ArraySelf, shape: Sequence[int], *, order: str = ...
+ ) -> _ArraySelf: ...
+ @overload
+ def reshape(self: _ArraySelf, *shape: int, order: str = ...) -> _ArraySelf: ...
+ @overload
+ def resize(self, new_shape: Sequence[int], *, refcheck: bool = ...) -> None: ...
+ @overload
+ def resize(self, *new_shape: int, refcheck: bool = ...) -> None: ...
+ @overload
+ def transpose(self: _ArraySelf, axes: Sequence[int]) -> _ArraySelf: ...
+ @overload
+ def transpose(self: _ArraySelf, *axes: int) -> _ArraySelf: ...
+ def swapaxes(self: _ArraySelf, axis1: int, axis2: int) -> _ArraySelf: ...
+ def flatten(self: _ArraySelf, order: str = ...) -> _ArraySelf: ...
+ def ravel(self: _ArraySelf, order: str = ...) -> _ArraySelf: ...
+ def squeeze(
+ self: _ArraySelf, axis: Union[int, Tuple[int, ...]] = ...
+ ) -> _ArraySelf: ...
+ # Many of these special methods are irrelevant currently, since protocols
+ # aren't supported yet. That said, I'm adding them for completeness.
+ # https://docs.python.org/3/reference/datamodel.html
+ def __len__(self) -> int: ...
+ def __getitem__(self, key) -> Any: ...
+ def __setitem__(self, key, value): ...
+ def __iter__(self) -> Any: ...
+ def __contains__(self, key) -> bool: ...
+ def __index__(self) -> int: ...
+
+# NOTE: while `np.generic` is not technically an instance of `ABCMeta`,
+# the `@abstractmethod` decorator is herein used to (forcefully) deny
+# the creation of `np.generic` instances.
+# The `# type: ignore` comments are necessary to silence mypy errors regarding
+# the missing `ABCMeta` metaclass.
+
+# See https://github.com/numpy/numpy-stubs/pull/80 for more details.
+
+class generic(_ArrayOrScalarCommon):
+ @abstractmethod
+ def __init__(self, *args: Any, **kwargs: Any) -> None: ...
+ @property
+ def base(self) -> None: ...
+
+class _real_generic(generic): # type: ignore
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+
+class number(generic): ... # type: ignore
+
+class bool_(_real_generic):
+ def __init__(self, value: object = ...) -> None: ...
+
+class object_(generic):
+ def __init__(self, value: object = ...) -> None: ...
+
+class datetime64:
+ @overload
+ def __init__(
+ self, _data: Union[datetime64, str, dt.datetime] = ..., _format: str = ...
+ ) -> None: ...
+ @overload
+ def __init__(self, _data: int, _format: str) -> None: ...
+ def __add__(self, other: Union[timedelta64, int]) -> datetime64: ...
+ def __sub__(self, other: Union[timedelta64, datetime64, int]) -> timedelta64: ...
+
+class integer(number, _real_generic): ... # type: ignore
+class signedinteger(integer): ... # type: ignore
+
+class int8(signedinteger):
+ def __init__(self, value: SupportsInt = ...) -> None: ...
+
+class int16(signedinteger):
+ def __init__(self, value: SupportsInt = ...) -> None: ...
+
+class int32(signedinteger):
+ def __init__(self, value: SupportsInt = ...) -> None: ...
+
+class int64(signedinteger):
+ def __init__(self, value: SupportsInt = ...) -> None: ...
+
+class timedelta64(signedinteger):
+ def __init__(self, _data: Any = ..., _format: str = ...) -> None: ...
+ @overload
+ def __add__(self, other: Union[timedelta64, int]) -> timedelta64: ...
+ @overload
+ def __add__(self, other: datetime64) -> datetime64: ...
+ def __sub__(self, other: Union[timedelta64, int]) -> timedelta64: ...
+ if sys.version_info[0] < 3:
+ @overload
+ def __div__(self, other: timedelta64) -> float: ...
+ @overload
+ def __div__(self, other: float) -> timedelta64: ...
+ @overload
+ def __truediv__(self, other: timedelta64) -> float: ...
+ @overload
+ def __truediv__(self, other: float) -> timedelta64: ...
+ def __mod__(self, other: timedelta64) -> timedelta64: ...
+
+class unsignedinteger(integer): ... # type: ignore
+
+class uint8(unsignedinteger):
+ def __init__(self, value: SupportsInt = ...) -> None: ...
+
+class uint16(unsignedinteger):
+ def __init__(self, value: SupportsInt = ...) -> None: ...
+
+class uint32(unsignedinteger):
+ def __init__(self, value: SupportsInt = ...) -> None: ...
+
+class uint64(unsignedinteger):
+ def __init__(self, value: SupportsInt = ...) -> None: ...
+
+class inexact(number): ... # type: ignore
+class floating(inexact, _real_generic): ... # type: ignore
+
+class float16(floating):
+ def __init__(self, value: SupportsFloat = ...) -> None: ...
+
+class float32(floating):
+ def __init__(self, value: SupportsFloat = ...) -> None: ...
+
+class float64(floating):
+ def __init__(self, value: SupportsFloat = ...) -> None: ...
+
+class complexfloating(inexact): ... # type: ignore
+
+class complex64(complexfloating):
+ def __init__(
+ self, value: Union[SupportsInt, SupportsFloat, SupportsComplex] = ...
+ ) -> None: ...
+ @property
+ def real(self) -> float32: ...
+ @property
+ def imag(self) -> float32: ...
+
+class complex128(complexfloating):
+ def __init__(
+ self, value: Union[SupportsInt, SupportsFloat, SupportsComplex] = ...
+ ) -> None: ...
+ @property
+ def real(self) -> float64: ...
+ @property
+ def imag(self) -> float64: ...
+
+class flexible(_real_generic): ... # type: ignore
+
+class void(flexible):
+ def __init__(self, value: Union[int, integer, bool_, bytes, bytes_]): ...
+
+class character(_real_generic): ... # type: ignore
+
+class bytes_(character):
+ @overload
+ def __init__(self, value: object = ...) -> None: ...
+ @overload
+ def __init__(
+ self, value: object, encoding: str = ..., errors: str = ...
+ ) -> None: ...
+
+class str_(character):
+ @overload
+ def __init__(self, value: object = ...) -> None: ...
+ @overload
+ def __init__(
+ self, value: object, encoding: str = ..., errors: str = ...
+ ) -> None: ...
+
+# TODO(alan): Platform dependent types
+# longcomplex, longdouble, longfloat
+# bytes, short, intc, intp, longlong
+# half, single, double, longdouble
+# uint_, int_, float_, complex_
+# float128, complex256
+# float96
+
+def array(
+ object: object,
+ dtype: DtypeLike = ...,
+ copy: bool = ...,
+ subok: bool = ...,
+ ndmin: int = ...,
+) -> ndarray: ...
+def zeros(
+ shape: _ShapeLike, dtype: DtypeLike = ..., order: Optional[str] = ...
+) -> ndarray: ...
+def ones(
+ shape: _ShapeLike, dtype: DtypeLike = ..., order: Optional[str] = ...
+) -> ndarray: ...
+def empty(
+ shape: _ShapeLike, dtype: DtypeLike = ..., order: Optional[str] = ...
+) -> ndarray: ...
+def zeros_like(
+ a: ArrayLike,
+ dtype: DtypeLike = ...,
+ order: str = ...,
+ subok: bool = ...,
+ shape: Optional[Union[int, Sequence[int]]] = ...,
+) -> ndarray: ...
+def ones_like(
+ a: ArrayLike,
+ dtype: DtypeLike = ...,
+ order: str = ...,
+ subok: bool = ...,
+ shape: Optional[_ShapeLike] = ...,
+) -> ndarray: ...
+def empty_like(
+ a: ArrayLike,
+ dtype: DtypeLike = ...,
+ order: str = ...,
+ subok: bool = ...,
+ shape: Optional[_ShapeLike] = ...,
+) -> ndarray: ...
+def full(
+ shape: _ShapeLike, fill_value: Any, dtype: DtypeLike = ..., order: str = ...
+) -> ndarray: ...
+def full_like(
+ a: ArrayLike,
+ fill_value: Any,
+ dtype: DtypeLike = ...,
+ order: str = ...,
+ subok: bool = ...,
+ shape: Optional[_ShapeLike] = ...,
+) -> ndarray: ...
+def count_nonzero(
+ a: ArrayLike, axis: Optional[Union[int, Tuple[int], Tuple[int, int]]] = ...
+) -> Union[int, ndarray]: ...
+def isfortran(a: ndarray) -> bool: ...
+def argwhere(a: ArrayLike) -> ndarray: ...
+def flatnonzero(a: ArrayLike) -> ndarray: ...
+def correlate(a: ArrayLike, v: ArrayLike, mode: str = ...) -> ndarray: ...
+def convolve(a: ArrayLike, v: ArrayLike, mode: str = ...) -> ndarray: ...
+def outer(a: ArrayLike, b: ArrayLike, out: ndarray = ...) -> ndarray: ...
+def tensordot(
+ a: ArrayLike,
+ b: ArrayLike,
+ axes: Union[
+ int, Tuple[int, int], Tuple[Tuple[int, int], ...], Tuple[List[int, int], ...]
+ ] = ...,
+) -> ndarray: ...
+def roll(
+ a: ArrayLike,
+ shift: Union[int, Tuple[int, ...]],
+ axis: Optional[Union[int, Tuple[int, ...]]] = ...,
+) -> ndarray: ...
+def rollaxis(a: ArrayLike, axis: int, start: int = ...) -> ndarray: ...
+def moveaxis(
+ a: ndarray,
+ source: Union[int, Sequence[int]],
+ destination: Union[int, Sequence[int]],
+) -> ndarray: ...
+def cross(
+ a: ArrayLike,
+ b: ArrayLike,
+ axisa: int = ...,
+ axisb: int = ...,
+ axisc: int = ...,
+ axis: Optional[int] = ...,
+) -> ndarray: ...
+def indices(
+ dimensions: Sequence[int], dtype: dtype = ..., sparse: bool = ...
+) -> Union[ndarray, Tuple[ndarray, ...]]: ...
+def fromfunction(function: Callable, shape: Tuple[int, int], **kwargs) -> Any: ...
+def isscalar(element: Any) -> bool: ...
+def binary_repr(num: int, width: Optional[int] = ...) -> str: ...
+def base_repr(number: int, base: int = ..., padding: int = ...) -> str: ...
+def identity(n: int, dtype: DtypeLike = ...) -> ndarray: ...
+def allclose(
+ a: ArrayLike,
+ b: ArrayLike,
+ rtol: float = ...,
+ atol: float = ...,
+ equal_nan: bool = ...,
+) -> bool: ...
+def isclose(
+ a: ArrayLike,
+ b: ArrayLike,
+ rtol: float = ...,
+ atol: float = ...,
+ equal_nan: bool = ...,
+) -> Union[bool_, ndarray]: ...
+def array_equal(a1: ArrayLike, a2: ArrayLike) -> bool: ...
+def array_equiv(a1: ArrayLike, a2: ArrayLike) -> bool: ...
+
+#
+# Constants
+#
+
+Inf: float
+Infinity: float
+NAN: float
+NINF: float
+NZERO: float
+NaN: float
+PINF: float
+PZERO: float
+e: float
+euler_gamma: float
+inf: float
+infty: float
+nan: float
+pi: float
+
+ALLOW_THREADS: int
+BUFSIZE: int
+CLIP: int
+ERR_CALL: int
+ERR_DEFAULT: int
+ERR_IGNORE: int
+ERR_LOG: int
+ERR_PRINT: int
+ERR_RAISE: int
+ERR_WARN: int
+FLOATING_POINT_SUPPORT: int
+FPE_DIVIDEBYZERO: int
+FPE_INVALID: int
+FPE_OVERFLOW: int
+FPE_UNDERFLOW: int
+MAXDIMS: int
+MAY_SHARE_BOUNDS: int
+MAY_SHARE_EXACT: int
+RAISE: int
+SHIFT_DIVIDEBYZERO: int
+SHIFT_INVALID: int
+SHIFT_OVERFLOW: int
+SHIFT_UNDERFLOW: int
+UFUNC_BUFSIZE_DEFAULT: int
+WRAP: int
+little_endian: int
+tracemalloc_domain: int
+
+class ufunc:
+ @property
+ def __name__(self) -> str: ...
+ def __call__(
+ self,
+ *args: ArrayLike,
+ out: Optional[Union[ndarray, Tuple[ndarray, ...]]] = ...,
+ where: Optional[ndarray] = ...,
+ # The list should be a list of tuples of ints, but since we
+ # don't know the signature it would need to be
+ # Tuple[int, ...]. But, since List is invariant something like
+ # e.g. List[Tuple[int, int]] isn't a subtype of
+ # List[Tuple[int, ...]], so we can't type precisely here.
+ axes: List[Any] = ...,
+ axis: int = ...,
+ keepdims: bool = ...,
+ # TODO: make this precise when we can use Literal.
+ casting: str = ...,
+ # TODO: make this precise when we can use Literal.
+ order: Optional[str] = ...,
+ dtype: DtypeLike = ...,
+ subok: bool = ...,
+ signature: Union[str, Tuple[str]] = ...,
+ # In reality this should be a length of list 3 containing an
+ # int, an int, and a callable, but there's no way to express
+ # that.
+ extobj: List[Union[int, Callable]] = ...,
+ ) -> Union[ndarray, generic]: ...
+ @property
+ def nin(self) -> int: ...
+ @property
+ def nout(self) -> int: ...
+ @property
+ def nargs(self) -> int: ...
+ @property
+ def ntypes(self) -> int: ...
+ @property
+ def types(self) -> List[str]: ...
+ # Broad return type because it has to encompass things like
+ #
+ # >>> np.logical_and.identity is True
+ # True
+ # >>> np.add.identity is 0
+ # True
+ # >>> np.sin.identity is None
+ # True
+ #
+ # and any user-defined ufuncs.
+ @property
+ def identity(self) -> Any: ...
+ # This is None for ufuncs and a string for gufuncs.
+ @property
+ def signature(self) -> Optional[str]: ...
+ # The next four methods will always exist, but they will just
+ # raise a ValueError ufuncs with that don't accept two input
+ # arguments and return one output argument. Because of that we
+ # can't type them very precisely.
+ @property
+ def reduce(self) -> Any: ...
+ @property
+ def accumulate(self) -> Any: ...
+ @property
+ def reduceat(self) -> Any: ...
+ @property
+ def outer(self) -> Any: ...
+ # Similarly at won't be defined for ufuncs that return multiple
+ # outputs, so we can't type it very precisely.
+ @property
+ def at(self) -> Any: ...
+
+absolute: ufunc
+add: ufunc
+arccos: ufunc
+arccosh: ufunc
+arcsin: ufunc
+arcsinh: ufunc
+arctan2: ufunc
+arctan: ufunc
+arctanh: ufunc
+bitwise_and: ufunc
+bitwise_or: ufunc
+bitwise_xor: ufunc
+cbrt: ufunc
+ceil: ufunc
+conjugate: ufunc
+copysign: ufunc
+cos: ufunc
+cosh: ufunc
+deg2rad: ufunc
+degrees: ufunc
+divmod: ufunc
+equal: ufunc
+exp2: ufunc
+exp: ufunc
+expm1: ufunc
+fabs: ufunc
+float_power: ufunc
+floor: ufunc
+floor_divide: ufunc
+fmax: ufunc
+fmin: ufunc
+fmod: ufunc
+frexp: ufunc
+gcd: ufunc
+greater: ufunc
+greater_equal: ufunc
+heaviside: ufunc
+hypot: ufunc
+invert: ufunc
+isfinite: ufunc
+isinf: ufunc
+isnan: ufunc
+isnat: ufunc
+lcm: ufunc
+ldexp: ufunc
+left_shift: ufunc
+less: ufunc
+less_equal: ufunc
+log10: ufunc
+log1p: ufunc
+log2: ufunc
+log: ufunc
+logaddexp2: ufunc
+logaddexp: ufunc
+logical_and: ufunc
+logical_not: ufunc
+logical_or: ufunc
+logical_xor: ufunc
+matmul: ufunc
+maximum: ufunc
+minimum: ufunc
+modf: ufunc
+multiply: ufunc
+negative: ufunc
+nextafter: ufunc
+not_equal: ufunc
+positive: ufunc
+power: ufunc
+rad2deg: ufunc
+radians: ufunc
+reciprocal: ufunc
+remainder: ufunc
+right_shift: ufunc
+rint: ufunc
+sign: ufunc
+signbit: ufunc
+sin: ufunc
+sinh: ufunc
+spacing: ufunc
+sqrt: ufunc
+square: ufunc
+subtract: ufunc
+tan: ufunc
+tanh: ufunc
+true_divide: ufunc
+trunc: ufunc
+
+# Warnings
+class ModuleDeprecationWarning(DeprecationWarning): ...
+class VisibleDeprecationWarning(UserWarning): ...
+class ComplexWarning(RuntimeWarning): ...
+class RankWarning(UserWarning): ...
+
+# Errors
+class TooHardError(RuntimeError): ...
+
+class AxisError(ValueError, IndexError):
+ def __init__(
+ self, axis: int, ndim: Optional[int] = ..., msg_prefix: Optional[str] = ...
+ ) -> None: ...
+
+# Functions from np.core.numerictypes
+_DefaultType = TypeVar("_DefaultType")
+
+def maximum_sctype(t: DtypeLike) -> dtype: ...
+def issctype(rep: object) -> bool: ...
+@overload
+def obj2sctype(rep: object) -> Optional[generic]: ...
+@overload
+def obj2sctype(rep: object, default: None) -> Optional[generic]: ...
+@overload
+def obj2sctype(
+ rep: object, default: Type[_DefaultType]
+) -> Union[generic, Type[_DefaultType]]: ...
+def issubclass_(arg1: object, arg2: Union[object, Tuple[object, ...]]) -> bool: ...
+def issubsctype(
+ arg1: Union[ndarray, DtypeLike], arg2: Union[ndarray, DtypeLike]
+) -> bool: ...
+def issubdtype(arg1: DtypeLike, arg2: DtypeLike) -> bool: ...
+def sctype2char(sctype: object) -> str: ...
+def find_common_type(
+ array_types: Sequence[DtypeLike], scalar_types: Sequence[DtypeLike]
+) -> dtype: ...
+
+# Functions from np.core.fromnumeric
+_Mode = Literal["raise", "wrap", "clip"]
+_Order = Literal["C", "F", "A"]
+_PartitionKind = Literal["introselect"]
+_SortKind = Literal["quicksort", "mergesort", "heapsort", "stable"]
+_Side = Literal["left", "right"]
+
+# Various annotations for scalars
+
+# While dt.datetime and dt.timedelta are not technically part of NumPy,
+# they are one of the rare few builtin scalars which serve as valid return types.
+# See https://github.com/numpy/numpy-stubs/pull/67#discussion_r412604113.
+_ScalarNumpy = Union[generic, dt.datetime, dt.timedelta]
+_ScalarBuiltin = Union[str, bytes, dt.date, dt.timedelta, bool, int, float, complex]
+_Scalar = Union[_ScalarBuiltin, _ScalarNumpy]
+
+# Integers and booleans can generally be used interchangeably
+_ScalarIntOrBool = TypeVar("_ScalarIntOrBool", bound=Union[integer, bool_])
+_ScalarGeneric = TypeVar("_ScalarGeneric", bound=generic)
+_ScalarGenericDT = TypeVar(
+ "_ScalarGenericDT", bound=Union[dt.datetime, dt.timedelta, generic]
+)
+
+# An array-like object consisting of integers
+_Int = Union[int, integer]
+_Bool = Union[bool, bool_]
+_IntOrBool = Union[_Int, _Bool]
+_ArrayLikeIntNested = ArrayLike # TODO: wait for support for recursive types
+_ArrayLikeBoolNested = ArrayLike # TODO: wait for support for recursive types
+
+# Integers and booleans can generally be used interchangeably
+_ArrayLikeIntOrBool = Union[
+ _IntOrBool,
+ ndarray,
+ Sequence[_IntOrBool],
+ Sequence[_ArrayLikeIntNested],
+ Sequence[_ArrayLikeBoolNested],
+]
+
+# The signature of take() follows a common theme with its overloads:
+# 1. A generic comes in; the same generic comes out
+# 2. A scalar comes in; a generic comes out
+# 3. An array-like object comes in; some keyword ensures that a generic comes out
+# 4. An array-like object comes in; an ndarray or generic comes out
+@overload
+def take(
+ a: _ScalarGenericDT,
+ indices: int,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+ mode: _Mode = ...,
+) -> _ScalarGenericDT: ...
+@overload
+def take(
+ a: _Scalar,
+ indices: int,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+ mode: _Mode = ...,
+) -> _ScalarNumpy: ...
+@overload
+def take(
+ a: ArrayLike,
+ indices: int,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+ mode: _Mode = ...,
+) -> _ScalarNumpy: ...
+@overload
+def take(
+ a: ArrayLike,
+ indices: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+ mode: _Mode = ...,
+) -> Union[_ScalarNumpy, ndarray]: ...
+def reshape(a: ArrayLike, newshape: _ShapeLike, order: _Order = ...) -> ndarray: ...
+@overload
+def choose(
+ a: _ScalarIntOrBool,
+ choices: Union[Sequence[ArrayLike], ndarray],
+ out: Optional[ndarray] = ...,
+ mode: _Mode = ...,
+) -> _ScalarIntOrBool: ...
+@overload
+def choose(
+ a: _IntOrBool,
+ choices: Union[Sequence[ArrayLike], ndarray],
+ out: Optional[ndarray] = ...,
+ mode: _Mode = ...,
+) -> Union[integer, bool_]: ...
+@overload
+def choose(
+ a: _ArrayLikeIntOrBool,
+ choices: Union[Sequence[ArrayLike], ndarray],
+ out: Optional[ndarray] = ...,
+ mode: _Mode = ...,
+) -> ndarray: ...
+def repeat(
+ a: ArrayLike, repeats: _ArrayLikeIntOrBool, axis: Optional[int] = ...
+) -> ndarray: ...
+def put(
+ a: ndarray, ind: _ArrayLikeIntOrBool, v: ArrayLike, mode: _Mode = ...
+) -> None: ...
+def swapaxes(
+ a: Union[Sequence[ArrayLike], ndarray], axis1: int, axis2: int
+) -> ndarray: ...
+def transpose(
+ a: ArrayLike, axes: Union[None, Sequence[int], ndarray] = ...
+) -> ndarray: ...
+def partition(
+ a: ArrayLike,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+@overload
+def argpartition(
+ a: generic,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> integer: ...
+@overload
+def argpartition(
+ a: _ScalarBuiltin,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+@overload
+def argpartition(
+ a: ArrayLike,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+def sort(
+ a: Union[Sequence[ArrayLike], ndarray],
+ axis: Optional[int] = ...,
+ kind: Optional[_SortKind] = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+def argsort(
+ a: Union[Sequence[ArrayLike], ndarray],
+ axis: Optional[int] = ...,
+ kind: Optional[_SortKind] = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+) -> ndarray: ...
+@overload
+def argmax(
+ a: Union[Sequence[ArrayLike], ndarray],
+ axis: None = ...,
+ out: Optional[ndarray] = ...,
+) -> integer: ...
+@overload
+def argmax(
+ a: Union[Sequence[ArrayLike], ndarray],
+ axis: int = ...,
+ out: Optional[ndarray] = ...,
+) -> Union[integer, ndarray]: ...
+@overload
+def argmin(
+ a: Union[Sequence[ArrayLike], ndarray],
+ axis: None = ...,
+ out: Optional[ndarray] = ...,
+) -> integer: ...
+@overload
+def argmin(
+ a: Union[Sequence[ArrayLike], ndarray],
+ axis: int = ...,
+ out: Optional[ndarray] = ...,
+) -> Union[integer, ndarray]: ...
+@overload
+def searchsorted(
+ a: Union[Sequence[ArrayLike], ndarray],
+ v: _Scalar,
+ side: _Side = ...,
+ sorter: Union[None, Sequence[_IntOrBool], ndarray] = ..., # 1D int array
+) -> integer: ...
+@overload
+def searchsorted(
+ a: Union[Sequence[ArrayLike], ndarray],
+ v: ArrayLike,
+ side: _Side = ...,
+ sorter: Union[None, Sequence[_IntOrBool], ndarray] = ..., # 1D int array
+) -> ndarray: ...
+def resize(a: ArrayLike, new_shape: _ShapeLike) -> ndarray: ...
+@overload
+def squeeze(a: _ScalarGeneric, axis: Optional[_ShapeLike] = ...) -> _ScalarGeneric: ...
+@overload
+def squeeze(a: ArrayLike, axis: Optional[_ShapeLike] = ...) -> ndarray: ...
+def diagonal(
+ a: Union[Sequence[Sequence[ArrayLike]], ndarray], # >= 2D array
+ offset: int = ...,
+ axis1: int = ...,
+ axis2: int = ...,
+) -> ndarray: ...
+def trace(
+ a: Union[Sequence[Sequence[ArrayLike]], ndarray], # >= 2D array
+ offset: int = ...,
+ axis1: int = ...,
+ axis2: int = ...,
+ dtype: DtypeLike = ...,
+ out: Optional[ndarray] = ...,
+) -> Union[number, ndarray]: ...
+def ravel(a: ArrayLike, order: _Order = ...) -> ndarray: ...
+def nonzero(a: ArrayLike) -> Tuple[ndarray, ...]: ...
+def shape(a: ArrayLike) -> _Shape: ...
+def compress(
+ condition: Union[Sequence[_Bool], ndarray], # 1D bool array
+ a: ArrayLike,
+ axis: Optional[int] = ...,
+ out: Optional[ndarray] = ...,
+) -> ndarray: ...
diff --git a/numpy/core/_internal.pyi b/numpy/core/_internal.pyi
new file mode 100644
index 000000000..1b3889e51
--- /dev/null
+++ b/numpy/core/_internal.pyi
@@ -0,0 +1,18 @@
+from typing import Any
+
+# TODO: add better annotations when ctypes is stubbed out
+
+class _ctypes:
+ @property
+ def data(self) -> int: ...
+ @property
+ def shape(self) -> Any: ...
+ @property
+ def strides(self) -> Any: ...
+ def data_as(self, obj: Any) -> Any: ...
+ def shape_as(self, obj: Any) -> Any: ...
+ def strides_as(self, obj: Any) -> Any: ...
+ def get_data(self) -> int: ...
+ def get_shape(self) -> Any: ...
+ def get_strides(self) -> Any: ...
+ def get_as_parameter(self) -> Any: ...
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index 16bac4272..5351b30bf 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -967,6 +967,7 @@ def configuration(parent_package='',top_path=None):
config.add_subpackage('tests')
config.add_data_dir('tests/data')
config.add_data_dir('tests/examples')
+ config.add_data_files('*.pyi')
config.make_svn_version_py()
diff --git a/numpy/py.typed b/numpy/py.typed
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/numpy/py.typed
diff --git a/numpy/setup.py b/numpy/setup.py
index 52db6a68b..c6498d101 100644
--- a/numpy/setup.py
+++ b/numpy/setup.py
@@ -18,6 +18,8 @@ def configuration(parent_package='',top_path=None):
config.add_subpackage('random')
config.add_subpackage('testing')
config.add_data_dir('doc')
+ config.add_data_files('py.typed')
+ config.add_data_files('*.pyi')
config.add_subpackage('tests')
config.make_config_py() # installs __config__.py
return config
diff --git a/numpy/tests/fail/array_like.py b/numpy/tests/fail/array_like.py
new file mode 100644
index 000000000..a5ef5795f
--- /dev/null
+++ b/numpy/tests/fail/array_like.py
@@ -0,0 +1,22 @@
+from typing import Any, TYPE_CHECKING
+
+import numpy as np
+
+if TYPE_CHECKING:
+ from numpy.typing import ArrayLike
+else:
+ ArrayLike = Any
+
+
+class A:
+ pass
+
+
+x1: ArrayLike = (i for i in range(10)) # E: Incompatible types in assignment
+x2: ArrayLike = A() # E: Incompatible types in assignment
+x3: ArrayLike = {1: "foo", 2: "bar"} # E: Incompatible types in assignment
+
+scalar = np.int64(1)
+scalar.__array__(dtype=np.float64) # E: Unexpected keyword argument
+array = np.array([1])
+array.__array__(dtype=np.float64) # E: Unexpected keyword argument
diff --git a/numpy/tests/fail/fromnumeric.py b/numpy/tests/fail/fromnumeric.py
new file mode 100644
index 000000000..f158a1071
--- /dev/null
+++ b/numpy/tests/fail/fromnumeric.py
@@ -0,0 +1,101 @@
+"""Tests for :mod:`numpy.core.fromnumeric`."""
+
+import numpy as np
+
+A = np.array(True, ndmin=2, dtype=bool)
+A.setflags(write=False)
+
+a = np.bool_(True)
+
+np.take(a, None) # E: No overload variant of "take" matches argument type
+np.take(a, axis=1.0) # E: No overload variant of "take" matches argument type
+np.take(A, out=1) # E: No overload variant of "take" matches argument type
+np.take(A, mode="bob") # E: No overload variant of "take" matches argument type
+
+np.reshape(a, None) # E: Argument 2 to "reshape" has incompatible type
+np.reshape(A, 1, order="bob") # E: Argument "order" to "reshape" has incompatible type
+
+np.choose(a, None) # E: No overload variant of "choose" matches argument type
+np.choose(a, out=1.0) # E: No overload variant of "choose" matches argument type
+np.choose(A, mode="bob") # E: No overload variant of "choose" matches argument type
+
+np.repeat(a, None) # E: Argument 2 to "repeat" has incompatible type
+np.repeat(A, 1, axis=1.0) # E: Argument "axis" to "repeat" has incompatible type
+
+np.swapaxes(a, 0, 0) # E: Argument 1 to "swapaxes" has incompatible type
+np.swapaxes(A, None, 1) # E: Argument 2 to "swapaxes" has incompatible type
+np.swapaxes(A, 1, [0]) # E: Argument 3 to "swapaxes" has incompatible type
+
+np.transpose(a, axes=1) # E: Argument "axes" to "transpose" has incompatible type
+np.transpose(A, axes=1.0) # E: Argument "axes" to "transpose" has incompatible type
+
+np.partition(a, None) # E: Argument 2 to "partition" has incompatible type
+np.partition(
+ a, 0, axis="bob" # E: Argument "axis" to "partition" has incompatible type
+)
+np.partition(
+ A, 0, kind="bob" # E: Argument "kind" to "partition" has incompatible type
+)
+np.partition(
+ A, 0, order=range(5) # E: Argument "order" to "partition" has incompatible type
+)
+
+np.argpartition( # E: No overload variant of "argpartition" matches argument type
+ a, None
+)
+np.argpartition( # E: No overload variant of "argpartition" matches argument type
+ a, 0, axis="bob"
+)
+np.argpartition( # E: No overload variant of "argpartition" matches argument type
+ A, 0, kind="bob"
+)
+np.argpartition(
+ A, 0, order=range(5) # E: Argument "order" to "argpartition" has incompatible type
+)
+
+np.sort(a) # E: Argument 1 to "sort" has incompatible type
+np.sort(A, axis="bob") # E: Argument "axis" to "sort" has incompatible type
+np.sort(A, kind="bob") # E: Argument "kind" to "sort" has incompatible type
+np.sort(A, order=range(5)) # E: Argument "order" to "sort" has incompatible type
+
+np.argsort(a) # E: Argument 1 to "argsort" has incompatible type
+np.argsort(A, axis="bob") # E: Argument "axis" to "argsort" has incompatible type
+np.argsort(A, kind="bob") # E: Argument "kind" to "argsort" has incompatible type
+np.argsort(A, order=range(5)) # E: Argument "order" to "argsort" has incompatible type
+
+np.argmax(a) # E: No overload variant of "argmax" matches argument type
+np.argmax(A, axis="bob") # E: No overload variant of "argmax" matches argument type
+np.argmax(A, kind="bob") # E: No overload variant of "argmax" matches argument type
+
+np.argmin(a) # E: No overload variant of "argmin" matches argument type
+np.argmin(A, axis="bob") # E: No overload variant of "argmin" matches argument type
+np.argmin(A, kind="bob") # E: No overload variant of "argmin" matches argument type
+
+np.searchsorted(a, 0) # E: No overload variant of "searchsorted" matches argument type
+np.searchsorted( # E: No overload variant of "searchsorted" matches argument type
+ A[0], 0, side="bob"
+)
+np.searchsorted( # E: No overload variant of "searchsorted" matches argument type
+ A[0], 0, sorter=1.0
+)
+
+np.resize(A, 1.0) # E: Argument 2 to "resize" has incompatible type
+
+np.squeeze(A, 1.0) # E: No overload variant of "squeeze" matches argument type
+
+np.diagonal(a) # E: Argument 1 to "diagonal" has incompatible type
+np.diagonal(A, offset=None) # E: Argument "offset" to "diagonal" has incompatible type
+np.diagonal(A, axis1="bob") # E: Argument "axis1" to "diagonal" has incompatible type
+np.diagonal(A, axis2=[]) # E: Argument "axis2" to "diagonal" has incompatible type
+
+np.trace(a) # E: Argument 1 to "trace" has incompatible type
+np.trace(A, offset=None) # E: Argument "offset" to "trace" has incompatible type
+np.trace(A, axis1="bob") # E: Argument "axis1" to "trace" has incompatible type
+np.trace(A, axis2=[]) # E: Argument "axis2" to "trace" has incompatible type
+
+np.ravel(a, order="bob") # E: Argument "order" to "ravel" has incompatible type
+
+np.compress(True, A) # E: Argument 1 to "compress" has incompatible type
+np.compress(
+ [True], A, axis=1.0 # E: Argument "axis" to "compress" has incompatible type
+)
diff --git a/numpy/tests/fail/ndarray.py b/numpy/tests/fail/ndarray.py
new file mode 100644
index 000000000..5a5130d40
--- /dev/null
+++ b/numpy/tests/fail/ndarray.py
@@ -0,0 +1,11 @@
+import numpy as np
+
+# Ban setting dtype since mutating the type of the array in place
+# makes having ndarray be generic over dtype impossible. Generally
+# users should use `ndarray.view` in this situation anyway. See
+#
+# https://github.com/numpy/numpy-stubs/issues/7
+#
+# for more context.
+float_array = np.array([1.0])
+float_array.dtype = np.bool_ # E: Property "dtype" defined in "ndarray" is read-only
diff --git a/numpy/tests/fail/numerictypes.py b/numpy/tests/fail/numerictypes.py
new file mode 100644
index 000000000..dd03eacc1
--- /dev/null
+++ b/numpy/tests/fail/numerictypes.py
@@ -0,0 +1,13 @@
+import numpy as np
+
+# Techincally this works, but probably shouldn't. See
+#
+# https://github.com/numpy/numpy/issues/16366
+#
+np.maximum_sctype(1) # E: incompatible type "int"
+
+np.issubsctype(1, np.int64) # E: incompatible type "int"
+
+np.issubdtype(1, np.int64) # E: incompatible type "int"
+
+np.find_common_type(np.int64, np.int64) # E: incompatible type "Type[int64]"
diff --git a/numpy/tests/fail/scalars.py b/numpy/tests/fail/scalars.py
new file mode 100644
index 000000000..0dfc55124
--- /dev/null
+++ b/numpy/tests/fail/scalars.py
@@ -0,0 +1,67 @@
+import numpy as np
+
+# Construction
+
+np.float32(3j) # E: incompatible type
+
+# Technically the following examples are valid NumPy code. But they
+# are not considered a best practice, and people who wish to use the
+# stubs should instead do
+#
+# np.array([1.0, 0.0, 0.0], dtype=np.float32)
+# np.array([], dtype=np.complex64)
+#
+# See e.g. the discussion on the mailing list
+#
+# https://mail.python.org/pipermail/numpy-discussion/2020-April/080566.html
+#
+# and the issue
+#
+# https://github.com/numpy/numpy-stubs/issues/41
+#
+# for more context.
+np.float32([1.0, 0.0, 0.0]) # E: incompatible type
+np.complex64([]) # E: incompatible type
+
+np.complex64(1, 2) # E: Too many arguments
+# TODO: protocols (can't check for non-existent protocols w/ __getattr__)
+
+np.datetime64(0) # E: non-matching overload
+
+dt_64 = np.datetime64(0, "D")
+td_64 = np.timedelta64(1, "h")
+
+dt_64 + dt_64 # E: Unsupported operand types
+
+td_64 - dt_64 # E: Unsupported operand types
+td_64 / dt_64 # E: No overload
+td_64 % 1 # E: Unsupported operand types
+td_64 % dt_64 # E: Unsupported operand types
+
+
+class A:
+ def __float__(self):
+ return 1.0
+
+
+np.int8(A()) # E: incompatible type
+np.int16(A()) # E: incompatible type
+np.int32(A()) # E: incompatible type
+np.int64(A()) # E: incompatible type
+np.uint8(A()) # E: incompatible type
+np.uint16(A()) # E: incompatible type
+np.uint32(A()) # E: incompatible type
+np.uint64(A()) # E: incompatible type
+
+np.void("test") # E: incompatible type
+
+np.generic(1) # E: Cannot instantiate abstract class
+np.number(1) # E: Cannot instantiate abstract class
+np.integer(1) # E: Cannot instantiate abstract class
+np.signedinteger(1) # E: Cannot instantiate abstract class
+np.unsignedinteger(1) # E: Cannot instantiate abstract class
+np.inexact(1) # E: Cannot instantiate abstract class
+np.floating(1) # E: Cannot instantiate abstract class
+np.complexfloating(1) # E: Cannot instantiate abstract class
+np.character("test") # E: Cannot instantiate abstract class
+np.flexible(b"test") # E: Cannot instantiate abstract class
diff --git a/numpy/tests/fail/simple.py b/numpy/tests/fail/simple.py
new file mode 100644
index 000000000..b5e9d1b13
--- /dev/null
+++ b/numpy/tests/fail/simple.py
@@ -0,0 +1,10 @@
+"""Simple expression that should fail with mypy."""
+
+import numpy as np
+
+# Array creation routines checks
+np.zeros("test") # E: incompatible type
+np.zeros() # E: Too few arguments
+
+np.ones("test") # E: incompatible type
+np.ones() # E: Too few arguments
diff --git a/numpy/tests/fail/ufuncs.py b/numpy/tests/fail/ufuncs.py
new file mode 100644
index 000000000..b178a4ea4
--- /dev/null
+++ b/numpy/tests/fail/ufuncs.py
@@ -0,0 +1,5 @@
+import numpy as np
+
+np.sin.nin + "foo" # E: Unsupported operand types
+np.sin(1, foo="bar") # E: Unexpected keyword argument
+np.sin(1, extobj=["foo", "foo", "foo"]) # E: incompatible type
diff --git a/numpy/tests/fail/warnings_and_errors.py b/numpy/tests/fail/warnings_and_errors.py
new file mode 100644
index 000000000..7390cc45f
--- /dev/null
+++ b/numpy/tests/fail/warnings_and_errors.py
@@ -0,0 +1,7 @@
+import numpy as np
+
+np.AxisError(1.0) # E: Argument 1 to "AxisError" has incompatible type
+np.AxisError(1, ndim=2.0) # E: Argument "ndim" to "AxisError" has incompatible type
+np.AxisError(
+ 2, msg_prefix=404 # E: Argument "msg_prefix" to "AxisError" has incompatible type
+)
diff --git a/numpy/tests/mypy.ini b/numpy/tests/mypy.ini
new file mode 100644
index 000000000..cad431a03
--- /dev/null
+++ b/numpy/tests/mypy.ini
@@ -0,0 +1,8 @@
+[mypy]
+mypy_path = ../..
+
+[mypy-numpy]
+ignore_errors = True
+
+[mypy-numpy.*]
+ignore_errors = True
diff --git a/numpy/tests/pass/array_like.py b/numpy/tests/pass/array_like.py
new file mode 100644
index 000000000..098149c4b
--- /dev/null
+++ b/numpy/tests/pass/array_like.py
@@ -0,0 +1,44 @@
+from typing import Any, List, Optional, TYPE_CHECKING
+
+import numpy as np
+
+if TYPE_CHECKING:
+ from numpy.typing import ArrayLike, DtypeLike, _SupportsArray
+else:
+ ArrayLike = Any
+ DtypeLike = Any
+ _SupportsArray = Any
+
+x1: ArrayLike = True
+x2: ArrayLike = 5
+x3: ArrayLike = 1.0
+x4: ArrayLike = 1 + 1j
+x5: ArrayLike = np.int8(1)
+x6: ArrayLike = np.float64(1)
+x7: ArrayLike = np.complex128(1)
+x8: ArrayLike = np.array([1, 2, 3])
+x9: ArrayLike = [1, 2, 3]
+x10: ArrayLike = (1, 2, 3)
+x11: ArrayLike = "foo"
+
+
+class A:
+ def __array__(self, dtype: DtypeLike = None) -> np.ndarray:
+ return np.array([1, 2, 3])
+
+
+x12: ArrayLike = A()
+
+scalar: _SupportsArray = np.int64(1)
+scalar.__array__(np.float64)
+array: _SupportsArray = np.array(1)
+array.__array__(np.float64)
+
+a: _SupportsArray = A()
+a.__array__(np.int64)
+a.__array__(dtype=np.int64)
+
+# Escape hatch for when you mean to make something like an object
+# array.
+object_array_scalar: Any = (i for i in range(10))
+np.array(object_array_scalar)
diff --git a/numpy/tests/pass/fromnumeric.py b/numpy/tests/pass/fromnumeric.py
new file mode 100644
index 000000000..0ce8ef970
--- /dev/null
+++ b/numpy/tests/pass/fromnumeric.py
@@ -0,0 +1,116 @@
+"""Tests for :mod:`numpy.core.fromnumeric`."""
+
+import numpy as np
+
+A = np.array(True, ndmin=2, dtype=bool)
+B = np.array(1.0, ndmin=2, dtype=np.float32)
+A.setflags(write=False)
+B.setflags(write=False)
+
+a = np.bool_(True)
+b = np.float32(1.0)
+c = 1.0
+
+np.take(a, 0)
+np.take(b, 0)
+np.take(c, 0)
+np.take(A, 0)
+np.take(B, 0)
+np.take(A, [0])
+np.take(B, [0])
+
+np.reshape(a, 1)
+np.reshape(b, 1)
+np.reshape(c, 1)
+np.reshape(A, 1)
+np.reshape(B, 1)
+
+np.choose(a, [True, True])
+np.choose(A, [1.0, 1.0])
+
+np.repeat(a, 1)
+np.repeat(b, 1)
+np.repeat(c, 1)
+np.repeat(A, 1)
+np.repeat(B, 1)
+
+np.swapaxes(A, 0, 0)
+np.swapaxes(B, 0, 0)
+
+np.transpose(a)
+np.transpose(b)
+np.transpose(c)
+np.transpose(A)
+np.transpose(B)
+
+np.partition(a, 0, axis=None)
+np.partition(b, 0, axis=None)
+np.partition(c, 0, axis=None)
+np.partition(A, 0)
+np.partition(B, 0)
+
+np.argpartition(a, 0)
+np.argpartition(b, 0)
+np.argpartition(c, 0)
+np.argpartition(A, 0)
+np.argpartition(B, 0)
+
+np.sort(A, 0)
+np.sort(B, 0)
+
+np.argsort(A, 0)
+np.argsort(B, 0)
+
+np.argmax(A)
+np.argmax(B)
+np.argmax(A, axis=0)
+np.argmax(B, axis=0)
+
+np.argmin(A)
+np.argmin(B)
+np.argmin(A, axis=0)
+np.argmin(B, axis=0)
+
+np.searchsorted(A[0], 0)
+np.searchsorted(B[0], 0)
+np.searchsorted(A[0], [0])
+np.searchsorted(B[0], [0])
+
+np.resize(a, (5, 5))
+np.resize(b, (5, 5))
+np.resize(c, (5, 5))
+np.resize(A, (5, 5))
+np.resize(B, (5, 5))
+
+np.squeeze(a)
+np.squeeze(b)
+np.squeeze(c)
+np.squeeze(A)
+np.squeeze(B)
+
+np.diagonal(A)
+np.diagonal(B)
+
+np.trace(A)
+np.trace(B)
+
+np.ravel(a)
+np.ravel(b)
+np.ravel(c)
+np.ravel(A)
+np.ravel(B)
+
+np.nonzero(A)
+np.nonzero(B)
+
+np.shape(a)
+np.shape(b)
+np.shape(c)
+np.shape(A)
+np.shape(B)
+
+np.compress([True], a)
+np.compress([True], b)
+np.compress([True], c)
+np.compress([True], A)
+np.compress([True], B)
diff --git a/numpy/tests/pass/ndarray_conversion.py b/numpy/tests/pass/ndarray_conversion.py
new file mode 100644
index 000000000..303cf53e4
--- /dev/null
+++ b/numpy/tests/pass/ndarray_conversion.py
@@ -0,0 +1,94 @@
+import os
+import tempfile
+
+import numpy as np
+
+nd = np.array([[1, 2], [3, 4]])
+scalar_array = np.array(1)
+
+# item
+scalar_array.item()
+nd.item(1)
+nd.item(0, 1)
+nd.item((0, 1))
+
+# tolist is pretty simple
+
+# itemset
+scalar_array.itemset(3)
+nd.itemset(3, 0)
+nd.itemset((0, 0), 3)
+
+# tobytes
+nd.tobytes()
+nd.tobytes("C")
+nd.tobytes(None)
+
+# tofile
+if os.name != "nt":
+ with tempfile.NamedTemporaryFile(suffix=".txt") as tmp:
+ nd.tofile(tmp.name)
+ nd.tofile(tmp.name, "")
+ nd.tofile(tmp.name, sep="")
+
+ nd.tofile(tmp.name, "", "%s")
+ nd.tofile(tmp.name, format="%s")
+
+ nd.tofile(tmp)
+
+# dump is pretty simple
+# dumps is pretty simple
+
+# astype
+nd.astype("float")
+nd.astype(float)
+
+nd.astype(float, "K")
+nd.astype(float, order="K")
+
+nd.astype(float, "K", "unsafe")
+nd.astype(float, casting="unsafe")
+
+nd.astype(float, "K", "unsafe", True)
+nd.astype(float, subok=True)
+
+nd.astype(float, "K", "unsafe", True, True)
+nd.astype(float, copy=True)
+
+# byteswap
+nd.byteswap()
+nd.byteswap(True)
+
+# copy
+nd.copy()
+nd.copy("C")
+
+# view
+nd.view()
+nd.view(np.int64)
+nd.view(dtype=np.int64)
+nd.view(np.int64, np.matrix)
+nd.view(type=np.matrix)
+
+# getfield
+complex_array = np.array([[1 + 1j, 0], [0, 1 - 1j]], dtype=np.complex128)
+
+complex_array.getfield("float")
+complex_array.getfield(float)
+
+complex_array.getfield("float", 8)
+complex_array.getfield(float, offset=8)
+
+# setflags
+nd.setflags()
+
+nd.setflags(True)
+nd.setflags(write=True)
+
+nd.setflags(True, True)
+nd.setflags(write=True, align=True)
+
+nd.setflags(True, True, False)
+nd.setflags(write=True, align=True, uic=False)
+
+# fill is pretty simple
diff --git a/numpy/tests/pass/ndarray_shape_manipulation.py b/numpy/tests/pass/ndarray_shape_manipulation.py
new file mode 100644
index 000000000..0ca3dff39
--- /dev/null
+++ b/numpy/tests/pass/ndarray_shape_manipulation.py
@@ -0,0 +1,47 @@
+import numpy as np
+
+nd1 = np.array([[1, 2], [3, 4]])
+
+# reshape
+nd1.reshape(4)
+nd1.reshape(2, 2)
+nd1.reshape((2, 2))
+
+nd1.reshape((2, 2), order="C")
+nd1.reshape(4, order="C")
+
+# resize
+nd1.resize()
+nd1.resize(4)
+nd1.resize(2, 2)
+nd1.resize((2, 2))
+
+nd1.resize((2, 2), refcheck=True)
+nd1.resize(4, refcheck=True)
+
+nd2 = np.array([[1, 2], [3, 4]])
+
+# transpose
+nd2.transpose()
+nd2.transpose(1, 0)
+nd2.transpose((1, 0))
+
+# swapaxes
+nd2.swapaxes(0, 1)
+
+# flatten
+nd2.flatten()
+nd2.flatten("C")
+
+# ravel
+nd2.ravel()
+nd2.ravel("C")
+
+# squeeze
+nd2.squeeze()
+
+nd3 = np.array([[1, 2]])
+nd3.squeeze(0)
+
+nd4 = np.array([[[1, 2]]])
+nd4.squeeze((0, 1))
diff --git a/numpy/tests/pass/numerictypes.py b/numpy/tests/pass/numerictypes.py
new file mode 100644
index 000000000..4f205cabc
--- /dev/null
+++ b/numpy/tests/pass/numerictypes.py
@@ -0,0 +1,29 @@
+import numpy as np
+
+np.maximum_sctype("S8")
+np.maximum_sctype(object)
+
+np.issctype(object)
+np.issctype("S8")
+
+np.obj2sctype(list)
+np.obj2sctype(list, default=None)
+np.obj2sctype(list, default=np.string_)
+
+np.issubclass_(np.int32, int)
+np.issubclass_(np.float64, float)
+np.issubclass_(np.float64, (int, float))
+
+np.issubsctype("int64", int)
+np.issubsctype(np.array([1]), np.array([1]))
+
+np.issubdtype("S1", np.string_)
+np.issubdtype(np.float64, np.float32)
+
+np.sctype2char("S1")
+np.sctype2char(list)
+
+np.find_common_type([], [np.int64, np.float32, complex])
+np.find_common_type((), (np.int64, np.float32, complex))
+np.find_common_type([np.int64, np.float32], [])
+np.find_common_type([np.float32], [np.int64, np.float64])
diff --git a/numpy/tests/pass/scalars.py b/numpy/tests/pass/scalars.py
new file mode 100644
index 000000000..bd055673b
--- /dev/null
+++ b/numpy/tests/pass/scalars.py
@@ -0,0 +1,88 @@
+import numpy as np
+
+
+# Construction
+class C:
+ def __complex__(self):
+ return 3j
+
+
+class B:
+ def __int__(self):
+ return 4
+
+
+class A:
+ def __float__(self):
+ return 4.0
+
+
+np.complex64(3j)
+np.complex64(C())
+np.complex128(3j)
+np.complex128(C())
+
+np.int8(4)
+np.int16(3.4)
+np.int32(4)
+np.int64(-1)
+np.uint8(B())
+np.uint32()
+
+np.float16(A())
+np.float32(16)
+np.float64(3.0)
+
+np.bytes_(b"hello")
+np.str_("hello")
+
+# Protocols
+float(np.int8(4))
+int(np.int16(5))
+np.int8(np.float32(6))
+
+# TODO(alan): test after https://github.com/python/typeshed/pull/2004
+# complex(np.int32(8))
+
+abs(np.int8(4))
+
+# Array-ish semantics
+np.int8().real
+np.int16().imag
+np.int32().data
+np.int64().flags
+
+np.uint8().itemsize * 2
+np.uint16().ndim + 1
+np.uint32().strides
+np.uint64().shape
+
+# Time structures
+np.datetime64()
+np.datetime64(0, "D")
+np.datetime64("2019")
+np.datetime64("2019", "D")
+
+np.timedelta64()
+np.timedelta64(0)
+np.timedelta64(0, "D")
+
+dt_64 = np.datetime64(0, "D")
+td_64 = np.timedelta64(1, "h")
+
+dt_64 + td_64
+dt_64 - dt_64
+dt_64 - td_64
+
+td_64 + td_64
+td_64 - td_64
+td_64 / 1.0
+td_64 / td_64
+td_64 % td_64
+
+np.void(1)
+np.void(np.int64(1))
+np.void(True)
+np.void(np.bool_(True))
+np.void(b"test")
+np.void(np.bytes_("test"))
diff --git a/numpy/tests/pass/simple.py b/numpy/tests/pass/simple.py
new file mode 100644
index 000000000..b9715da5d
--- /dev/null
+++ b/numpy/tests/pass/simple.py
@@ -0,0 +1,175 @@
+"""Simple expression that should pass with mypy."""
+import operator
+
+import numpy as np
+from typing import Iterable # noqa: F401
+
+# Basic checks
+array = np.array([1, 2])
+
+
+def ndarray_func(x):
+ # type: (np.ndarray) -> np.ndarray
+ return x
+
+
+ndarray_func(np.array([1, 2]))
+array == 1
+array.dtype == float
+
+# Array creation routines checks
+ndarray_func(np.zeros([1, 2]))
+ndarray_func(np.ones([1, 2]))
+ndarray_func(np.empty([1, 2]))
+
+ndarray_func(np.zeros_like(array))
+ndarray_func(np.ones_like(array))
+ndarray_func(np.empty_like(array))
+
+# Dtype construction
+np.dtype(float)
+np.dtype(np.float64)
+np.dtype(None)
+np.dtype("float64")
+np.dtype(np.dtype(float))
+np.dtype(("U", 10))
+np.dtype((np.int32, (2, 2)))
+# Define the arguments on the previous line to prevent bidirectional
+# type inference in mypy from broadening the types.
+two_tuples_dtype = [("R", "u1"), ("G", "u1"), ("B", "u1")]
+np.dtype(two_tuples_dtype)
+
+three_tuples_dtype = [("R", "u1", 2)]
+np.dtype(three_tuples_dtype)
+
+mixed_tuples_dtype = [("R", "u1"), ("G", np.unicode_, 1)]
+np.dtype(mixed_tuples_dtype)
+
+shape_tuple_dtype = [("R", "u1", (2, 2))]
+np.dtype(shape_tuple_dtype)
+
+shape_like_dtype = [("R", "u1", (2, 2)), ("G", np.unicode_, 1)]
+np.dtype(shape_like_dtype)
+
+object_dtype = [("field1", object)]
+np.dtype(object_dtype)
+
+np.dtype({"col1": ("U10", 0), "col2": ("float32", 10)})
+np.dtype((np.int32, {"real": (np.int16, 0), "imag": (np.int16, 2)}))
+np.dtype((np.int32, (np.int8, 4)))
+
+# Dtype comparision
+np.dtype(float) == float
+np.dtype(float) != np.float64
+np.dtype(float) < None
+np.dtype(float) <= "float64"
+np.dtype(float) > np.dtype(float)
+np.dtype(float) >= np.dtype(("U", 10))
+
+# Iteration and indexing
+def iterable_func(x):
+ # type: (Iterable) -> Iterable
+ return x
+
+
+iterable_func(array)
+[element for element in array]
+iter(array)
+zip(array, array)
+array[1]
+array[:]
+array[...]
+array[:] = 0
+
+array_2d = np.ones((3, 3))
+array_2d[:2, :2]
+array_2d[..., 0]
+array_2d[:2, :2] = 0
+
+# Other special methods
+len(array)
+str(array)
+array_scalar = np.array(1)
+int(array_scalar)
+float(array_scalar)
+# currently does not work due to https://github.com/python/typeshed/issues/1904
+# complex(array_scalar)
+bytes(array_scalar)
+operator.index(array_scalar)
+bool(array_scalar)
+
+# comparisons
+array < 1
+array <= 1
+array == 1
+array != 1
+array > 1
+array >= 1
+1 < array
+1 <= array
+1 == array
+1 != array
+1 > array
+1 >= array
+
+# binary arithmetic
+array + 1
+1 + array
+array += 1
+
+array - 1
+1 - array
+array -= 1
+
+array * 1
+1 * array
+array *= 1
+
+array / 1
+1 / array
+float_array = np.array([1.0, 2.0])
+float_array /= 1
+
+array // 1
+1 // array
+array //= 1
+
+array % 1
+1 % array
+array %= 1
+
+divmod(array, 1)
+divmod(1, array)
+
+array ** 1
+1 ** array
+array **= 1
+
+array << 1
+1 << array
+array <<= 1
+
+array >> 1
+1 >> array
+array >>= 1
+
+array & 1
+1 & array
+array &= 1
+
+array ^ 1
+1 ^ array
+array ^= 1
+
+array | 1
+1 | array
+array |= 1
+
+# unary arithmetic
+-array
++array
+abs(array)
+~array
+
+# Other methods
+np.array([1, 2]).transpose()
diff --git a/numpy/tests/pass/simple_py3.py b/numpy/tests/pass/simple_py3.py
new file mode 100644
index 000000000..c05a1ce61
--- /dev/null
+++ b/numpy/tests/pass/simple_py3.py
@@ -0,0 +1,6 @@
+import numpy as np
+
+array = np.array([1, 2])
+
+# The @ operator is not in python 2
+array @ array
diff --git a/numpy/tests/pass/ufuncs.py b/numpy/tests/pass/ufuncs.py
new file mode 100644
index 000000000..c81ac48d1
--- /dev/null
+++ b/numpy/tests/pass/ufuncs.py
@@ -0,0 +1,11 @@
+import numpy as np
+
+np.sin(1)
+np.sin([1, 2, 3])
+np.sin(1, out=np.empty(1))
+np.matmul(np.ones((2, 2, 2)), np.ones((2, 2, 2)), axes=[(0, 1), (0, 1), (0, 1)])
+np.sin(1, signature="D")
+np.sin(1, extobj=[16, 1, lambda: None])
+np.sin(1) + np.sin(1)
+np.sin.types[0]
+np.sin.__name__
diff --git a/numpy/tests/pass/warnings_and_errors.py b/numpy/tests/pass/warnings_and_errors.py
new file mode 100644
index 000000000..5b6ec2626
--- /dev/null
+++ b/numpy/tests/pass/warnings_and_errors.py
@@ -0,0 +1,7 @@
+import numpy as np
+
+np.AxisError(1)
+np.AxisError(1, ndim=2)
+np.AxisError(1, ndim=None)
+np.AxisError(1, ndim=2, msg_prefix="error")
+np.AxisError(1, ndim=2, msg_prefix=None)
diff --git a/numpy/tests/reveal/constants.py b/numpy/tests/reveal/constants.py
new file mode 100644
index 000000000..8e00810bd
--- /dev/null
+++ b/numpy/tests/reveal/constants.py
@@ -0,0 +1,44 @@
+import numpy as np
+
+reveal_type(np.Inf) # E: float
+reveal_type(np.Infinity) # E: float
+reveal_type(np.NAN) # E: float
+reveal_type(np.NINF) # E: float
+reveal_type(np.NZERO) # E: float
+reveal_type(np.NaN) # E: float
+reveal_type(np.PINF) # E: float
+reveal_type(np.PZERO) # E: float
+reveal_type(np.e) # E: float
+reveal_type(np.euler_gamma) # E: float
+reveal_type(np.inf) # E: float
+reveal_type(np.infty) # E: float
+reveal_type(np.nan) # E: float
+reveal_type(np.pi) # E: float
+
+reveal_type(np.ALLOW_THREADS) # E: int
+reveal_type(np.BUFSIZE) # E: int
+reveal_type(np.CLIP) # E: int
+reveal_type(np.ERR_CALL) # E: int
+reveal_type(np.ERR_DEFAULT) # E: int
+reveal_type(np.ERR_IGNORE) # E: int
+reveal_type(np.ERR_LOG) # E: int
+reveal_type(np.ERR_PRINT) # E: int
+reveal_type(np.ERR_RAISE) # E: int
+reveal_type(np.ERR_WARN) # E: int
+reveal_type(np.FLOATING_POINT_SUPPORT) # E: int
+reveal_type(np.FPE_DIVIDEBYZERO) # E: int
+reveal_type(np.FPE_INVALID) # E: int
+reveal_type(np.FPE_OVERFLOW) # E: int
+reveal_type(np.FPE_UNDERFLOW) # E: int
+reveal_type(np.MAXDIMS) # E: int
+reveal_type(np.MAY_SHARE_BOUNDS) # E: int
+reveal_type(np.MAY_SHARE_EXACT) # E: int
+reveal_type(np.RAISE) # E: int
+reveal_type(np.SHIFT_DIVIDEBYZERO) # E: int
+reveal_type(np.SHIFT_INVALID) # E: int
+reveal_type(np.SHIFT_OVERFLOW) # E: int
+reveal_type(np.SHIFT_UNDERFLOW) # E: int
+reveal_type(np.UFUNC_BUFSIZE_DEFAULT) # E: int
+reveal_type(np.WRAP) # E: int
+reveal_type(np.little_endian) # E: int
+reveal_type(np.tracemalloc_domain) # E: int
diff --git a/numpy/tests/reveal/fromnumeric.py b/numpy/tests/reveal/fromnumeric.py
new file mode 100644
index 000000000..7d79d5fa9
--- /dev/null
+++ b/numpy/tests/reveal/fromnumeric.py
@@ -0,0 +1,135 @@
+"""Tests for :mod:`numpy.core.fromnumeric`."""
+
+import numpy as np
+
+A = np.array(True, ndmin=2, dtype=bool)
+B = np.array(1.0, ndmin=2, dtype=np.float32)
+A.setflags(write=False)
+B.setflags(write=False)
+
+a = np.bool_(True)
+b = np.float32(1.0)
+c = 1.0
+
+reveal_type(np.take(a, 0)) # E: numpy.bool_
+reveal_type(np.take(b, 0)) # E: numpy.float32
+reveal_type(
+ np.take(c, 0) # E: Union[numpy.generic, datetime.datetime, datetime.timedelta]
+)
+reveal_type(
+ np.take(A, 0) # E: Union[numpy.generic, datetime.datetime, datetime.timedelta]
+)
+reveal_type(
+ np.take(B, 0) # E: Union[numpy.generic, datetime.datetime, datetime.timedelta]
+)
+reveal_type(
+ np.take( # E: Union[Union[numpy.generic, datetime.datetime, datetime.timedelta], numpy.ndarray]
+ A, [0]
+ )
+)
+reveal_type(
+ np.take( # E: Union[Union[numpy.generic, datetime.datetime, datetime.timedelta], numpy.ndarray]
+ B, [0]
+ )
+)
+
+reveal_type(np.reshape(a, 1)) # E: numpy.ndarray
+reveal_type(np.reshape(b, 1)) # E: numpy.ndarray
+reveal_type(np.reshape(c, 1)) # E: numpy.ndarray
+reveal_type(np.reshape(A, 1)) # E: numpy.ndarray
+reveal_type(np.reshape(B, 1)) # E: numpy.ndarray
+
+reveal_type(np.choose(a, [True, True])) # E: numpy.bool_
+reveal_type(np.choose(A, [True, True])) # E: numpy.ndarray
+
+reveal_type(np.repeat(a, 1)) # E: numpy.ndarray
+reveal_type(np.repeat(b, 1)) # E: numpy.ndarray
+reveal_type(np.repeat(c, 1)) # E: numpy.ndarray
+reveal_type(np.repeat(A, 1)) # E: numpy.ndarray
+reveal_type(np.repeat(B, 1)) # E: numpy.ndarray
+
+# TODO: Add tests for np.put()
+
+reveal_type(np.swapaxes(A, 0, 0)) # E: numpy.ndarray
+reveal_type(np.swapaxes(B, 0, 0)) # E: numpy.ndarray
+
+reveal_type(np.transpose(a)) # E: numpy.ndarray
+reveal_type(np.transpose(b)) # E: numpy.ndarray
+reveal_type(np.transpose(c)) # E: numpy.ndarray
+reveal_type(np.transpose(A)) # E: numpy.ndarray
+reveal_type(np.transpose(B)) # E: numpy.ndarray
+
+reveal_type(np.partition(a, 0, axis=None)) # E: numpy.ndarray
+reveal_type(np.partition(b, 0, axis=None)) # E: numpy.ndarray
+reveal_type(np.partition(c, 0, axis=None)) # E: numpy.ndarray
+reveal_type(np.partition(A, 0)) # E: numpy.ndarray
+reveal_type(np.partition(B, 0)) # E: numpy.ndarray
+
+reveal_type(np.argpartition(a, 0)) # E: numpy.integer
+reveal_type(np.argpartition(b, 0)) # E: numpy.integer
+reveal_type(np.argpartition(c, 0)) # E: numpy.ndarray
+reveal_type(np.argpartition(A, 0)) # E: numpy.ndarray
+reveal_type(np.argpartition(B, 0)) # E: numpy.ndarray
+
+reveal_type(np.sort(A, 0)) # E: numpy.ndarray
+reveal_type(np.sort(B, 0)) # E: numpy.ndarray
+
+reveal_type(np.argsort(A, 0)) # E: numpy.ndarray
+reveal_type(np.argsort(B, 0)) # E: numpy.ndarray
+
+reveal_type(np.argmax(A)) # E: numpy.integer
+reveal_type(np.argmax(B)) # E: numpy.integer
+reveal_type(np.argmax(A, axis=0)) # E: Union[numpy.integer, numpy.ndarray]
+reveal_type(np.argmax(B, axis=0)) # E: Union[numpy.integer, numpy.ndarray]
+
+reveal_type(np.argmin(A)) # E: numpy.integer
+reveal_type(np.argmin(B)) # E: numpy.integer
+reveal_type(np.argmin(A, axis=0)) # E: Union[numpy.integer, numpy.ndarray]
+reveal_type(np.argmin(B, axis=0)) # E: Union[numpy.integer, numpy.ndarray]
+
+reveal_type(np.searchsorted(A[0], 0)) # E: numpy.integer
+reveal_type(np.searchsorted(B[0], 0)) # E: numpy.integer
+reveal_type(np.searchsorted(A[0], [0])) # E: numpy.ndarray
+reveal_type(np.searchsorted(B[0], [0])) # E: numpy.ndarray
+
+reveal_type(np.resize(a, (5, 5))) # E: numpy.ndarray
+reveal_type(np.resize(b, (5, 5))) # E: numpy.ndarray
+reveal_type(np.resize(c, (5, 5))) # E: numpy.ndarray
+reveal_type(np.resize(A, (5, 5))) # E: numpy.ndarray
+reveal_type(np.resize(B, (5, 5))) # E: numpy.ndarray
+
+reveal_type(np.squeeze(a)) # E: numpy.bool_
+reveal_type(np.squeeze(b)) # E: numpy.float32
+reveal_type(np.squeeze(c)) # E: numpy.ndarray
+reveal_type(np.squeeze(A)) # E: numpy.ndarray
+reveal_type(np.squeeze(B)) # E: numpy.ndarray
+
+reveal_type(np.diagonal(A)) # E: numpy.ndarray
+reveal_type(np.diagonal(B)) # E: numpy.ndarray
+
+reveal_type(np.trace(A)) # E: Union[numpy.number, numpy.ndarray]
+reveal_type(np.trace(B)) # E: Union[numpy.number, numpy.ndarray]
+
+reveal_type(np.ravel(a)) # E: numpy.ndarray
+reveal_type(np.ravel(b)) # E: numpy.ndarray
+reveal_type(np.ravel(c)) # E: numpy.ndarray
+reveal_type(np.ravel(A)) # E: numpy.ndarray
+reveal_type(np.ravel(B)) # E: numpy.ndarray
+
+reveal_type(np.nonzero(a)) # E: tuple[numpy.ndarray]
+reveal_type(np.nonzero(b)) # E: tuple[numpy.ndarray]
+reveal_type(np.nonzero(c)) # E: tuple[numpy.ndarray]
+reveal_type(np.nonzero(A)) # E: tuple[numpy.ndarray]
+reveal_type(np.nonzero(B)) # E: tuple[numpy.ndarray]
+
+reveal_type(np.shape(a)) # E: tuple[builtins.int]
+reveal_type(np.shape(b)) # E: tuple[builtins.int]
+reveal_type(np.shape(c)) # E: tuple[builtins.int]
+reveal_type(np.shape(A)) # E: tuple[builtins.int]
+reveal_type(np.shape(B)) # E: tuple[builtins.int]
+
+reveal_type(np.compress([True], a)) # E: numpy.ndarray
+reveal_type(np.compress([True], b)) # E: numpy.ndarray
+reveal_type(np.compress([True], c)) # E: numpy.ndarray
+reveal_type(np.compress([True], A)) # E: numpy.ndarray
+reveal_type(np.compress([True], B)) # E: numpy.ndarray
diff --git a/numpy/tests/reveal/ndarray_conversion.py b/numpy/tests/reveal/ndarray_conversion.py
new file mode 100644
index 000000000..411adcf63
--- /dev/null
+++ b/numpy/tests/reveal/ndarray_conversion.py
@@ -0,0 +1,54 @@
+import numpy as np
+
+nd = np.array([[1, 2], [3, 4]])
+
+# item
+reveal_type(nd.item()) # E: Any
+reveal_type(nd.item(1)) # E: Any
+reveal_type(nd.item(0, 1)) # E: Any
+reveal_type(nd.item((0, 1))) # E: Any
+
+# tolist
+reveal_type(nd.tolist()) # E: builtins.list[Any]
+
+# itemset does not return a value
+# tostring is pretty simple
+# tobytes is pretty simple
+# tofile does not return a value
+# dump does not return a value
+# dumps is pretty simple
+
+# astype
+reveal_type(nd.astype("float")) # E: numpy.ndarray
+reveal_type(nd.astype(float)) # E: numpy.ndarray
+reveal_type(nd.astype(float, "K")) # E: numpy.ndarray
+reveal_type(nd.astype(float, "K", "unsafe")) # E: numpy.ndarray
+reveal_type(nd.astype(float, "K", "unsafe", True)) # E: numpy.ndarray
+reveal_type(nd.astype(float, "K", "unsafe", True, True)) # E: numpy.ndarray
+
+# byteswap
+reveal_type(nd.byteswap()) # E: numpy.ndarray
+reveal_type(nd.byteswap(True)) # E: numpy.ndarray
+
+# copy
+reveal_type(nd.copy()) # E: numpy.ndarray
+reveal_type(nd.copy("C")) # E: numpy.ndarray
+
+# view
+class SubArray(np.ndarray):
+ pass
+
+
+reveal_type(nd.view()) # E: numpy.ndarray
+reveal_type(nd.view(np.int64)) # E: numpy.ndarray
+# replace `Any` with `numpy.matrix` when `matrix` will be added to stubs
+reveal_type(nd.view(np.int64, np.matrix)) # E: Any
+reveal_type(nd.view(np.int64, SubArray)) # E: SubArray
+
+# getfield
+reveal_type(nd.getfield("float")) # E: numpy.ndarray
+reveal_type(nd.getfield(float)) # E: numpy.ndarray
+reveal_type(nd.getfield(float, 8)) # E: numpy.ndarray
+
+# setflags does not return a value
+# fill does not return a value
diff --git a/numpy/tests/reveal/ndarray_shape_manipulation.py b/numpy/tests/reveal/ndarray_shape_manipulation.py
new file mode 100644
index 000000000..a44e1cfa1
--- /dev/null
+++ b/numpy/tests/reveal/ndarray_shape_manipulation.py
@@ -0,0 +1,35 @@
+import numpy as np
+
+nd = np.array([[1, 2], [3, 4]])
+
+# reshape
+reveal_type(nd.reshape()) # E: numpy.ndarray
+reveal_type(nd.reshape(4)) # E: numpy.ndarray
+reveal_type(nd.reshape(2, 2)) # E: numpy.ndarray
+reveal_type(nd.reshape((2, 2))) # E: numpy.ndarray
+
+reveal_type(nd.reshape((2, 2), order="C")) # E: numpy.ndarray
+reveal_type(nd.reshape(4, order="C")) # E: numpy.ndarray
+
+# resize does not return a value
+
+# transpose
+reveal_type(nd.transpose()) # E: numpy.ndarray
+reveal_type(nd.transpose(1, 0)) # E: numpy.ndarray
+reveal_type(nd.transpose((1, 0))) # E: numpy.ndarray
+
+# swapaxes
+reveal_type(nd.swapaxes(0, 1)) # E: numpy.ndarray
+
+# flatten
+reveal_type(nd.flatten()) # E: numpy.ndarray
+reveal_type(nd.flatten("C")) # E: numpy.ndarray
+
+# ravel
+reveal_type(nd.ravel()) # E: numpy.ndarray
+reveal_type(nd.ravel("C")) # E: numpy.ndarray
+
+# squeeze
+reveal_type(nd.squeeze()) # E: numpy.ndarray
+reveal_type(nd.squeeze(0)) # E: numpy.ndarray
+reveal_type(nd.squeeze((0, 2))) # E: numpy.ndarray
diff --git a/numpy/tests/reveal/numerictypes.py b/numpy/tests/reveal/numerictypes.py
new file mode 100644
index 000000000..e026158cd
--- /dev/null
+++ b/numpy/tests/reveal/numerictypes.py
@@ -0,0 +1,18 @@
+import numpy as np
+
+reveal_type(np.issctype(np.generic)) # E: bool
+reveal_type(np.issctype("foo")) # E: bool
+
+reveal_type(np.obj2sctype("S8")) # E: Union[numpy.generic, None]
+reveal_type(np.obj2sctype("S8", default=None)) # E: Union[numpy.generic, None]
+reveal_type(
+ np.obj2sctype("foo", default=int) # E: Union[numpy.generic, Type[builtins.int*]]
+)
+
+reveal_type(np.issubclass_(np.float64, float)) # E: bool
+reveal_type(np.issubclass_(np.float64, (int, float))) # E: bool
+
+reveal_type(np.sctype2char("S8")) # E: str
+reveal_type(np.sctype2char(list)) # E: str
+
+reveal_type(np.find_common_type([np.int64], [np.int64])) # E: numpy.dtype
diff --git a/numpy/tests/reveal/scalars.py b/numpy/tests/reveal/scalars.py
new file mode 100644
index 000000000..8a9555fc3
--- /dev/null
+++ b/numpy/tests/reveal/scalars.py
@@ -0,0 +1,30 @@
+import numpy as np
+
+x = np.complex64(3 + 2j)
+
+reveal_type(x.real) # E: numpy.float32
+reveal_type(x.imag) # E: numpy.float32
+
+reveal_type(x.real.real) # E: numpy.float32
+reveal_type(x.real.imag) # E: numpy.float32
+
+reveal_type(x.itemsize) # E: int
+reveal_type(x.shape) # E: tuple[builtins.int]
+reveal_type(x.strides) # E: tuple[builtins.int]
+
+# Time structures
+dt = np.datetime64(0, "D")
+td = np.timedelta64(0, "D")
+
+reveal_type(dt + td) # E: numpy.datetime64
+reveal_type(dt + 1) # E: numpy.datetime64
+reveal_type(dt - dt) # E: numpy.timedelta64
+reveal_type(dt - 1) # E: numpy.timedelta64
+
+reveal_type(td + td) # E: numpy.timedelta64
+reveal_type(td + 1) # E: numpy.timedelta64
+reveal_type(td - td) # E: numpy.timedelta64
+reveal_type(td - 1) # E: numpy.timedelta64
+reveal_type(td / 1.0) # E: numpy.timedelta64
+reveal_type(td / td) # E: float
+reveal_type(td % td) # E: numpy.timedelta64
diff --git a/numpy/tests/reveal/warnings_and_errors.py b/numpy/tests/reveal/warnings_and_errors.py
new file mode 100644
index 000000000..c428deb7a
--- /dev/null
+++ b/numpy/tests/reveal/warnings_and_errors.py
@@ -0,0 +1,10 @@
+from typing import Type
+
+import numpy as np
+
+reveal_type(np.ModuleDeprecationWarning()) # E: numpy.ModuleDeprecationWarning
+reveal_type(np.VisibleDeprecationWarning()) # E: numpy.VisibleDeprecationWarning
+reveal_type(np.ComplexWarning()) # E: numpy.ComplexWarning
+reveal_type(np.RankWarning()) # E: numpy.RankWarning
+reveal_type(np.TooHardError()) # E: numpy.TooHardError
+reveal_type(np.AxisError(1)) # E: numpy.AxisError
diff --git a/numpy/tests/setup.py b/numpy/tests/setup.py
new file mode 100644
index 000000000..03900a82b
--- /dev/null
+++ b/numpy/tests/setup.py
@@ -0,0 +1,13 @@
+def configuration(parent_package='', top_path=None):
+ from numpy.distutils.misc_util import Configuration
+ config = Configuration('tests', parent_package, top_path)
+ config.add_data_dir('pass')
+ config.add_data_dir('fail')
+ config.add_data_dir('reveal')
+ config.add_data_files('mypy.ini')
+ return config
+
+
+if __name__ == '__main__':
+ from numpy.distutils.core import setup
+ setup(configuration=configuration)
diff --git a/numpy/tests/test_typing.py b/numpy/tests/test_typing.py
new file mode 100644
index 000000000..757ea0b52
--- /dev/null
+++ b/numpy/tests/test_typing.py
@@ -0,0 +1,127 @@
+import importlib.util
+import itertools
+import os
+import re
+from collections import defaultdict
+
+import pytest
+try:
+ from mypy import api
+except ImportError:
+ NO_MYPY = True
+else:
+ NO_MYPY = False
+
+TESTS_DIR = os.path.dirname(os.path.abspath(__file__))
+PASS_DIR = os.path.join(TESTS_DIR, "pass")
+FAIL_DIR = os.path.join(TESTS_DIR, "fail")
+REVEAL_DIR = os.path.join(TESTS_DIR, "reveal")
+MYPY_INI = os.path.join(TESTS_DIR, "mypy.ini")
+CACHE_DIR = os.path.join(TESTS_DIR, ".mypy_cache")
+
+
+def get_test_cases(directory):
+ for root, _, files in os.walk(directory):
+ for fname in files:
+ if os.path.splitext(fname)[-1] == ".py":
+ fullpath = os.path.join(root, fname)
+ # Use relative path for nice py.test name
+ relpath = os.path.relpath(fullpath, start=directory)
+
+ yield pytest.param(
+ fullpath,
+ # Manually specify a name for the test
+ id=relpath,
+ )
+
+
+@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed")
+@pytest.mark.parametrize("path", get_test_cases(PASS_DIR))
+def test_success(path):
+ stdout, stderr, exitcode = api.run([
+ "--config-file",
+ MYPY_INI,
+ "--cache-dir",
+ CACHE_DIR,
+ path,
+ ])
+ assert exitcode == 0, stdout
+ assert re.match(r"Success: no issues found in \d+ source files?", stdout.strip())
+
+
+@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed")
+@pytest.mark.parametrize("path", get_test_cases(FAIL_DIR))
+def test_fail(path):
+ stdout, stderr, exitcode = api.run([
+ "--config-file",
+ MYPY_INI,
+ "--cache-dir",
+ CACHE_DIR,
+ path,
+ ])
+ assert exitcode != 0
+
+ with open(path) as fin:
+ lines = fin.readlines()
+
+ errors = defaultdict(lambda: "")
+ error_lines = stdout.rstrip("\n").split("\n")
+ assert re.match(
+ r"Found \d+ errors? in \d+ files? \(checked \d+ source files?\)",
+ error_lines[-1].strip(),
+ )
+ for error_line in error_lines[:-1]:
+ error_line = error_line.strip()
+ if not error_line:
+ continue
+
+ lineno = int(error_line.split(":")[1])
+ errors[lineno] += error_line
+
+ for i, line in enumerate(lines):
+ lineno = i + 1
+ if " E:" not in line and lineno not in errors:
+ continue
+
+ target_line = lines[lineno - 1]
+ if "# E:" in target_line:
+ marker = target_line.split("# E:")[-1].strip()
+ assert lineno in errors, f'Extra error "{marker}"'
+ assert marker in errors[lineno]
+ else:
+ pytest.fail(f"Error {repr(errors[lineno])} not found")
+
+
+@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed")
+@pytest.mark.parametrize("path", get_test_cases(REVEAL_DIR))
+def test_reveal(path):
+ stdout, stderr, exitcode = api.run([
+ "--config-file",
+ MYPY_INI,
+ "--cache-dir",
+ CACHE_DIR,
+ path,
+ ])
+
+ with open(path) as fin:
+ lines = fin.readlines()
+
+ for error_line in stdout.split("\n"):
+ error_line = error_line.strip()
+ if not error_line:
+ continue
+
+ lineno = int(error_line.split(":")[1])
+ assert "Revealed type is" in error_line
+ marker = lines[lineno - 1].split("# E:")[-1].strip()
+ assert marker in error_line
+
+
+@pytest.mark.skipif(NO_MYPY, reason="Mypy is not installed")
+@pytest.mark.parametrize("path", get_test_cases(PASS_DIR))
+def test_code_runs(path):
+ path_without_extension, _ = os.path.splitext(path)
+ dirname, filename = path.split(os.sep)[-2:]
+ spec = importlib.util.spec_from_file_location(f"{dirname}.{filename}", path)
+ test_module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(test_module)
diff --git a/numpy/typing.pyi b/numpy/typing.pyi
new file mode 100644
index 000000000..f5705192a
--- /dev/null
+++ b/numpy/typing.pyi
@@ -0,0 +1,64 @@
+import sys
+from typing import Any, Dict, List, overload, Sequence, Text, Tuple, Union
+
+from numpy import dtype, ndarray
+
+if sys.version_info >= (3, 8):
+ from typing import Protocol
+else:
+ from typing_extensions import Protocol
+
+_Shape = Tuple[int, ...]
+
+# Anything that can be coerced to a shape tuple
+_ShapeLike = Union[int, Sequence[int]]
+
+_DtypeLikeNested = Any # TODO: wait for support for recursive types
+
+# Anything that can be coerced into numpy.dtype.
+# Reference: https://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html
+DtypeLike = Union[
+ dtype,
+ # default data type (float64)
+ None,
+ # array-scalar types and generic types
+ type, # TODO: enumerate these when we add type hints for numpy scalars
+ # TODO: add a protocol for anything with a dtype attribute
+ # character codes, type strings or comma-separated fields, e.g., 'float64'
+ str,
+ # (flexible_dtype, itemsize)
+ Tuple[_DtypeLikeNested, int],
+ # (fixed_dtype, shape)
+ Tuple[_DtypeLikeNested, _ShapeLike],
+ # [(field_name, field_dtype, field_shape), ...]
+ #
+ # The type here is quite broad because NumPy accepts quite a wide
+ # range of inputs inside the list; see the tests for some
+ # examples.
+ List[Any],
+ # {'names': ..., 'formats': ..., 'offsets': ..., 'titles': ...,
+ # 'itemsize': ...}
+ # TODO: use TypedDict when/if it's officially supported
+ Dict[
+ str,
+ Union[
+ Sequence[str], # names
+ Sequence[_DtypeLikeNested], # formats
+ Sequence[int], # offsets
+ Sequence[Union[bytes, Text, None]], # titles
+ int, # itemsize
+ ],
+ ],
+ # {'field1': ..., 'field2': ..., ...}
+ Dict[str, Tuple[_DtypeLikeNested, int]],
+ # (base_dtype, new_dtype)
+ Tuple[_DtypeLikeNested, _DtypeLikeNested],
+]
+
+class _SupportsArray(Protocol):
+ @overload
+ def __array__(self, __dtype: DtypeLike = ...) -> ndarray: ...
+ @overload
+ def __array__(self, dtype: DtypeLike = ...) -> ndarray: ...
+
+ArrayLike = Union[bool, int, float, complex, _SupportsArray, Sequence]