8000 API: Add `npt.NDArray`, a runtime-subscriptable alias for `np.ndarray` by BvB93 · Pull Request #18935 · numpy/numpy · GitHub
[go: up one dir, main page]

Skip to content

API: Add npt.NDArray, a runtime-subscriptable alias for np.ndarray #18935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions doc/release/upcoming_changes/18935.new_feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
A runtime-subcriptable alias has been added for `ndarray`
---------------------------------------------------------
`numpy.typing.NDArray` has been added, a runtime-subscriptable alias for
``np.ndarray[Any, np.dtype[~Scalar]]``. The new type alias can be used
for annotating arrays with a given dtype and unspecified shape. :sup:`1`

:sup:`1` NumPy does not support the annotating of array shapes as of 1.21,
this is expected to change in the future though (see :pep:`646`).

Examples
~~~~~~~~

.. code-block:: python

>>> import numpy as np
>>> import numpy.typing as npt

>>> print(npt.NDArray)
numpy.ndarray[typing.Any, numpy.dtype[~ScalarType]]

>>> print(npt.NDArray[np.float64])
numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]

>>> NDArrayInt = npt.NDArray[np.int_]
>>> a: NDArrayInt = np.arange(10)

>>> def func(a: npt.ArrayLike) -> npt.NDArray[Any]:
8000 ... return np.array(a)
780 changes: 390 additions & 390 deletions numpy/__init__.pyi

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion numpy/core/_add_newdocs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2176,6 +2176,8 @@
empty : Create an array, but leave its allocated memory unchanged (i.e.,
it contains "garbage").
dtype : Create a data-type.
numpy.typing.NDArray : A :term:`generic <generic type>` version
of ndarray.

Notes
-----
Expand Down Expand Up @@ -5814,7 +5816,7 @@
>>> (arr + arr).dtype.metadata
mappingproxy({'key': 'value'})

But if the arrays have different dtype metadata, the metadata may be
But if the arrays have different dtype metadata, the metadata may be
dropped:

>>> dt2 = np.dtype(float, metadata={"key2": "value2"})
Expand Down
30 changes: 15 additions & 15 deletions numpy/lib/index_tricks.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ from numpy.typing import (
ArrayLike,
_NestedSequence,
_RecursiveSequence,
_ArrayND,
NDArray,
_ArrayLikeInt,

# DTypes
Expand Down Expand Up @@ -68,7 +68,7 @@ def unravel_index(
indices: _ArrayLikeInt,
shape: _ShapeLike,
order: _OrderCF = ...
) -> Tuple[_ArrayND[intp], ...]: ...
) -> Tuple[NDArray[intp], ...]: ...

@overload
def ravel_multi_index( # type: ignore[misc]
Expand All @@ -83,24 +83,24 @@ def ravel_multi_index(
dims: _ShapeLike,
mode: Union[_ModeKind, Tuple[_ModeKind, ...]] = ...,
order: _OrderCF = ...
) -> _ArrayND[intp]: ...
) -> NDArray[intp]: ...

@overload
def ix_(*args: _NestedSequence[_SupportsDType[_DType]]) -> Tuple[ndarray[Any, _DType], ...]: ...
@overload
def ix_(*args: _NestedSequence[str]) -> Tuple[_ArrayND[str_], ...]: ...
def ix_(*args: _NestedSequence[str]) -> Tuple[NDArray[str_], ...]: ...
@overload
def ix_(*args: _NestedSequence[bytes]) -> Tuple[_ArrayND[bytes_], ...]: ...
def ix_(*args: _NestedSequence[bytes]) -> Tuple[NDArray[bytes_], ...]: ...
@overload
def ix_(*args: _NestedSequence[bool]) -> Tuple[_ArrayND[bool_], ...]: ...
def ix_(*args: _NestedSequence[bool]) -> Tuple[NDArray[bool_], ...]: ...
@overload
def ix_(*args: _NestedSequence[int]) -> Tuple[_ArrayND[int_], ...]: ...
def ix_(*args: _NestedSequence[int]) -> Tuple[NDArray[int_], ...]: ...
@overload
def ix_(*args: _NestedSequence[float]) -> Tuple[_ArrayND[float_], ...]: ...
def ix_(*args: _NestedSequence[float]) -> Tuple[NDArray[float_], ...]: ...
@overload
def ix_(*args: _NestedSequence[complex]) -> Tuple[_ArrayND[complex_], ...]: ...
def ix_(*args: _NestedSequence[complex]) -> Tuple[NDArray[complex_], ...]: ...
@overload
def ix_(*args: _RecursiveSequence) -> Tuple[_ArrayND[Any], ...]: ...
def ix_(*args: _RecursiveSequence) -> Tuple[NDArray[Any], ...]: ...

