1"""
2============================
3Typing (:mod:`numpy.typing`)
4============================
5
6.. versionadded:: 1.20
7
8Large parts of the NumPy API have :pep:`484`-style type annotations. In
9addition a number of type aliases are available to users, most prominently
10the two below:
11
12- `ArrayLike`: objects that can be converted to arrays
13- `DTypeLike`: objects that can be converted to dtypes
14
15.. _typing-extensions: https://pypi.org/project/typing-extensions/
16
17Mypy plugin
18-----------
19
20.. versionadded:: 1.21
21
22.. automodule:: numpy.typing.mypy_plugin
23
24.. currentmodule:: numpy.typing
25
26Differences from the runtime NumPy API
27--------------------------------------
28
29NumPy is very flexible. Trying to describe the full range of
30possibilities statically would result in types that are not very
31helpful. For that reason, the typed NumPy API is often stricter than
32the runtime NumPy API. This section describes some notable
33differences.
34
35ArrayLike
36~~~~~~~~~
37
38The `ArrayLike` type tries to avoid creating object arrays. For
39example,
40
41.. code-block:: python
42
43 >>> np.array(x**2 for x in range(10))
44 array(<generator object <genexpr> at ...>, dtype=object)
45
46is valid NumPy code which will create a 0-dimensional object
47array. Type checkers will complain about the above example when using
48the NumPy types however. If you really intended to do the above, then
49you can either use a ``# type: ignore`` comment:
50
51.. code-block:: python
52
53 >>> np.array(x**2 for x in range(10)) # type: ignore
54
55or explicitly type the array like object as `~typing.Any`:
56
57.. code-block:: python
58
59 >>> from typing import Any
60 >>> array_like: Any = (x**2 for x in range(10))
61 >>> np.array(array_like)
62 array(<generator object <genexpr> at ...>, dtype=object)
63
64ndarray
65~~~~~~~
66
67It's possible to mutate the dtype of an array at runtime. For example,
68the following code is valid:
69
70.. code-block:: python
71
72 >>> x = np.array([1, 2])
73 >>> x.dtype = np.bool_
74
75This sort of mutation is not allowed by the types. Users who want to
76write statically typed code should instead use the `numpy.ndarray.view`
77method to create a view of the array with a different dtype.
78
79DTypeLike
80~~~~~~~~~
81
82The `DTypeLike` type tries to avoid creation of dtype objects using
83dictionary of fields like below:
84
85.. code-block:: python
86
87 >>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)})
88
89Although this is valid NumPy code, the type checker will complain about it,
90since its usage is discouraged.
91Please see : :ref:`Data type objects <arrays.dtypes>`
92
93Number precision
94~~~~~~~~~~~~~~~~
95
96The precision of `numpy.number` subclasses is treated as a covariant generic
97parameter (see :class:`~NBitBase`), simplifying the annotating of processes
98involving precision-based casting.
99
100.. code-block:: python
101
102 >>> from typing import TypeVar
103 >>> import numpy as np
104 >>> import numpy.typing as npt
105
106 >>> T = TypeVar("T", bound=npt.NBitBase)
107 >>> def func(a: "np.floating[T]", b: "np.floating[T]") -> "np.floating[T]":
108 ... ...
109
110Consequently, the likes of `~numpy.float16`, `~numpy.float32` and
111`~numpy.float64` are still sub-types of `~numpy.floating`, but, contrary to
112runtime, they're not necessarily considered as sub-classes.
113
114Timedelta64
115~~~~~~~~~~~
116
117The `~numpy.timedelta64` class is not considered a subclass of
118`~numpy.signedinteger`, the former only inheriting from `~numpy.generic`
119while static type checking.
120
1210D arrays
122~~~~~~~~~
123
124During runtime numpy aggressively casts any passed 0D arrays into their
125corresponding `~numpy.generic` instance. Until the introduction of shape
126typing (see :pep:`646`) it is unfortunately not possible to make the
127necessary distinction between 0D and >0D arrays. While thus not strictly
128correct, all operations are that can potentially perform a 0D-array -> scalar
129cast are currently annotated as exclusively returning an `ndarray`.
130
131If it is known in advance that an operation _will_ perform a
1320D-array -> scalar cast, then one can consider manually remedying the
133situation with either `typing.cast` or a ``# type: ignore`` comment.
134
135Record array dtypes
136~~~~~~~~~~~~~~~~~~~
137
138The dtype of `numpy.recarray`, and the `numpy.rec` functions in general,
139can be specified in one of two ways:
140
141* Directly via the ``dtype`` argument.
142* With up to five helper arguments that operate via `numpy.format_parser`:
143 ``formats``, ``names``, ``titles``, ``aligned`` and ``byteorder``.
144
145These two approaches are currently typed as being mutually exclusive,
146*i.e.* if ``dtype`` is specified than one may not specify ``formats``.
147While this mutual exclusivity is not (strictly) enforced during runtime,
148combining both dtype specifiers can lead to unexpected or even downright
149buggy behavior.
150
151API
152---
153
154"""
155# NOTE: The API section will be appended with additional entries
156# further down in this file
157
158from numpy._typing import (
159 ArrayLike,
160 DTypeLike,
161 NBitBase,
162 NDArray,
163)
164
165__all__ = ["ArrayLike", "DTypeLike", "NBitBase", "NDArray"]
166
167if __doc__ is not None:
168 from numpy._typing._add_docstring import _docstrings
169 __doc__ += _docstrings
170 __doc__ += '\n.. autoclass:: numpy.typing.NBitBase\n'
171 del _docstrings
172
173from numpy._pytesttester import PytestTester
174test = PytestTester(__name__)
175del PytestTester