diff options
Diffstat (limited to 'numpy')
-rw-r--r-- | numpy/setup.py | 1 | ||||
-rw-r--r-- | numpy/tests/test_public_api.py | 3 | ||||
-rw-r--r-- | numpy/tests/typing/fail/array_like.py | 8 | ||||
-rw-r--r-- | numpy/tests/typing/pass/array_like.py | 10 | ||||
-rw-r--r-- | numpy/typing/__init__.py | 81 | ||||
-rw-r--r-- | numpy/typing/_array_like.py | 34 | ||||
-rw-r--r-- | numpy/typing/_dtype_like.py (renamed from numpy/typing.pyi) | 26 | ||||
-rw-r--r-- | numpy/typing/_shape.py | 6 |
8 files changed, 131 insertions, 38 deletions
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]] |