summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/upcoming_changes/16558.new_feature.rst9
-rw-r--r--doc/source/reference/index.rst1
-rw-r--r--doc/source/reference/typing.rst2
-rw-r--r--numpy/setup.py1
-rw-r--r--numpy/tests/test_public_api.py3
-rw-r--r--numpy/tests/typing/fail/array_like.py8
-rw-r--r--numpy/tests/typing/pass/array_like.py10
-rw-r--r--numpy/typing/__init__.py81
-rw-r--r--numpy/typing/_array_like.py34
-rw-r--r--numpy/typing/_dtype_like.py (renamed from numpy/typing.pyi)26
-rw-r--r--numpy/typing/_shape.py6
11 files changed, 143 insertions, 38 deletions
diff --git a/doc/release/upcoming_changes/16558.new_feature.rst b/doc/release/upcoming_changes/16558.new_feature.rst
new file mode 100644
index 000000000..9bd508e83
--- /dev/null
+++ b/doc/release/upcoming_changes/16558.new_feature.rst
@@ -0,0 +1,9 @@
+``numpy.typing`` is accessible at runtime
+-----------------------------------------
+The types in ``numpy.typing`` can now be imported at runtime. Code
+like the following will now work:
+
+.. code:: python
+
+ from numpy.typing import ArrayLike
+ x: ArrayLike = [1, 2, 3, 4]
diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst
index 2e1dcafa2..661a08ffa 100644
--- a/doc/source/reference/index.rst
+++ b/doc/source/reference/index.rst
@@ -22,6 +22,7 @@ For learning how to use NumPy, see the :ref:`complete documentation <numpy_docs_
constants
ufuncs
routines
+ typing
global_state
distutils
distutils_guide
diff --git a/doc/source/reference/typing.rst b/doc/source/reference/typing.rst
new file mode 100644
index 000000000..c948bc4be
--- /dev/null
+++ b/doc/source/reference/typing.rst
@@ -0,0 +1,2 @@
+.. _typing:
+.. automodule:: numpy.typing
diff --git a/numpy/setup.py b/numpy/setup.py
index c6498d101..cbf633504 100644
--- a/numpy/setup.py
+++ b/numpy/setup.py
@@ -17,6 +17,7 @@ def configuration(parent_package='',top_path=None):
config.add_subpackage('polynomial')
config.add_subpackage('random')
config.add_subpackage('testing')
+ config.add_subpackage('typing')
config.add_data_dir('doc')
config.add_data_files('py.typed')
config.add_data_files('*.pyi')
diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py
index 9fa61951a..df0e04285 100644
--- a/numpy/tests/test_public_api.py
+++ b/numpy/tests/test_public_api.py
@@ -102,7 +102,7 @@ def test_dir_testing():
"""Assert that output of dir has only one "testing/tester"
attribute without duplicate"""
assert len(dir(np)) == len(set(dir(np)))
-
+
def test_numpy_linalg():
bad_results = check_dir(np.linalg)
@@ -180,6 +180,7 @@ PUBLIC_MODULES = ['numpy.' + s for s in [
"polynomial.polyutils",
"random",
"testing",
+ "typing",
"version",
]]
diff --git a/numpy/tests/typing/fail/array_like.py b/numpy/tests/typing/fail/array_like.py
index a5ef5795f..a97e72dc7 100644
--- a/numpy/tests/typing/fail/array_like.py
+++ b/numpy/tests/typing/fail/array_like.py
@@ -1,11 +1,5 @@
-from typing import Any, TYPE_CHECKING
-
import numpy as np
-
-if TYPE_CHECKING:
- from numpy.typing import ArrayLike
-else:
- ArrayLike = Any
+from numpy.typing import ArrayLike
class A:
diff --git a/numpy/tests/typing/pass/array_like.py b/numpy/tests/typing/pass/array_like.py
index 098149c4b..e668b4963 100644
--- a/numpy/tests/typing/pass/array_like.py
+++ b/numpy/tests/typing/pass/array_like.py
@@ -1,13 +1,7 @@
-from typing import Any, List, Optional, TYPE_CHECKING
+from typing import Any, List, Optional
import numpy as np
-
-if TYPE_CHECKING:
- from numpy.typing import ArrayLike, DtypeLike, _SupportsArray
-else:
- ArrayLike = Any
- DtypeLike = Any
- _SupportsArray = Any
+from numpy.typing import ArrayLike, DtypeLike, _SupportsArray
x1: ArrayLike = True
x2: ArrayLike = 5
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.pyi b/numpy/typing/_dtype_like.py
index f5705192a..b9df0af04 100644
--- a/numpy/typing.pyi
+++ b/numpy/typing/_dtype_like.py
@@ -1,17 +1,7 @@
-import sys
-from typing import Any, Dict, List, overload, Sequence, Text, Tuple, Union
+from typing import Any, Dict, List, Sequence, 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]]
+from numpy import dtype
+from ._shape import _ShapeLike
_DtypeLikeNested = Any # TODO: wait for support for recursive types
@@ -45,7 +35,7 @@ DtypeLike = Union[
Sequence[str], # names
Sequence[_DtypeLikeNested], # formats
Sequence[int], # offsets
- Sequence[Union[bytes, Text, None]], # titles
+ Sequence[Union[bytes, str, None]], # titles
int, # itemsize
],
],
@@ -54,11 +44,3 @@ DtypeLike = Union[
# (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]
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]]