summaryrefslogtreecommitdiff
path: root/numpy/typing
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/typing')
-rw-r--r--numpy/typing/__init__.py81
-rw-r--r--numpy/typing/_array_like.py34
-rw-r--r--numpy/typing/_dtype_like.py46
-rw-r--r--numpy/typing/_shape.py6
4 files changed, 167 insertions, 0 deletions
diff --git a/numpy/typing/__init__.py b/numpy/typing/__init__.py
new file mode 100644
index 000000000..f2000823f
--- /dev/null
+++ b/numpy/typing/__init__.py
@@ -0,0 +1,81 @@
+"""
+============================
+Typing (:mod:`numpy.typing`)
+============================
+
+.. warning::
+
+ Some of the types in this module rely on features only present in
+ the standard library in Python 3.8 and greater. If you want to use
+ these types in earlier versions of Python, you should install the
+ typing-extensions_ package.
+
+Large parts of the NumPy API have PEP-484-style type annotations. In
+addition, the following type aliases are available for users.
+
+- ``typing.ArrayLike``: objects that can be converted to arrays
+- ``typing.DtypeLike``: objects that can be converted to dtypes
+
+Roughly speaking, ``typing.ArrayLike`` is "objects that can be used as
+inputs to ``np.array``" and ``typing.DtypeLike`` is "objects that can
+be used as inputs to ``np.dtype``".
+
+.. _typing-extensions: https://pypi.org/project/typing-extensions/
+
+Differences from the runtime NumPy API
+--------------------------------------
+
+NumPy is very flexible. Trying to describe the full range of
+possibilities statically would result in types that are not very
+helpful. For that reason, the typed NumPy API is often stricter than
+the runtime NumPy API. This section describes some notable
+differences.
+
+ArrayLike
+~~~~~~~~~
+
+The ``ArrayLike`` type tries to avoid creating object arrays. For
+example,
+
+.. code-block:: python
+
+ >>> np.array(x**2 for x in range(10))
+ array(<generator object <genexpr> at 0x10c004cd0>, dtype=object)
+
+is valid NumPy code which will create a 0-dimensional object
+array. Type checkers will complain about the above example when using
+the NumPy types however. If you really intended to do the above, then
+you can either use a ``# type: ignore`` comment:
+
+.. code-block:: python
+
+ >>> np.array(x**2 for x in range(10)) # type: ignore
+
+or explicitly type the array like object as ``Any``:
+
+.. code-block:: python
+
+ >>> from typing import Any
+ >>> array_like: Any = (x**2 for x in range(10))
+ >>> np.array(array_like)
+ array(<generator object <genexpr> at 0x1192741d0>, dtype=object)
+
+ndarray
+~~~~~~~
+
+It's possible to mutate the dtype of an array at runtime. For example,
+the following code is valid:
+
+.. code-block:: python
+
+ x = np.array([1, 2])
+ x.dtype = np.bool_
+
+This sort of mutation is not allowed by the types. Users who want to
+write statically typed code should insted use the `numpy.ndarray.view`
+method to create a view of the array with a different dtype.
+
+"""
+from ._array_like import _SupportsArray, ArrayLike
+from ._shape import _Shape, _ShapeLike
+from ._dtype_like import DtypeLike
diff --git a/numpy/typing/_array_like.py b/numpy/typing/_array_like.py
new file mode 100644
index 000000000..76c0c839c
--- /dev/null
+++ b/numpy/typing/_array_like.py
@@ -0,0 +1,34 @@
+import sys
+from typing import Any, overload, Sequence, TYPE_CHECKING, Union
+
+from numpy import ndarray
+from ._dtype_like import DtypeLike
+
+if sys.version_info >= (3, 8):
+ from typing import Protocol
+ HAVE_PROTOCOL = True
+else:
+ try:
+ from typing_extensions import Protocol
+ except ImportError:
+ HAVE_PROTOCOL = False
+ else:
+ HAVE_PROTOCOL = True
+
+if TYPE_CHECKING or HAVE_PROTOCOL:
+ class _SupportsArray(Protocol):
+ @overload
+ def __array__(self, __dtype: DtypeLike = ...) -> ndarray: ...
+ @overload
+ def __array__(self, dtype: DtypeLike = ...) -> ndarray: ...
+else:
+ _SupportsArray = Any
+
+# TODO: support buffer protocols once
+#
+# https://bugs.python.org/issue27501
+#
+# is resolved. See also the mypy issue:
+#
+# https://github.com/python/typing/issues/593
+ArrayLike = Union[bool, int, float, complex, _SupportsArray, Sequence]
diff --git a/numpy/typing/_dtype_like.py b/numpy/typing/_dtype_like.py
new file mode 100644
index 000000000..b9df0af04
--- /dev/null
+++ b/numpy/typing/_dtype_like.py
@@ -0,0 +1,46 @@
+from typing import Any, Dict, List, Sequence, Tuple, Union
+
+from numpy import dtype
+from ._shape import _ShapeLike
+
+_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, str, None]], # titles
+ int, # itemsize
+ ],
+ ],
+ # {'field1': ..., 'field2': ..., ...}
+ Dict[str, Tuple[_DtypeLikeNested, int]],
+ # (base_dtype, new_dtype)
+ Tuple[_DtypeLikeNested, _DtypeLikeNested],
+]
diff --git a/numpy/typing/_shape.py b/numpy/typing/_shape.py
new file mode 100644
index 000000000..4629046ea
--- /dev/null
+++ b/numpy/typing/_shape.py
@@ -0,0 +1,6 @@
+from typing import Sequence, Tuple, Union
+
+_Shape = Tuple[int, ...]
+
+# Anything that can be coerced to a shape tuple
+_ShapeLike = Union[int, Sequence[int]]