/
__init__.py
399 lines (321 loc) · 12.1 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
"""
============================
Typing (:mod:`numpy.typing`)
============================
.. versionadded:: 1.20
Large parts of the NumPy API have PEP-484-style type annotations. In
addition a number of type aliases are available to users, most prominently
the two below:
- `ArrayLike`: objects that can be converted to arrays
- `DTypeLike`: objects that can be converted to dtypes
.. _typing-extensions: https://pypi.org/project/typing-extensions/
Mypy plugin
-----------
.. versionadded:: 1.21
.. automodule:: numpy.typing.mypy_plugin
.. currentmodule:: numpy.typing
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 ...>, 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 `~typing.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 ...>, 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 instead use the `numpy.ndarray.view`
method to create a view of the array with a different dtype.
DTypeLike
~~~~~~~~~
The `DTypeLike` type tries to avoid creation of dtype objects using
dictionary of fields like below:
.. code-block:: python
>>> x = np.dtype({"field1": (float, 1), "field2": (int, 3)})
Although this is valid NumPy code, the type checker will complain about it,
since its usage is discouraged.
Please see : :ref:`Data type objects <arrays.dtypes>`
Number precision
~~~~~~~~~~~~~~~~
The precision of `numpy.number` subclasses is treated as a covariant generic
parameter (see :class:`~NBitBase`), simplifying the annotating of processes
involving precision-based casting.
.. code-block:: python
>>> from typing import TypeVar
>>> import numpy as np
>>> import numpy.typing as npt
>>> T = TypeVar("T", bound=npt.NBitBase)
>>> def func(a: "np.floating[T]", b: "np.floating[T]") -> "np.floating[T]":
... ...
Consequently, the likes of `~numpy.float16`, `~numpy.float32` and
`~numpy.float64` are still sub-types of `~numpy.floating`, but, contrary to
runtime, they're not necessarily considered as sub-classes.
Timedelta64
~~~~~~~~~~~
The `~numpy.timedelta64` class is not considered a subclass of
`~numpy.signedinteger`, the former only inheriting from `~numpy.generic`
while static type checking.
0D arrays
~~~~~~~~~
During runtime numpy aggressively casts any passed 0D arrays into their
corresponding `~numpy.generic` instance. Until the introduction of shape
typing (see :pep:`646`) it is unfortunately not possible to make the
necessary distinction between 0D and >0D arrays. While thus not strictly
correct, all operations are that can potentially perform a 0D-array -> scalar
cast are currently annotated as exclusively returning an `ndarray`.
If it is known in advance that an operation _will_ perform a
0D-array -> scalar cast, then one can consider manually remedying the
situation with either `typing.cast` or a ``# type: ignore`` comment.
Record array dtypes
~~~~~~~~~~~~~~~~~~~
The dtype of `numpy.recarray`, and the `numpy.rec` functions in general,
can be specified in one of two ways:
* Directly via the ``dtype`` argument.
* With up to five helper arguments that operate via `numpy.format_parser`:
``formats``, ``names``, ``titles``, ``aligned`` and ``byteorder``.
These two approaches are currently typed as being mutually exclusive,
*i.e.* if ``dtype`` is specified than one may not specify ``formats``.
While this mutual exclusivity is not (strictly) enforced during runtime,
combining both dtype specifiers can lead to unexpected or even downright
buggy behavior.
API
---
"""
# NOTE: The API section will be appended with additional entries
# further down in this file
from __future__ import annotations
from numpy import ufunc
from typing import TYPE_CHECKING, final
if not TYPE_CHECKING:
__all__ = ["ArrayLike", "DTypeLike", "NBitBase", "NDArray"]
else:
# Ensure that all objects within this module are accessible while
# static type checking. This includes private ones, as we need them
# for internal use.
#
# Declare to mypy that `__all__` is a list of strings without assigning
# an explicit value
__all__: list[str]
__path__: list[str]
@final # Disallow the creation of arbitrary `NBitBase` subclasses
class NBitBase:
"""
A type representing `numpy.number` precision during static type checking.
Used exclusively for the purpose static type checking, `NBitBase`
represents the base of a hierarchical set of subclasses.
Each subsequent subclass is herein used for representing a lower level
of precision, *e.g.* ``64Bit > 32Bit > 16Bit``.
.. versionadded:: 1.20
Examples
--------
Below is a typical usage example: `NBitBase` is herein used for annotating
a function that takes a float and integer of arbitrary precision
as arguments and returns a new float of whichever precision is largest
(*e.g.* ``np.float16 + np.int64 -> np.float64``).
.. code-block:: python
>>> from __future__ import annotations
>>> from typing import TypeVar, TYPE_CHECKING
>>> import numpy as np
>>> import numpy.typing as npt
>>> T1 = TypeVar("T1", bound=npt.NBitBase)
>>> T2 = TypeVar("T2", bound=npt.NBitBase)
>>> def add(a: np.floating[T1], b: np.integer[T2]) -> np.floating[T1 | T2]:
... return a + b
>>> a = np.float16()
>>> b = np.int64()
>>> out = add(a, b)
>>> if TYPE_CHECKING:
... reveal_locals()
... # note: Revealed local types are:
... # note: a: numpy.floating[numpy.typing._16Bit*]
... # note: b: numpy.signedinteger[numpy.typing._64Bit*]
... # note: out: numpy.floating[numpy.typing._64Bit*]
"""
def __init_subclass__(cls) -> None:
allowed_names = {
"NBitBase", "_256Bit", "_128Bit", "_96Bit", "_80Bit",
"_64Bit", "_32Bit", "_16Bit", "_8Bit",
}
if cls.__name__ not in allowed_names:
raise TypeError('cannot inherit from final class "NBitBase"')
super().__init_subclass__()
# Silence errors about subclassing a `@final`-decorated class
class _256Bit(NBitBase): # type: ignore[misc]
pass
class _128Bit(_256Bit): # type: ignore[misc]
pass
class _96Bit(_128Bit): # type: ignore[misc]
pass
class _80Bit(_96Bit): # type: ignore[misc]
pass
class _64Bit(_80Bit): # type: ignore[misc]
pass
class _32Bit(_64Bit): # type: ignore[misc]
pass
class _16Bit(_32Bit): # type: ignore[misc]
pass
class _8Bit(_16Bit): # type: ignore[misc]
pass
from ._nested_sequence import (
_NestedSequence as _NestedSequence,
)
from ._nbit import (
_NBitByte as _NBitByte,
_NBitShort as _NBitShort,
_NBitIntC as _NBitIntC,
_NBitIntP as _NBitIntP,
_NBitInt as _NBitInt,
_NBitLongLong as _NBitLongLong,
_NBitHalf as _NBitHalf,
_NBitSingle as _NBitSingle,
_NBitDouble as _NBitDouble,
_NBitLongDouble as _NBitLongDouble,
)
from ._char_codes import (
_BoolCodes as _BoolCodes,
_UInt8Codes as _UInt8Codes,
_UInt16Codes as _UInt16Codes,
_UInt32Codes as _UInt32Codes,
_UInt64Codes as _UInt64Codes,
_Int8Codes as _Int8Codes,
_Int16Codes as _Int16Codes,
_Int32Codes as _Int32Codes,
_Int64Codes as _Int64Codes,
_Float16Codes as _Float16Codes,
_Float32Codes as _Float32Codes,
_Float64Codes as _Float64Codes,
_Complex64Codes as _Complex64Codes,
_Complex128Codes as _Complex128Codes,
_ByteCodes as _ByteCodes,
_ShortCodes as _ShortCodes,
_IntCCodes as _IntCCodes,
_IntPCodes as _IntPCodes,
_IntCodes as _IntCodes,
_LongLongCodes as _LongLongCodes,
_UByteCodes as _UByteCodes,
_UShortCodes as _UShortCodes,
_UIntCCodes as _UIntCCodes,
_UIntPCodes as _UIntPCodes,
_UIntCodes as _UIntCodes,
_ULongLongCodes as _ULongLongCodes,
_HalfCodes as _HalfCodes,
_SingleCodes as _SingleCodes,
_DoubleCodes as _DoubleCodes,
_LongDoubleCodes as _LongDoubleCodes,
_CSingleCodes as _CSingleCodes,
_CDoubleCodes as _CDoubleCodes,
_CLongDoubleCodes as _CLongDoubleCodes,
_DT64Codes as _DT64Codes,
_TD64Codes as _TD64Codes,
_StrCodes as _StrCodes,
_BytesCodes as _BytesCodes,
_VoidCodes as _VoidCodes,
_ObjectCodes as _ObjectCodes,
)
from ._scalars import (
_CharLike_co as _CharLike_co,
_BoolLike_co as _BoolLike_co,
_UIntLike_co as _UIntLike_co,
_IntLike_co as _IntLike_co,
_FloatLike_co as _FloatLike_co,
_ComplexLike_co as _ComplexLike_co,
_TD64Like_co as _TD64Like_co,
_NumberLike_co as _NumberLike_co,
_ScalarLike_co as _ScalarLike_co,
_VoidLike_co as _VoidLike_co,
)
from ._shape import (
_Shape as _Shape,
_ShapeLike as _ShapeLike,
)
from ._dtype_like import (
DTypeLike as DTypeLike,
_SupportsDType as _SupportsDType,
_VoidDTypeLike as _VoidDTypeLike,
_DTypeLikeBool as _DTypeLikeBool,
_DTypeLikeUInt as _DTypeLikeUInt,
_DTypeLikeInt as _DTypeLikeInt,
_DTypeLikeFloat as _DTypeLikeFloat,
_DTypeLikeComplex as _DTypeLikeComplex,
_DTypeLikeTD64 as _DTypeLikeTD64,
_DTypeLikeDT64 as _DTypeLikeDT64,
_DTypeLikeObject as _DTypeLikeObject,
_DTypeLikeVoid as _DTypeLikeVoid,
_DTypeLikeStr as _DTypeLikeStr,
_DTypeLikeBytes as _DTypeLikeBytes,
_DTypeLikeComplex_co as _DTypeLikeComplex_co,
)
from ._array_like import (
ArrayLike as ArrayLike,
_ArrayLike as _ArrayLike,
_FiniteNestedSequence as _FiniteNestedSequence,
_SupportsArray as _SupportsArray,
_ArrayLikeInt as _ArrayLikeInt,
_ArrayLikeBool_co as _ArrayLikeBool_co,
_ArrayLikeUInt_co as _ArrayLikeUInt_co,
_ArrayLikeInt_co as _ArrayLikeInt_co,
_ArrayLikeFloat_co as _ArrayLikeFloat_co,
_ArrayLikeComplex_co as _ArrayLikeComplex_co,
_ArrayLikeNumber_co as _ArrayLikeNumber_co,
_ArrayLikeTD64_co as _ArrayLikeTD64_co,
_ArrayLikeDT64_co as _ArrayLikeDT64_co,
_ArrayLikeObject_co as _ArrayLikeObject_co,
_ArrayLikeVoid_co as _ArrayLikeVoid_co,
_ArrayLikeStr_co as _ArrayLikeStr_co,
_ArrayLikeBytes_co as _ArrayLikeBytes_co,
)
from ._generic_alias import (
NDArray as NDArray,
_DType as _DType,
_GenericAlias as _GenericAlias,
)
if TYPE_CHECKING:
from ._ufunc import (
_UFunc_Nin1_Nout1 as _UFunc_Nin1_Nout1,
_UFunc_Nin2_Nout1 as _UFunc_Nin2_Nout1,
_UFunc_Nin1_Nout2 as _UFunc_Nin1_Nout2,
_UFunc_Nin2_Nout2 as _UFunc_Nin2_Nout2,
_GUFunc_Nin2_Nout1 as _GUFunc_Nin2_Nout1,
)
else:
# Declare the (type-check-only) ufunc subclasses as ufunc aliases during
# runtime; this helps autocompletion tools such as Jedi (numpy/numpy#19834)
_UFunc_Nin1_Nout1 = ufunc
_UFunc_Nin2_Nout1 = ufunc
_UFunc_Nin1_Nout2 = ufunc
_UFunc_Nin2_Nout2 = ufunc
_GUFunc_Nin2_Nout1 = ufunc
# Clean up the namespace
del TYPE_CHECKING, final, ufunc
if __doc__ is not None:
from ._add_docstring import _docstrings
__doc__ += _docstrings
__doc__ += '\n.. autoclass:: numpy.typing.NBitBase\n'
del _docstrings
from numpy._pytesttester import PytestTester
test = PytestTester(__name__)
del PytestTester