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 invariant 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
114.. deprecated:: 2.3
115 The :class:`~numpy.typing.NBitBase` helper is deprecated and will be
116 removed in a future release. Prefer expressing precision relationships via
117 ``typing.overload`` or ``TypeVar`` definitions bounded by concrete scalar
118 classes. For example:
119
120 .. code-block:: python
121
122 from typing import TypeVar
123 import numpy as np
124
125 S = TypeVar("S", bound=np.floating)
126
127 def func(a: S, b: S) -> S:
128 ...
129
130 or in the case of different input types mapping to different output types:
131
132 .. code-block:: python
133
134 from typing import overload
135 import numpy as np
136
137 @overload
138 def phase(x: np.complex64) -> np.float32: ...
139 @overload
140 def phase(x: np.complex128) -> np.float64: ...
141 @overload
142 def phase(x: np.clongdouble) -> np.longdouble: ...
143 def phase(x: np.complexfloating) -> np.floating:
144 ...
145
146Timedelta64
147~~~~~~~~~~~
148
149The `~numpy.timedelta64` class is not considered a subclass of
150`~numpy.signedinteger`, the former only inheriting from `~numpy.generic`
151while static type checking.
152
1530D arrays
154~~~~~~~~~
155
156During runtime numpy aggressively casts any passed 0D arrays into their
157corresponding `~numpy.generic` instance. Until the introduction of shape
158typing (see :pep:`646`) it is unfortunately not possible to make the
159necessary distinction between 0D and >0D arrays. While thus not strictly
160correct, all operations that can potentially perform a 0D-array -> scalar
161cast are currently annotated as exclusively returning an `~numpy.ndarray`.
162
163If it is known in advance that an operation *will* perform a
1640D-array -> scalar cast, then one can consider manually remedying the
165situation with either `typing.cast` or a ``# type: ignore`` comment.
166
167Record array dtypes
168~~~~~~~~~~~~~~~~~~~
169
170The dtype of `numpy.recarray`, and the :ref:`routines.array-creation.rec`
171functions in general, can be specified in one of two ways:
172
173* Directly via the ``dtype`` argument.
174* With up to five helper arguments that operate via `numpy.rec.format_parser`:
175 ``formats``, ``names``, ``titles``, ``aligned`` and ``byteorder``.
176
177These two approaches are currently typed as being mutually exclusive,
178*i.e.* if ``dtype`` is specified than one may not specify ``formats``.
179While this mutual exclusivity is not (strictly) enforced during runtime,
180combining both dtype specifiers can lead to unexpected or even downright
181buggy behavior.
182
183API
184---
185
186"""
187# NOTE: The API section will be appended with additional entries
188# further down in this file
189
190# pyright: reportDeprecated=false
191
192from numpy._typing import ArrayLike, DTypeLike, NBitBase, NDArray
193
194__all__ = ["ArrayLike", "DTypeLike", "NBitBase", "NDArray"]
195
196
197__DIR = __all__ + [k for k in globals() if k.startswith("__") and k.endswith("__")]
198__DIR_SET = frozenset(__DIR)
199
200
201def __dir__() -> list[str]:
202 return __DIR
203
204def __getattr__(name: str) -> object:
205 if name == "NBitBase":
206 import warnings
207
208 # Deprecated in NumPy 2.3, 2025-05-01
209 warnings.warn(
210 "`NBitBase` is deprecated and will be removed from numpy.typing in the "
211 "future. Use `@typing.overload` or a `TypeVar` with a scalar-type as upper "
212 "bound, instead. (deprecated in NumPy 2.3)",
213 DeprecationWarning,
214 stacklevel=2,
215 )
216 return NBitBase
217
218 if name in __DIR_SET:
219 return globals()[name]
220
221 raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
222
223
224if __doc__ is not None:
225 from numpy._typing._add_docstring import _docstrings
226 __doc__ += _docstrings
227 __doc__ += '\n.. autoclass:: numpy.typing.NBitBase\n'
228 del _docstrings
229
230from numpy._pytesttester import PytestTester
231
232test = PytestTester(__name__)
233del PytestTester