diff options
-rw-r--r-- | numpy/__init__.pyi | 59 | ||||
-rw-r--r-- | numpy/core/function_base.pyi | 13 | ||||
-rw-r--r-- | numpy/lib/function_base.pyi | 308 | ||||
-rw-r--r-- | numpy/typing/tests/data/fail/lib_function_base.pyi | 19 | ||||
-rw-r--r-- | numpy/typing/tests/data/fail/ndarray_misc.pyi | 4 | ||||
-rw-r--r-- | numpy/typing/tests/data/reveal/lib_function_base.pyi | 99 | ||||
-rw-r--r-- | numpy/typing/tests/data/reveal/ndarray_misc.pyi | 11 |
7 files changed, 474 insertions, 39 deletions
diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index c78d48cc6..69f18fac4 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -197,6 +197,7 @@ from typing import ( Final, final, ClassVar, + Set, ) # Ensures that the stubs are picked up @@ -828,24 +829,6 @@ class poly1d: def integ(self, m=..., k=...): ... def deriv(self, m=...): ... -class vectorize: - pyfunc: Any - cache: Any - signature: Any - otypes: Any - excluded: Any - __doc__: Any - def __init__( - self, - pyfunc, - otypes: Any = ..., - doc: Any = ..., - excluded: Any = ..., - cache: Any = ..., - signature: Any = ..., - ) -> None: ... - def __call__(self, *args: Any, **kwargs: Any) -> Any: ... - # Some of these are aliases; others are wrappers with an identical signature round = around round_ = around @@ -1181,8 +1164,6 @@ class _ArrayOrScalarCommon: # generics and 0d arrays return builtin scalars def tolist(self) -> Any: ... - # TODO: Add proper signatures - def __getitem__(self, key) -> Any: ... @property def __array_interface__(self): ... @property @@ -1679,6 +1660,26 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]): /, ) -> ndarray[_ShapeType2, _DType]: ... + @overload + def __getitem__(self, key: Union[ + SupportsIndex, + _ArrayLikeInt_co, + Tuple[SupportsIndex | _ArrayLikeInt_co, ...], + ]) -> Any: ... + @overload + def __getitem__(self, key: Union[ + None, + slice, + ellipsis, + SupportsIndex, + _ArrayLikeInt_co, + Tuple[None | slice | ellipsis | _ArrayLikeInt_co | SupportsIndex, ...], + ]) -> ndarray[Any, _DType_co]: ... + @overload + def __getitem__(self: NDArray[void], key: str) -> NDArray[Any]: ... + @overload + def __getitem__(self: NDArray[void], key: list[str]) -> ndarray[_ShapeType, dtype[void]]: ... + @property def ctypes(self) -> _ctypes[int]: ... @property @@ -3879,3 +3880,21 @@ class memmap(ndarray[_ShapeType, _DType_co]): ) -> Any: ... def __getitem__(self, index): ... # TODO def flush(self) -> None: ... + +class vectorize: + pyfunc: Callable[..., Any] + cache: bool + signature: None | str + otypes: None | str + excluded: Set[int | str] + __doc__: None | str + def __init__( + self, + pyfunc: Callable[..., Any], + otypes: None | str | Iterable[DTypeLike] = ..., + doc: None | str = ..., + excluded: None | Iterable[int | str] = ..., + cache: bool = ..., + signature: None | str = ..., + ) -> None: ... + def __call__(self, *args: Any, **kwargs: Any) -> NDArray[Any]: ... diff --git a/numpy/core/function_base.pyi b/numpy/core/function_base.pyi index c35629aa7..68d3b3a98 100644 --- a/numpy/core/function_base.pyi +++ b/numpy/core/function_base.pyi @@ -1,4 +1,4 @@ -from typing import overload, Tuple, Union, Sequence, Any, SupportsIndex, Literal +from typing import overload, Tuple, Union, Sequence, Any, SupportsIndex, Literal, List from numpy import ndarray from numpy.typing import ArrayLike, DTypeLike, _SupportsArray, _NumberLike_co @@ -8,6 +8,9 @@ _ArrayLikeNested = Sequence[Sequence[Any]] _ArrayLikeNumber = Union[ _NumberLike_co, Sequence[_NumberLike_co], ndarray, _SupportsArray, _ArrayLikeNested ] + +__all__: List[str] + @overload def linspace( start: _ArrayLikeNumber, @@ -47,3 +50,11 @@ def geomspace( dtype: DTypeLike = ..., axis: SupportsIndex = ..., ) -> ndarray: ... + +# Re-exported to `np.lib.function_base` +def add_newdoc( + place: str, + obj: str, + doc: str | Tuple[str, str] | List[Tuple[str, str]], + warn_on_python: bool = ..., +) -> None: ... diff --git a/numpy/lib/function_base.pyi b/numpy/lib/function_base.pyi index 69c615c9c..cbbc87e65 100644 --- a/numpy/lib/function_base.pyi +++ b/numpy/lib/function_base.pyi @@ -1,7 +1,48 @@ -from typing import List +import sys +from typing import ( + Literal as L, + List, + Type, + Sequence, + Tuple, + Union, + Any, + TypeVar, + Iterator, + overload, + Callable, + Protocol, + SupportsIndex, + Iterable, +) + +if sys.version_info >= (3, 10): + from typing import TypeGuard +else: + from typing_extensions import TypeGuard from numpy import ( vectorize as vectorize, + dtype, + generic, + floating, + complexfloating, + object_, + _OrderKACF, +) + +from numpy.typing import ( + NDArray, + ArrayLike, + DTypeLike, + _ShapeLike, + _ScalarLike_co, + _SupportsDType, + _FiniteNestedSequence, + _SupportsArray, + _ArrayLikeComplex_co, + _ArrayLikeFloat_co, + _ArrayLikeObject_co, ) from numpy.core.function_base import ( @@ -12,30 +53,261 @@ from numpy.core.multiarray import ( add_docstring as add_docstring, bincount as bincount, ) + from numpy.core.umath import _add_newdoc_ufunc +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) +_SCT = TypeVar("_SCT", bound=generic) +_ArrayType = TypeVar("_ArrayType", bound=NDArray[Any]) + +_2Tuple = Tuple[_T, _T] +_ArrayLike = _FiniteNestedSequence[_SupportsArray[dtype[_SCT]]] +_DTypeLike = Union[ + dtype[_SCT], + Type[_SCT], + _SupportsDType[dtype[_SCT]], +] + +class _TrimZerosSequence(Protocol[_T_co]): + def __len__(self) -> int: ... + def __getitem__(self, key: slice, /) -> _T_co: ... + def __iter__(self) -> Iterator[Any]: ... + +class _SupportsWriteFlush(Protocol): + def write(self, s: str, /) -> object: ... + def flush(self) -> object: ... + __all__: List[str] add_newdoc_ufunc = _add_newdoc_ufunc -def rot90(m, k=..., axes = ...): ... -def flip(m, axis=...): ... -def iterable(y): ... -def average(a, axis=..., weights=..., returned=...): ... -def asarray_chkfinite(a, dtype=..., order=...): ... -def piecewise(x, condlist, funclist, *args, **kw): ... -def select(condlist, choicelist, default=...): ... -def copy(a, order=..., subok=...): ... -def gradient(f, *varargs, axis=..., edge_order=...): ... -def diff(a, n=..., axis=..., prepend = ..., append = ...): ... +@overload +def rot90( + m: _ArrayLike[_SCT], + k: int = ..., + axes: Tuple[int, int] = ..., +) -> NDArray[_SCT]: ... +@overload +def rot90( + m: ArrayLike, + k: int = ..., + axes: Tuple[int, int] = ..., +) -> NDArray[Any]: ... + +@overload +def flip(m: _SCT, axis: None = ...) -> _SCT: ... +@overload +def flip(m: _ScalarLike_co, axis: None = ...) -> Any: ... +@overload +def flip(m: _ArrayLike[_SCT], axis: None | _ShapeLike = ...) -> NDArray[_SCT]: ... +@overload +def flip(m: ArrayLike, axis: None | _ShapeLike = ...) -> NDArray[Any]: ... + +def iterable(y: object) -> TypeGuard[Iterable[Any]]: ... + +@overload +def average( + a: _ArrayLikeFloat_co, + axis: None = ..., + weights: None | _ArrayLikeFloat_co= ..., + returned: L[False] = ..., +) -> floating[Any]: ... +@overload +def average( + a: _ArrayLikeComplex_co, + axis: None = ..., + weights: None | _ArrayLikeComplex_co = ..., + returned: L[False] = ..., +) -> complexfloating[Any, Any]: ... +@overload +def average( + a: _ArrayLikeObject_co, + axis: None = ..., + weights: None | Any = ..., + returned: L[False] = ..., +) -> Any: ... +@overload +def average( + a: _ArrayLikeFloat_co, + axis: None = ..., + weights: None | _ArrayLikeFloat_co= ..., + returned: L[True] = ..., +) -> _2Tuple[floating[Any]]: ... +@overload +def average( + a: _ArrayLikeComplex_co, + axis: None = ..., + weights: None | _ArrayLikeComplex_co = ..., + returned: L[True] = ..., +) -> _2Tuple[complexfloating[Any, Any]]: ... +@overload +def average( + a: _ArrayLikeObject_co, + axis: None = ..., + weights: None | Any = ..., + returned: L[True] = ..., +) -> _2Tuple[Any]: ... +@overload +def average( + a: _ArrayLikeComplex_co | _ArrayLikeObject_co, + axis: None | _ShapeLike = ..., + weights: None | Any = ..., + returned: L[False] = ..., +) -> Any: ... +@overload +def average( + a: _ArrayLikeComplex_co | _ArrayLikeObject_co, + axis: None | _ShapeLike = ..., + weights: None | Any = ..., + returned: L[True] = ..., +) -> _2Tuple[Any]: ... + +@overload +def asarray_chkfinite( + a: _ArrayLike[_SCT], + dtype: None = ..., + order: _OrderKACF = ..., +) -> NDArray[_SCT]: ... +@overload +def asarray_chkfinite( + a: object, + dtype: None = ..., + order: _OrderKACF = ..., +) -> NDArray[Any]: ... +@overload +def asarray_chkfinite( + a: Any, + dtype: _DTypeLike[_SCT], + order: _OrderKACF = ..., +) -> NDArray[_SCT]: ... +@overload +def asarray_chkfinite( + a: Any, + dtype: DTypeLike, + order: _OrderKACF = ..., +) -> NDArray[Any]: ... + +@overload +def piecewise( + x: _ArrayLike[_SCT], + condlist: ArrayLike, + funclist: Sequence[Any | Callable[..., Any]], + *args: Any, + **kw: Any, +) -> NDArray[_SCT]: ... +@overload +def piecewise( + x: ArrayLike, + condlist: ArrayLike, + funclist: Sequence[Any | Callable[..., Any]], + *args: Any, + **kw: Any, +) -> NDArray[Any]: ... + +def select( + condlist: Sequence[ArrayLike], + choicelist: Sequence[ArrayLike], + default: ArrayLike = ..., +) -> NDArray[Any]: ... + +@overload +def copy( + a: _ArrayType, + order: _OrderKACF, + subok: L[True], +) -> _ArrayType: ... +@overload +def copy( + a: _ArrayType, + order: _OrderKACF = ..., + *, + subok: L[True], +) -> _ArrayType: ... +@overload +def copy( + a: _ArrayLike[_SCT], + order: _OrderKACF = ..., + subok: L[False] = ..., +) -> NDArray[_SCT]: ... +@overload +def copy( + a: ArrayLike, + order: _OrderKACF = ..., + subok: L[False] = ..., +) -> NDArray[Any]: ... + +def gradient( + f: ArrayLike, + *varargs: ArrayLike, + axis: None | _ShapeLike = ..., + edge_order: L[1, 2] = ..., +) -> Any: ... + +@overload +def diff( + a: _T, + n: L[0], + axis: SupportsIndex = ..., + prepend: ArrayLike = ..., + append: ArrayLike = ..., +) -> _T: ... +@overload +def diff( + a: ArrayLike, + n: int = ..., + axis: SupportsIndex = ..., + prepend: ArrayLike = ..., + append: ArrayLike = ..., +) -> NDArray[Any]: ... + +# TODO def interp(x, xp, fp, left=..., right=..., period=...): ... -def angle(z, deg=...): ... -def unwrap(p, discont = ..., axis=..., *, period=...): ... -def sort_complex(a): ... -def trim_zeros(filt, trim=...): ... -def extract(condition, arr): ... -def place(arr, mask, vals): ... -def disp(mesg, device=..., linefeed=...): ... + +@overload +def angle(z: _ArrayLikeFloat_co, deg: bool = ...) -> floating[Any]: ... +@overload +def angle(z: _ArrayLikeComplex_co, deg: bool = ...) -> complexfloating[Any, Any]: ... +@overload +def angle(z: _ArrayLikeObject_co, deg: bool = ...) -> Any: ... + +@overload +def unwrap( + p: _ArrayLikeFloat_co, + discont: None | float = ..., + axis: int = ..., + *, + period: float = ..., +) -> NDArray[floating[Any]]: ... +@overload +def unwrap( + p: _ArrayLikeObject_co, + discont: None | float = ..., + axis: int = ..., + *, + period: float = ..., +) -> NDArray[object_]: ... + +def sort_complex(a: ArrayLike) -> NDArray[complexfloating[Any, Any]]: ... + +def trim_zeros( + filt: _TrimZerosSequence[_T], + trim: L["f", "b", "fb", "bf"] = ..., +) -> _T: ... + +@overload +def extract(condition: ArrayLike, arr: _ArrayLike[_SCT]) -> NDArray[_SCT]: ... +@overload +def extract(condition: ArrayLike, arr: ArrayLike) -> NDArray[Any]: ... + +def place(arr: NDArray[Any], mask: ArrayLike, vals: Any) -> None: ... + +def disp( + mesg: object, + device: None | _SupportsWriteFlush = ..., + linefeed: bool = ..., +) -> None: ... + def cov(m, y=..., rowvar=..., bias=..., ddof=..., fweights=..., aweights=..., *, dtype=...): ... def corrcoef(x, y=..., rowvar=..., bias = ..., ddof = ..., *, dtype=...): ... def blackman(M): ... diff --git a/numpy/typing/tests/data/fail/lib_function_base.pyi b/numpy/typing/tests/data/fail/lib_function_base.pyi new file mode 100644 index 000000000..019bd7f01 --- /dev/null +++ b/numpy/typing/tests/data/fail/lib_function_base.pyi @@ -0,0 +1,19 @@ +from typing import Any + +import numpy as np +import numpy.typing as npt + +AR_m: npt.NDArray[np.timedelta64] +AR_f8: npt.NDArray[np.float64] +AR_c16: npt.NDArray[np.complex128] + +np.average(AR_m) # E: incompatible type +np.select(1, [AR_f8]) # E: incompatible type +np.angle(AR_m) # E: incompatible type +np.unwrap(AR_m) # E: incompatible type +np.unwrap(AR_c16) # E: incompatible type +np.trim_zeros(1) # E: incompatible type +np.place(1, [True], 1.5) # E: incompatible type +np.vectorize(1) # E: incompatible type +np.add_newdoc("__main__", 1.5, "docstring") # E: incompatible type +np.place(AR_f8, slice(None), 5) # E: incompatible type diff --git a/numpy/typing/tests/data/fail/ndarray_misc.pyi b/numpy/typing/tests/data/fail/ndarray_misc.pyi index cf3fedc45..8320a44f3 100644 --- a/numpy/typing/tests/data/fail/ndarray_misc.pyi +++ b/numpy/typing/tests/data/fail/ndarray_misc.pyi @@ -35,3 +35,7 @@ AR_M.__int__() # E: Invalid self argument AR_M.__float__() # E: Invalid self argument AR_M.__complex__() # E: Invalid self argument AR_b.__index__() # E: Invalid self argument + +AR_f8[1.5] # E: No overload variant +AR_f8["field_a"] # E: No overload variant +AR_f8[["field_a", "field_b"]] # E: Invalid index type diff --git a/numpy/typing/tests/data/reveal/lib_function_base.pyi b/numpy/typing/tests/data/reveal/lib_function_base.pyi new file mode 100644 index 000000000..76d54c49f --- /dev/null +++ b/numpy/typing/tests/data/reveal/lib_function_base.pyi @@ -0,0 +1,99 @@ +from typing import Any + +import numpy as np +import numpy.typing as npt + +vectorized_func: np.vectorize + +f8: np.float64 +AR_LIKE_f8: list[float] + +AR_i8: npt.NDArray[np.int64] +AR_f8: npt.NDArray[np.float64] +AR_c16: npt.NDArray[np.complex128] +AR_O: npt.NDArray[np.object_] +AR_b: npt.NDArray[np.bool_] +AR_U: npt.NDArray[np.str_] +CHAR_AR_U: np.chararray[Any, np.dtype[np.str_]] + +def func(*args: Any, **kwargs: Any) -> Any: ... + +reveal_type(vectorized_func.pyfunc) # E: def (*Any, **Any) -> Any +reveal_type(vectorized_func.cache) # E: bool +reveal_type(vectorized_func.signature) # E: Union[None, builtins.str] +reveal_type(vectorized_func.otypes) # E: Union[None, builtins.str] +reveal_type(vectorized_func.excluded) # E: set[Union[builtins.int, builtins.str]] +reveal_type(vectorized_func.__doc__) # E: Union[None, builtins.str] +reveal_type(vectorized_func([1])) # E: numpy.ndarray[Any, numpy.dtype[Any]] +reveal_type(np.vectorize(int)) # E: numpy.vectorize +reveal_type(np.vectorize( # E: numpy.vectorize + int, otypes="i", doc="doc", excluded=(), cache=True, signature=None +)) + +reveal_type(np.add_newdoc("__main__", "blabla", doc="test doc")) # E: None +reveal_type(np.add_newdoc("__main__", "blabla", doc=("meth", "test doc"))) # E: None +reveal_type(np.add_newdoc("__main__", "blabla", doc=[("meth", "test doc")])) # E: None + +reveal_type(np.rot90(AR_f8, k=2)) # E: numpy.ndarray[Any, numpy.dtype[{float64}]] +reveal_type(np.rot90(AR_LIKE_f8, axes=(0, 1))) # E: numpy.ndarray[Any, numpy.dtype[Any]] + +reveal_type(np.flip(f8)) # E: {float64} +reveal_type(np.flip(1.0)) # E: Any +reveal_type(np.flip(AR_f8, axis=(0, 1))) # E: numpy.ndarray[Any, numpy.dtype[{float64}]] +reveal_type(np.flip(AR_LIKE_f8, axis=0)) # E: numpy.ndarray[Any, numpy.dtype[Any]] + +reveal_type(np.iterable(1)) # E: bool +reveal_type(np.iterable([1])) # E: bool + +reveal_type(np.average(AR_f8)) # E: numpy.floating[Any] +reveal_type(np.average(AR_f8, weights=AR_c16)) # E: numpy.complexfloating[Any, Any] +reveal_type(np.average(AR_O)) # E: Any +reveal_type(np.average(AR_f8, returned=True)) # E: Tuple[numpy.floating[Any], numpy.floating[Any]] +reveal_type(np.average(AR_f8, weights=AR_c16, returned=True)) # E: Tuple[numpy.complexfloating[Any, Any], numpy.complexfloating[Any, Any]] +reveal_type(np.average(AR_O, returned=True)) # E: Tuple[Any, Any] +reveal_type(np.average(AR_f8, axis=0)) # E: Any +reveal_type(np.average(AR_f8, axis=0, returned=True)) # E: Tuple[Any, Any] + +reveal_type(np.asarray_chkfinite(AR_f8)) # E: numpy.ndarray[Any, numpy.dtype[{float64}]] +reveal_type(np.asarray_chkfinite(AR_LIKE_f8)) # E: numpy.ndarray[Any, numpy.dtype[Any]] +reveal_type(np.asarray_chkfinite(AR_f8, dtype=np.float64)) # E: numpy.ndarray[Any, numpy.dtype[{float64}]] +reveal_type(np.asarray_chkfinite(AR_f8, dtype=float)) # E: numpy.ndarray[Any, numpy.dtype[Any]] + +reveal_type(np.piecewise(AR_f8, AR_b, [func])) # E: numpy.ndarray[Any, numpy.dtype[{float64}]] +reveal_type(np.piecewise(AR_LIKE_f8, AR_b, [func])) # E: numpy.ndarray[Any, numpy.dtype[Any]] + +reveal_type(np.select([AR_f8], [AR_f8])) # E: numpy.ndarray[Any, numpy.dtype[Any]] + +reveal_type(np.copy(AR_LIKE_f8)) # E: numpy.ndarray[Any, numpy.dtype[Any]] +reveal_type(np.copy(AR_U)) # E: numpy.ndarray[Any, numpy.dtype[numpy.str_]] +reveal_type(np.copy(CHAR_AR_U)) # E: numpy.ndarray[Any, Any] +reveal_type(np.copy(CHAR_AR_U, "K", subok=True)) # E: numpy.chararray[Any, numpy.dtype[numpy.str_]] +reveal_type(np.copy(CHAR_AR_U, subok=True)) # E: numpy.chararray[Any, numpy.dtype[numpy.str_]] + +reveal_type(np.gradient(AR_f8, axis=None)) # E: Any +reveal_type(np.gradient(AR_LIKE_f8, edge_order=2)) # E: Any + +reveal_type(np.diff("bob", n=0)) # E: str +reveal_type(np.diff(AR_f8, axis=0)) # E: numpy.ndarray[Any, numpy.dtype[Any]] +reveal_type(np.diff(AR_LIKE_f8, prepend=1.5)) # E: numpy.ndarray[Any, numpy.dtype[Any]] + +reveal_type(np.angle(AR_f8)) # E: numpy.floating[Any] +reveal_type(np.angle(AR_c16, deg=True)) # E: numpy.complexfloating[Any, Any] +reveal_type(np.angle(AR_O)) # E: Any + +reveal_type(np.unwrap(AR_f8)) # E: numpy.ndarray[Any, numpy.dtype[numpy.floating[Any]]] +reveal_type(np.unwrap(AR_O)) # E: numpy.ndarray[Any, numpy.dtype[numpy.object_]] + +reveal_type(np.sort_complex(AR_f8)) # E: numpy.ndarray[Any, numpy.dtype[numpy.complexfloating[Any, Any]]] + +reveal_type(np.trim_zeros(AR_f8)) # E: numpy.ndarray[Any, numpy.dtype[{float64}]] +reveal_type(np.trim_zeros(AR_LIKE_f8)) # E: list[builtins.float] + +reveal_type(np.extract(AR_i8, AR_f8)) # E: numpy.ndarray[Any, numpy.dtype[{float64}]] +reveal_type(np.extract(AR_i8, AR_LIKE_f8)) # E: numpy.ndarray[Any, numpy.dtype[Any]] + +reveal_type(np.place(AR_f8, mask=AR_i8, vals=5.0)) # E: None + +reveal_type(np.disp(1, linefeed=True)) # E: None +with open("test", "w") as f: + reveal_type(np.disp("message", device=f)) # E: None diff --git a/numpy/typing/tests/data/reveal/ndarray_misc.pyi b/numpy/typing/tests/data/reveal/ndarray_misc.pyi index 050b82cdc..e384b5388 100644 --- a/numpy/typing/tests/data/reveal/ndarray_misc.pyi +++ b/numpy/typing/tests/data/reveal/ndarray_misc.pyi @@ -20,6 +20,7 @@ B: SubClass AR_f8: NDArray[np.float64] AR_i8: NDArray[np.int64] AR_U: NDArray[np.str_] +AR_V: NDArray[np.void] ctypes_obj = AR_f8.ctypes @@ -193,3 +194,13 @@ reveal_type(operator.index(AR_i8)) # E: int reveal_type(AR_f8.__array_prepare__(B)) # E: numpy.ndarray[Any, numpy.dtype[numpy.object_]] reveal_type(AR_f8.__array_wrap__(B)) # E: numpy.ndarray[Any, numpy.dtype[numpy.object_]] + +reveal_type(AR_V[0]) # E: Any +reveal_type(AR_V[0, 0]) # E: Any +reveal_type(AR_V[AR_i8]) # E: Any +reveal_type(AR_V[AR_i8, AR_i8]) # E: Any +reveal_type(AR_V[AR_i8, None]) # E: numpy.ndarray[Any, numpy.dtype[numpy.void]] +reveal_type(AR_V[0, ...]) # E: numpy.ndarray[Any, numpy.dtype[numpy.void]] +reveal_type(AR_V[:]) # E: numpy.ndarray[Any, numpy.dtype[numpy.void]] +reveal_type(AR_V["a"]) # E: numpy.ndarray[Any, numpy.dtype[Any]] +reveal_type(AR_V[["a", "b"]]) # E: numpy.ndarray[Any, numpy.dtype[numpy.void]] |