class nd_grid(Generic[_BoolType]):
sparse: _BoolType
Expand All @@ -109,12 +109,12 @@ class nd_grid(Generic[_BoolType]):
def __getitem__(
self: nd_grid[Literal[False]],
key: Union[slice, Sequence[slice]],
) -> _ArrayND[Any]: ...
) -> NDArray[Any]: ...
@overload
def __getitem__(
self: nd_grid[Literal[True]],
key: Union[slice, Sequence[slice]],
) -> List[_ArrayND[Any]]: ...
) -> List[NDArray[Any]]: ...

class MGridClass(nd_grid[Literal[False]]):
def __init__(self) -> None: ...
Expand Down Expand Up @@ -142,7 +142,7 @@ class AxisConcatenator:
@overload
def concatenate( # type: ignore[misc]
*a: ArrayLike, axis: SupportsIndex = ..., out: None = ...
) -> _ArrayND[Any]: ...
) -> NDArray[Any]: ...
@staticmethod
@overload
def concatenate(
Expand Down Expand Up @@ -188,7 +188,7 @@ index_exp: IndexExpression[Literal[True]]
s_: IndexExpression[Literal[False]]

def fill_diagonal(a: ndarray[Any, Any], val: Any, wrap: bool = ...) -> None: ...
def diag_indices(n: int, ndim: int = ...) -> Tuple[_ArrayND[int_], ...]: ...
def diag_indices_from(arr: ArrayLike) -> Tuple[_ArrayND[int_], ...]: ...
def diag_indices(n: int, ndim: int = ...) -> Tuple[NDArray[int_], ...]: ...
def diag_indices_from(arr: ArrayLike) -> Tuple[NDArray[int_], ...]: ...

# NOTE: see `numpy/__init__.pyi` for `ndenumerate` and `ndindex`
10 changes: 5 additions & 5 deletions numpy/lib/ufunclike.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ from typing import Any, overload, TypeVar, List, Union

from numpy import floating, bool_, object_, ndarray
from numpy.typing import (
_ArrayND,
NDArray,
_FloatLike_co,
_ArrayLikeFloat_co,
_ArrayLikeObject_co,
Expand All @@ -21,12 +21,12 @@ def fix( # type: ignore[misc]
def fix(
x: _ArrayLikeFloat_co,
out: None = ...,
) -> _ArrayND[floating[Any]]: ...
) -> NDArray[floating[Any]]: ...
@overload
def fix(
x: _ArrayLikeObject_co,
out: None = ...,
) -> _ArrayND[object_]: ...
) -> NDArray[object_]: ...
@overload
def fix(
x: Union[_ArrayLikeFloat_co, _ArrayLikeObject_co],
Expand All @@ -42,7 +42,7 @@ def isposinf( # type: ignore[misc]
def isposinf(
x: _ArrayLikeFloat_co,
out: None = ...,
) -> _ArrayND[bool_]: ...
) -> NDArray[bool_]: ...
@overload
def isposinf(
x: _ArrayLikeFloat_co,
Expand All @@ -58,7 +58,7 @@ def isneginf( # type: ignore[misc]
def isneginf(
x: _ArrayLikeFloat_co,
out: None = ...,
) -> _ArrayND[bool_]: ...
) -> NDArray[bool_]: ...
@overload
def isneginf(
x: _ArrayLikeFloat_co,
Expand Down
5 changes: 4 additions & 1 deletion numpy/typing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,6 @@ class _8Bit(_16Bit): ... # type: ignore[misc]
_NestedSequence,
_RecursiveSequence,
_SupportsArray,
_ArrayND,
_ArrayLikeInt,
_ArrayLikeBool_co,
_ArrayLikeUInt_co,
Expand All @@ -354,6 +353,10 @@ class _8Bit(_16Bit): ... # type: ignore[misc]
_ArrayLikeStr_co,
_ArrayLikeBytes_co,
)
from ._generic_alias import (
NDArray as NDArray,
_GenericAlias,
)

if __doc__ is not None:
from ._add_docstring import _docstrings
Expand Down
51 changes: 49 additions & 2 deletions numpy/typing/_add_docstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,32 @@
import re
import textwrap

from ._generic_alias import NDArray

_docstrings_list = []


def add_newdoc(name, value, doc):
def add_newdoc(name: str, value: str, doc: str) -> None:
"""Append ``_docstrings_list`` with a docstring for `name`.

Parameters
----------
name : str
The name of the object.
value : str
A string-representation of the object.
doc : str
The docstring of the object.

"""
_docstrings_list.append((name, value, doc))


def _parse_docstrings():
def _parse_docstrings() -> str:
"""Convert all docstrings in ``_docstrings_list`` into a single
sphinx-legible text block.

"""
type_list_ret = []
for name, value, doc in _docstrings_list:
s = textwrap.dedent(doc).replace("\n", "\n ")
Expand Down Expand Up @@ -93,4 +111,33 @@ def _parse_docstrings():

""")

add_newdoc('NDArray', repr(NDArray),
"""
A :term:`generic <generic type>` version of
`np.ndarray[Any, np.dtype[~ScalarType]] <numpy.ndarray>`.

Can be used during runtime for typing arrays with a given dtype
and unspecified shape.

Examples
--------
.. code-block:: python

>>> import numpy as np
>>> import numpy.typing as npt

>>> print(npt.NDArray)
numpy.ndarray[typing.Any, numpy.dtype[~ScalarType]]

>>> print(npt.NDArray[np.float64])
numpy.ndarray[typing.Any, numpy.dtype[numpy.float64]]

>>> NDArrayInt = npt.NDArray[np.int_]
>>> a: NDArrayInt = np.arange(10)

>>> def func(a: npt.ArrayLike) -> npt.NDArray[Any]:
... return np.array(a)

""")

_docstrings = _parse_docstrings()
5 changes: 0 additions &am FA6C p; 5 deletions numpy/typing/_array_like.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,3 @@ def __array__(self) -> ndarray[Any, _DType_co]: ...
"dtype[integer[Any]]",
int,
]

if TYPE_CHECKING:
_ArrayND = ndarray[Any, dtype[_ScalarType]]
else:
_ArrayND = Any
5 changes: 3 additions & 2 deletions numpy/typing/_callable.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
_NumberLike_co,
)
from . import NBitBase
from ._array_like import ArrayLike, _ArrayND
from ._array_like import ArrayLike
from ._generic_alias import NDArray

if sys.version_info >= (3, 8):
from typing import Protocol
Expand Down Expand Up @@ -336,7 +337,7 @@ class _ComparisonOp(Protocol[_T1, _T2]):
@overload
def __call__(self, __other: _T1) -> bool_: ...
@overload
def __call__(self, __other: _T2) -> _ArrayND[bool_]: ...
def __call__(self, __other: _T2) -> NDArray[bool_]: ...

else:
_BoolOp = Any
Expand Down
Loading
0