Skip to content

Commit f302af7

Browse files
committed
🏷️ stub lib.user_array and lib._user_array_impl
1 parent 18e6c4e commit f302af7

File tree

3 files changed

+242
-0
lines changed

3 files changed

+242
-0
lines changed
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
from _typeshed import Incomplete
2+
from types import EllipsisType
3+
from typing import Any, Generic, SupportsIndex, TypeAlias, TypeVar, overload
4+
from typing_extensions import Self, deprecated, override
5+
6+
import numpy as np
7+
import numpy.typing as npt
8+
from numpy._typing import _ArrayLike, _ArrayLikeBool_co, _ArrayLikeInt_co, _DTypeLike
9+
10+
###
11+
12+
_ScalarT = TypeVar("_ScalarT", bound=np.generic)
13+
_ShapeT = TypeVar("_ShapeT", bound=tuple[int, ...])
14+
_ShapeT_co = TypeVar("_ShapeT_co", bound=tuple[int, ...], default=Any, covariant=True)
15+
_DTypeT = TypeVar("_DTypeT", bound=np.dtype[Any])
16+
_DTypeT_co = TypeVar("_DTypeT_co", bound=np.dtype[Any], default=np.dtype[Any], covariant=True)
17+
18+
_BoolArrayT = TypeVar("_BoolArrayT", bound=container[Any, np.dtype[np.bool]])
19+
_IntegralArrayT = TypeVar("_IntegralArrayT", bound=container[Any, np.dtype[np.bool | np.integer | np.object_]])
20+
_RealContainerT = TypeVar(
21+
"_RealContainerT",
22+
bound=container[Any, np.dtype[np.bool | np.integer | np.floating | np.timedelta64 | np.object_]],
23+
)
24+
_NumericContainerT = TypeVar("_NumericContainerT", bound=container[Any, np.dtype[np.number | np.timedelta64 | np.object_]])
25+
26+
_ArrayInt_co: TypeAlias = npt.NDArray[np.integer | np.bool]
27+
28+
_ToIndexSlice: TypeAlias = slice | EllipsisType | _ArrayInt_co | None
29+
_ToIndexSlices: TypeAlias = _ToIndexSlice | tuple[_ToIndexSlice, ...]
30+
_ToIndex: TypeAlias = SupportsIndex | _ToIndexSlice
31+
_ToIndices: TypeAlias = _ToIndex | tuple[_ToIndex, ...]
32+
33+
###
34+
35+
class container(Generic[_ShapeT_co, _DTypeT_co]):
36+
array: np.ndarray[_ShapeT_co, _DTypeT_co]
37+
38+
@overload
39+
def __init__(
40+
self,
41+
/,
42+
data: container[_ShapeT_co, _DTypeT_co] | np.ndarray[_ShapeT_co, _DTypeT_co],
43+
dtype: None = None,
44+
copy: bool = True,
45+
) -> None: ...
46+
@overload
47+
def __init__(
48+
self: container[Any, np.dtype[_ScalarT]],
49+
/,
50+
data: _ArrayLike[_ScalarT],
51+
dtype: None = None,
52+
copy: bool = True,
53+
) -> None: ...
54+
@overload
55+
def __init__(
56+
self: container[Any, np.dtype[_ScalarT]],
57+
/,
58+
data: npt.ArrayLike,
59+
dtype: _DTypeLike[_ScalarT],
60+
copy: bool = True,
61+
) -> None: ...
62+
@overload
63+
def __init__(self, /, data: npt.ArrayLike, dtype: npt.DTypeLike | None = None, copy: bool = True) -> None: ...
64+
65+
#
66+
def __complex__(self, /) -> complex: ...
67+
def __float__(self, /) -> float: ...
68+
def __int__(self, /) -> int: ...
69+
def __hex__(self, /) -> str: ...
70+
def __oct__(self, /) -> str: ...
71+
72+
#
73+
@override
74+
def __eq__(self, other: object, /) -> container[_ShapeT_co, np.dtype[np.bool]]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
75+
@override
76+
def __ne__(self, other: object, /) -> container[_ShapeT_co, np.dtype[np.bool]]: ... # type: ignore[override] # pyright: ignore[reportIncompatibleMethodOverride]
77+
78+
#
79+
def __lt__(self, other: npt.ArrayLike, /) -> container[_ShapeT_co, np.dtype[np.bool]]: ...
80+
def __le__(self, other: npt.ArrayLike, /) -> container[_ShapeT_co, np.dtype[np.bool]]: ...
81+
def __gt__(self, other: npt.ArrayLike, /) -> container[_ShapeT_co, np.dtype[np.bool]]: ...
82+
def __ge__(self, other: npt.ArrayLike, /) -> container[_ShapeT_co, np.dtype[np.bool]]: ...
83+
84+
#
85+
def __len__(self, /) -> int: ...
86+
87+
# keep in sync with np.ndarray
88+
@overload
89+
def __getitem__(self, key: _ArrayInt_co | tuple[_ArrayInt_co, ...], /) -> container[_ShapeT_co, _DTypeT_co]: ...
90+
@overload
91+
def __getitem__(self, key: _ToIndexSlices, /) -> container[Any, _DTypeT_co]: ...
92+
@overload
93+
def __getitem__(self, key: _ToIndices, /) -> Any: ...
94+
@overload
95+
def __getitem__(self: container[Any, np.dtype[np.void]], key: list[str], /) -> container[_ShapeT_co, np.dtype[np.void]]: ...
96+
@overload
97+
def __getitem__(self: container[Any, np.dtype[np.void]], key: str, /) -> container[_ShapeT_co, np.dtype[Any]]: ...
98+
99+
# keep in sync with np.ndarray
100+
@overload
101+
def __setitem__(self, index: _ToIndices, value: object, /) -> None: ...
102+
@overload
103+
def __setitem__(self: container[Any, np.dtype[np.void]], key: str | list[str], value: object, /) -> None: ...
104+
105+
# keep in sync with np.ndarray
106+
@overload
107+
def __abs__(self: container[_ShapeT, np.dtype[np.complex64]], /) -> container[_ShapeT, np.dtype[np.float32]]: ... # type: ignore[overload-overlap]
108+
@overload
109+
def __abs__(self: container[_ShapeT, np.dtype[np.complex128]], /) -> container[_ShapeT, np.dtype[np.float64]]: ...
110+
@overload
111+
def __abs__(self: container[_ShapeT, np.dtype[np.complex192]], /) -> container[_ShapeT, np.dtype[np.float96]]: ...
112+
@overload
113+
def __abs__(self: container[_ShapeT, np.dtype[np.complex256]], /) -> container[_ShapeT, np.dtype[np.float128]]: ...
114+
@overload
115+
def __abs__(self: _RealContainerT, /) -> _RealContainerT: ...
116+
117+
#
118+
def __neg__(self: _NumericContainerT, /) -> _NumericContainerT: ... # noqa: PYI019
119+
def __pos__(self: _NumericContainerT, /) -> _NumericContainerT: ... # noqa: PYI019
120+
def __invert__(self: _IntegralArrayT, /) -> _IntegralArrayT: ... # noqa: PYI019
121+
122+
# TODO(jorenham): complete these binary ops
123+
124+
#
125+
def __add__(self, other: npt.ArrayLike, /) -> Incomplete: ...
126+
def __radd__(self, other: npt.ArrayLike, /) -> Incomplete: ...
127+
def __iadd__(self, other: npt.ArrayLike, /) -> Self: ...
128+
129+
#
130+
def __sub__(self, other: npt.ArrayLike, /) -> Incomplete: ...
131+
def __rsub__(self, other: npt.ArrayLike, /) -> Incomplete: ...
132+
def __isub__(self, other: npt.ArrayLike, /) -> Self: ...
133+
134+
#
135+
def __mul__(self, other: npt.ArrayLike, /) -> Incomplete: ...
136+
def __rmul__(self, other: npt.ArrayLike, /) -> Incomplete: ...
137+
def __imul__(self, other: npt.ArrayLike, /) -> Self: ...
138+
139+
#
140+
def __div__(self, other: npt.ArrayLike, /) -> Incomplete: ...
141+
def __rdiv__(self, other: npt.ArrayLike, /) -> Incomplete: ...
142+
def __idiv__(self, other: npt.ArrayLike, /) -> Self: ...
143+
144+
#
145+
def __mod__(self, other: npt.ArrayLike, /) -> Incomplete: ...
146+
def __rmod__(self, other: npt.ArrayLike, /) -> Incomplete: ...
147+
def __imod__(self, other: npt.ArrayLike, /) -> Self: ...
148+
149+
#
150+
def __divmod__(self, other: npt.ArrayLike, /) -> tuple[Incomplete, Incomplete]: ...
151+
def __rdivmod__(self, other: npt.ArrayLike, /) -> tuple[Incomplete, Incomplete]: ...
152+
153+
#
154+
def __pow__(self, other: npt.ArrayLike, /) -> Incomplete: ...
155+
def __rpow__(self, other: npt.ArrayLike, /) -> Incomplete: ...
156+
def __ipow__(self, other: npt.ArrayLike, /) -> Self: ...
157+
158+
#
159+
def __lshift__(self, other: _ArrayLikeInt_co, /) -> container[Any, np.dtype[np.integer]]: ...
160+
def __rlshift__(self, other: _ArrayLikeInt_co, /) -> container[Any, np.dtype[np.integer]]: ...
161+
def __ilshift__(self, other: _ArrayLikeInt_co, /) -> Self: ...
162+
163+
#
164+
def __rshift__(self, other: _ArrayLikeInt_co, /) -> container[Any, np.dtype[np.integer]]: ...
165+
def __rrshift__(self, other: _ArrayLikeInt_co, /) -> container[Any, np.dtype[np.integer]]: ...
166+
def __irshift__(self, other: _ArrayLikeInt_co, /) -> Self: ...
167+
168+
#
169+
@overload
170+
def __and__(self: container[Any, np.dtype[np.bool]], other: _ArrayLikeBool_co, /) -> container[Any, np.dtype[np.bool]]: ...
171+
@overload
172+
def __and__(self, other: _ArrayLikeInt_co, /) -> container[Any, np.dtype[np.bool | np.integer]]: ...
173+
__rand__ = __and__
174+
@overload
175+
def __iand__(self: _BoolArrayT, other: _ArrayLikeBool_co, /) -> _BoolArrayT: ...
176+
@overload
177+
def __iand__(self, other: _ArrayLikeInt_co, /) -> Self: ...
178+
179+
#
180+
@overload
181+
def __xor__(self: container[Any, np.dtype[np.bool]], other: _ArrayLikeBool_co, /) -> container[Any, np.dtype[np.bool]]: ...
182+
@overload
183+
def __xor__(self, other: _ArrayLikeInt_co, /) -> container[Any, np.dtype[np.bool | np.integer]]: ...
184+
__rxor__ = __xor__
185+
@overload
186+
def __ixor__(self: _BoolArrayT, other: _ArrayLikeBool_co, /) -> _BoolArrayT: ...
187+
@overload
188+
def __ixor__(self, other: _ArrayLikeInt_co, /) -> Self: ...
189+
190+
#
191+
@overload
192+
def __or__(self: container[Any, np.dtype[np.bool]], other: _ArrayLikeBool_co, /) -> container[Any, np.dtype[np.bool]]: ...
193+
@overload
194+
def __or__(self, other: _ArrayLikeInt_co, /) -> container[Any, np.dtype[np.bool | np.integer]]: ...
195+
__ror__ = __or__
196+
@overload
197+
def __ior__(self: _BoolArrayT, other: _ArrayLikeBool_co, /) -> _BoolArrayT: ...
198+
@overload
199+
def __ior__(self, other: _ArrayLikeInt_co, /) -> Self: ...
200+
201+
#
202+
@overload
203+
def __array__(self, /, t: None = None) -> np.ndarray[_ShapeT_co, _DTypeT_co]: ...
204+
@overload
205+
def __array__(self, /, t: _DTypeT) -> np.ndarray[_ShapeT_co, _DTypeT]: ...
206+
207+
#
208+
@overload
209+
def __array_wrap__(self, arg0: npt.ArrayLike, /) -> container[_ShapeT_co, _DTypeT_co]: ...
210+
@overload
211+
def __array_wrap__(self, a: np.ndarray[_ShapeT, _DTypeT], c: Any = ..., s: Any = ..., /) -> container[_ShapeT, _DTypeT]: ...
212+
213+
#
214+
def copy(self, /) -> Self: ...
215+
@deprecated("tostring() is deprecated. Use tobytes() instead.")
216+
def tostring(self, /) -> bytes: ...
217+
def tobytes(self, /) -> bytes: ...
218+
def byteswap(self, /) -> Self: ...
219+
def astype(self, /, typecode: _DTypeLike[_ScalarT]) -> container[_ShapeT_co, np.dtype[_ScalarT]]: ...

src/numpy-stubs/lib/user_array.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from ._user_array_impl import container as container

test/runtime/accept/lib_user_array.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""Base on the `if __name__ == "__main__"` test code in `lib/_user_array_impl.py`."""
2+
3+
from __future__ import annotations
4+
5+
import numpy as np
6+
from numpy.lib.user_array import container
7+
8+
N = 10_000
9+
W = H = int(N**0.5)
10+
11+
a: np.ndarray[tuple[int, int], np.dtype[np.int32]]
12+
ua: container[tuple[int, int], np.dtype[np.int32]]
13+
14+
a = np.arange(N, dtype=np.int32).reshape(W, H)
15+
ua = container(a)
16+
17+
ua_small: container[tuple[int, int], np.dtype[np.int32]] = ua[:3, :5]
18+
ua_small[0, 0] = 10
19+
20+
ua_bool: container[tuple[int, int], np.dtype[np.bool]] = ua_small > 1
21+
22+
# shape: tuple[int, int] = np.shape(ua)

0 commit comments

Comments
 (0)