Skip to content

Commit a37a51c

Browse files
authored
Merge pull request numpy#20230 from BvB93/ctypeslib
ENH: Add annotations for `np.ctypeslib`
2 parents 1e70045 + 66df704 commit a37a51c

File tree

3 files changed

+408
-22
lines changed

3 files changed

+408
-22
lines changed

numpy/ctypeslib.pyi

Lines changed: 260 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,268 @@
1-
from typing import List, Type
2-
31
# NOTE: Numpy's mypy plugin is used for importing the correct
42
# platform-specific `ctypes._SimpleCData[int]` sub-type
53
from ctypes import c_int64 as _c_intp
64

5+
import os
6+
import sys
7+
import ctypes
8+
from typing import (
9+
Literal as L,
10+
Any,
11+
List,
12+
Union,
13+
TypeVar,
14+
Type,
15+
Generic,
16+
Optional,
17+
overload,
18+
Iterable,
19+
ClassVar,
20+
Tuple,
21+
Sequence,
22+
Dict,
23+
)
24+
25+
from numpy import (
26+
ndarray,
27+
dtype,
28+
generic,
29+
bool_,
30+
byte,
31+
short,
32+
intc,
33+
int_,
34+
longlong,
35+
ubyte,
36+
ushort,
37+
uintc,
38+
uint,
39+
ulonglong,
40+
single,
41+
double,
42+
float_,
43+
longdouble,
44+
void,
45+
)
46+
from numpy.core._internal import _ctypes
47+
from numpy.core.multiarray import flagsobj
48+
from numpy.typing import (
49+
# Arrays
50+
ArrayLike,
51+
NDArray,
52+
_FiniteNestedSequence,
53+
_SupportsArray,
54+
55+
# Shapes
56+
_ShapeLike,
57+
58+
# DTypes
59+
DTypeLike,
60+
_SupportsDType,
61+
_VoidDTypeLike,
62+
_BoolCodes,
63+
_UByteCodes,
64+
_UShortCodes,
65+
_UIntCCodes,
66+
_UIntCodes,
67+
_ULongLongCodes,
68+
_ByteCodes,
69+
_ShortCodes,
70+
_IntCCodes,
71+
_IntCodes,
72+
_LongLongCodes,
73+
_SingleCodes,
74+
_DoubleCodes,
75+
_LongDoubleCodes,
76+
)
77+
78+
# TODO: Add a proper `_Shape` bound once we've got variadic typevars
79+
_DType = TypeVar("_DType", bound=dtype[Any])
80+
_DTypeOptional = TypeVar("_DTypeOptional", bound=Optional[dtype[Any]])
81+
_SCT = TypeVar("_SCT", bound=generic)
82+
83+
_DTypeLike = Union[
84+
dtype[_SCT],
85+
Type[_SCT],
86+
_SupportsDType[dtype[_SCT]],
87+
]
88+
_ArrayLike = _FiniteNestedSequence[_SupportsArray[dtype[_SCT]]]
89+
90+
_FlagsKind = L[
91+
'C_CONTIGUOUS', 'CONTIGUOUS', 'C',
92+
'F_CONTIGUOUS', 'FORTRAN', 'F',
93+
'ALIGNED', 'A',
94+
'WRITEABLE', 'W',
95+
'OWNDATA', 'O',
96+
'UPDATEIFCOPY', 'U',
97+
'WRITEBACKIFCOPY', 'X',
98+
]
99+
100+
# TODO: Add a shape typevar once we have variadic typevars (PEP 646)
101+
class _ndptr(ctypes.c_void_p, Generic[_DTypeOptional]):
102+
# In practice these 4 classvars are defined in the dynamic class
103+
# returned by `ndpointer`
104+
_dtype_: ClassVar[_DTypeOptional]
105+
_shape_: ClassVar[None]
106+
_ndim_: ClassVar[None | int]
107+
_flags_: ClassVar[None | List[_FlagsKind]]
108+
109+
@overload
110+
@classmethod
111+
def from_param(cls: Type[_ndptr[None]], obj: ndarray[Any, Any]) -> _ctypes: ...
112+
@overload
113+
@classmethod
114+
def from_param(cls: Type[_ndptr[_DType]], obj: ndarray[Any, _DType]) -> _ctypes: ...
115+
116+
class _concrete_ndptr(_ndptr[_DType]):
117+
_dtype_: ClassVar[_DType]
118+
_shape_: ClassVar[Tuple[int, ...]]
119+
@property
120+
def contents(self) -> ndarray[Any, _DType]: ...
121+
122+
def load_library(
123+
libname: str | bytes | os.PathLike[str] | os.PathLike[bytes],
124+
loader_path: str | bytes | os.PathLike[str] | os.PathLike[bytes],
125+
) -> ctypes.CDLL: ...
126+
7127
__all__: List[str]
8128

9129
c_intp = _c_intp
10130

11-
def load_library(libname, loader_path): ...
12-
def ndpointer(dtype=..., ndim=..., shape=..., flags=...): ...
13-
def as_ctypes(obj): ...
14-
def as_array(obj, shape=...): ...
15-
def as_ctypes_type(dtype): ...
131+
@overload
132+
def ndpointer(
133+
dtype: None = ...,
134+
ndim: int = ...,
135+
shape: None | _ShapeLike = ...,
136+
flags: None | _FlagsKind | Iterable[_FlagsKind] | int | flagsobj = ...,
137+
) -> Type[_ndptr[None]]: ...
138+
@overload
139+
def ndpointer(
140+
dtype: _DTypeLike[_SCT],
141+
ndim: int = ...,
142+
*,
143+
shape: _ShapeLike,
144+
flags: None | _FlagsKind | Iterable[_FlagsKind] | int | flagsobj = ...,
145+
) -> Type[_concrete_ndptr[dtype[_SCT]]]: ...
146+
@overload
147+
def ndpointer(
148+
dtype: DTypeLike,
149+
ndim: int = ...,
150+
*,
151+
shape: _ShapeLike,
152+
flags: None | _FlagsKind | Iterable[_FlagsKind] | int | flagsobj = ...,
153+
) -> Type[_concrete_ndptr[dtype[Any]]]: ...
154+
@overload
155+
def ndpointer(
156+
dtype: _DTypeLike[_SCT],
157+
ndim: int = ...,
158+
shape: None = ...,
159+
flags: None | _FlagsKind | Iterable[_FlagsKind] | int | flagsobj = ...,
160+
) -> Type[_ndptr[dtype[_SCT]]]: ...
161+
@overload
162+
def ndpointer(
163+
dtype: DTypeLike,
164+
ndim: int = ...,
165+
shape: None = ...,
166+
flags: None | _FlagsKind | Iterable[_FlagsKind] | int | flagsobj = ...,
167+
) -> Type[_ndptr[dtype[Any]]]: ...
168+
169+
@overload
170+
def as_ctypes_type(dtype: _BoolCodes | _DTypeLike[bool_] | Type[ctypes.c_bool]) -> Type[ctypes.c_bool]: ...
171+
@overload
172+
def as_ctypes_type(dtype: _ByteCodes | _DTypeLike[byte] | Type[ctypes.c_byte]) -> Type[ctypes.c_byte]: ...
173+
@overload
174+
def as_ctypes_type(dtype: _ShortCodes | _DTypeLike[short] | Type[ctypes.c_short]) -> Type[ctypes.c_short]: ...
175+
@overload
176+
def as_ctypes_type(dtype: _IntCCodes | _DTypeLike[intc] | Type[ctypes.c_int]) -> Type[ctypes.c_int]: ...
177+
@overload
178+
def as_ctypes_type(dtype: _IntCodes | _DTypeLike[int_] | Type[int | ctypes.c_long]) -> Type[ctypes.c_long]: ...
179+
@overload
180+
def as_ctypes_type(dtype: _LongLongCodes | _DTypeLike[longlong] | Type[ctypes.c_longlong]) -> Type[ctypes.c_longlong]: ...
181+
@overload
182+
def as_ctypes_type(dtype: _UByteCodes | _DTypeLike[ubyte] | Type[ctypes.c_ubyte]) -> Type[ctypes.c_ubyte]: ...
183+
@overload
184+
def as_ctypes_type(dtype: _UShortCodes | _DTypeLike[ushort] | Type[ctypes.c_ushort]) -> Type[ctypes.c_ushort]: ...
185+
@overload
186+
def as_ctypes_type(dtype: _UIntCCodes | _DTypeLike[uintc] | Type[ctypes.c_uint]) -> Type[ctypes.c_uint]: ...
187+
@overload
188+
def as_ctypes_type(dtype: _UIntCodes | _DTypeLike[uint] | Type[ctypes.c_ulong]) -> Type[ctypes.c_ulong]: ...
189+
@overload
190+
def as_ctypes_type(dtype: _ULongLongCodes | _DTypeLike[ulonglong] | Type[ctypes.c_ulonglong]) -> Type[ctypes.c_ulonglong]: ...
191+
@overload
192+
def as_ctypes_type(dtype: _SingleCodes | _DTypeLike[single] | Type[ctypes.c_float]) -> Type[ctypes.c_float]: ...
193+
@overload
194+
def as_ctypes_type(dtype: _DoubleCodes | _DTypeLike[double] | Type[float | ctypes.c_double]) -> Type[ctypes.c_double]: ...
195+
@overload
196+
def as_ctypes_type(dtype: _LongDoubleCodes | _DTypeLike[longdouble] | Type[ctypes.c_longdouble]) -> Type[ctypes.c_longdouble]: ...
197+
@overload
198+
def as_ctypes_type(dtype: _VoidDTypeLike) -> Type[Any]: ... # `ctypes.Union` or `ctypes.Structure`
199+
@overload
200+
def as_ctypes_type(dtype: str) -> Type[Any]: ...
201+
202+
@overload
203+
def as_array(obj: ctypes._PointerLike, shape: Sequence[int]) -> NDArray[Any]: ...
204+
@overload
205+
def as_array(obj: _ArrayLike[_SCT], shape: None | _ShapeLike = ...) -> NDArray[_SCT]: ...
206+
@overload
207+
def as_array(obj: object, shape: None | _ShapeLike = ...) -> NDArray[Any]: ...
208+
209+
@overload
210+
def as_ctypes(obj: bool_) -> ctypes.c_bool: ...
211+
@overload
212+
def as_ctypes(obj: byte) -> ctypes.c_byte: ...
213+
@overload
214+
def as_ctypes(obj: short) -> ctypes.c_short: ...
215+
@overload
216+
def as_ctypes(obj: intc) -> ctypes.c_int: ...
217+
@overload
218+
def as_ctypes(obj: int_) -> ctypes.c_long: ...
219+
@overload
220+
def as_ctypes(obj: longlong) -> ctypes.c_longlong: ...
221+
@overload
222+
def as_ctypes(obj: ubyte) -> ctypes.c_ubyte: ...
223+
@overload
224+
def as_ctypes(obj: ushort) -> ctypes.c_ushort: ...
225+
@overload
226+
def as_ctypes(obj: uintc) -> ctypes.c_uint: ...
227+
@overload
228+
def as_ctypes(obj: uint) -> ctypes.c_ulong: ...
229+
@overload
230+
def as_ctypes(obj: ulonglong) -> ctypes.c_ulonglong: ...
231+
@overload
232+
def as_ctypes(obj: single) -> ctypes.c_float: ...
233+
@overload
234+
def as_ctypes(obj: double) -> ctypes.c_double: ...
235+
@overload
236+
def as_ctypes(obj: longdouble) -> ctypes.c_longdouble: ...
237+
@overload
238+
def as_ctypes(obj: void) -> Any: ... # `ctypes.Union` or `ctypes.Structure`
239+
@overload
240+
def as_ctypes(obj: NDArray[bool_]) -> ctypes.Array[ctypes.c_bool]: ...
241+
@overload
242+
def as_ctypes(obj: NDArray[byte]) -> ctypes.Array[ctypes.c_byte]: ...
243+
@overload
244+
def as_ctypes(obj: NDArray[short]) -> ctypes.Array[ctypes.c_short]: ...
245+
@overload
246+
def as_ctypes(obj: NDArray[intc]) -> ctypes.Array[ctypes.c_int]: ...
247+
@overload
248+
def as_ctypes(obj: NDArray[int_]) -> ctypes.Array[ctypes.c_long]: ...
249+
@overload
250+
def as_ctypes(obj: NDArray[longlong]) -> ctypes.Array[ctypes.c_longlong]: ...
251+
@overload
252+
def as_ctypes(obj: NDArray[ubyte]) -> ctypes.Array[ctypes.c_ubyte]: ...
253+
@overload
254+
def as_ctypes(obj: NDArray[ushort]) -> ctypes.Array[ctypes.c_ushort]: ...
255+
@overload
256+
def as_ctypes(obj: NDArray[uintc]) -> ctypes.Array[ctypes.c_uint]: ...
257+
@overload
258+
def as_ctypes(obj: NDArray[uint]) -> ctypes.Array[ctypes.c_ulong]: ...
259+
@overload
260+
def as_ctypes(obj: NDArray[ulonglong]) -> ctypes.Array[ctypes.c_ulonglong]: ...
261+
@overload
262+
def as_ctypes(obj: NDArray[single]) -> ctypes.Array[ctypes.c_float]: ...
263+
@overload
264+
def as_ctypes(obj: NDArray[double]) -> ctypes.Array[ctypes.c_double]: ...
265+
@overload
266+
def as_ctypes(obj: NDArray[longdouble]) -> ctypes.Array[ctypes.c_longdouble]: ...
267+
@overload
268+
def as_ctypes(obj: NDArray[void]) -> ctypes.Array[Any]: ... # `ctypes.Union` or `ctypes.Structure`
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,87 @@
1+
import ctypes
2+
from typing import Any
3+
14
import numpy as np
5+
import numpy.typing as npt
6+
7+
AR_bool: npt.NDArray[np.bool_]
8+
AR_ubyte: npt.NDArray[np.ubyte]
9+
AR_ushort: npt.NDArray[np.ushort]
10+
AR_uintc: npt.NDArray[np.uintc]
11+
AR_uint: npt.NDArray[np.uint]
12+
AR_ulonglong: npt.NDArray[np.ulonglong]
13+
AR_byte: npt.NDArray[np.byte]
14+
AR_short: npt.NDArray[np.short]
15+
AR_intc: npt.NDArray[np.intc]
16+
AR_int: npt.NDArray[np.int_]
17+
AR_longlong: npt.NDArray[np.longlong]
18+
AR_single: npt.NDArray[np.single]
19+
AR_double: npt.NDArray[np.double]
20+
AR_longdouble: npt.NDArray[np.longdouble]
21+
AR_void: npt.NDArray[np.void]
22+
23+
pointer: ctypes.pointer[Any]
224

325
reveal_type(np.ctypeslib.c_intp()) # E: {c_intp}
26+
27+
reveal_type(np.ctypeslib.ndpointer()) # E: Type[numpy.ctypeslib._ndptr[None]]
28+
reveal_type(np.ctypeslib.ndpointer(dtype=np.float64)) # E: Type[numpy.ctypeslib._ndptr[numpy.dtype[{float64}]]]
29+
reveal_type(np.ctypeslib.ndpointer(dtype=float)) # E: Type[numpy.ctypeslib._ndptr[numpy.dtype[Any]]]
30+
reveal_type(np.ctypeslib.ndpointer(shape=(10, 3))) # E: Type[numpy.ctypeslib._ndptr[None]]
31+
reveal_type(np.ctypeslib.ndpointer(np.int64, shape=(10, 3))) # E: Type[numpy.ctypeslib._concrete_ndptr[numpy.dtype[{int64}]]]
32+
reveal_type(np.ctypeslib.ndpointer(int, shape=(1,))) # E: Type[numpy.ctypeslib._concrete_ndptr[numpy.dtype[Any]]]
33+
34+
reveal_type(np.ctypeslib.as_ctypes_type(np.bool_)) # E: Type[ctypes.c_bool]
35+
reveal_type(np.ctypeslib.as_ctypes_type(np.ubyte)) # E: Type[{c_ubyte}]
36+
reveal_type(np.ctypeslib.as_ctypes_type(np.ushort)) # E: Type[{c_ushort}]
37+
reveal_type(np.ctypeslib.as_ctypes_type(np.uintc)) # E: Type[{c_uint}]
38+
reveal_type(np.ctypeslib.as_ctypes_type(np.uint)) # E: Type[{c_ulong}]
39+
reveal_type(np.ctypeslib.as_ctypes_type(np.ulonglong)) # E: Type[{c_ulonglong}]
40+
reveal_type(np.ctypeslib.as_ctypes_type(np.byte)) # E: Type[{c_byte}]
41+
reveal_type(np.ctypeslib.as_ctypes_type(np.short)) # E: Type[{c_short}]
42+
reveal_type(np.ctypeslib.as_ctypes_type(np.intc)) # E: Type[{c_int}]
43+
reveal_type(np.ctypeslib.as_ctypes_type(np.int_)) # E: Type[{c_long}]
44+
reveal_type(np.ctypeslib.as_ctypes_type(np.longlong)) # E: Type[{c_longlong}]
45+
reveal_type(np.ctypeslib.as_ctypes_type(np.single)) # E: Type[{c_float}]
46+
reveal_type(np.ctypeslib.as_ctypes_type(np.double)) # E: Type[{c_double}]
47+
reveal_type(np.ctypeslib.as_ctypes_type(np.longdouble)) # E: Type[{c_longdouble}]
48+
reveal_type(np.ctypeslib.as_ctypes_type(ctypes.c_double)) # E: Type[{c_double}]
49+
reveal_type(np.ctypeslib.as_ctypes_type("q")) # E: Type[ctypes.c_longlong]
50+
reveal_type(np.ctypeslib.as_ctypes_type([("i8", np.int64), ("f8", np.float64)])) # E: Type[Any]
51+
reveal_type(np.ctypeslib.as_ctypes_type("i8")) # E: Type[Any]
52+
reveal_type(np.ctypeslib.as_ctypes_type("f8")) # E: Type[Any]
53+
54+
reveal_type(np.ctypeslib.as_ctypes(AR_bool.take(0))) # E: ctypes.c_bool
55+
reveal_type(np.ctypeslib.as_ctypes(AR_ubyte.take(0))) # E: {c_ubyte}
56+
reveal_type(np.ctypeslib.as_ctypes(AR_ushort.take(0))) # E: {c_ushort}
57+
reveal_type(np.ctypeslib.as_ctypes(AR_uintc.take(0))) # E: {c_uint}
58+
reveal_type(np.ctypeslib.as_ctypes(AR_uint.take(0))) # E: {c_ulong}
59+
reveal_type(np.ctypeslib.as_ctypes(AR_ulonglong.take(0))) # E: {c_ulonglong}
60+
reveal_type(np.ctypeslib.as_ctypes(AR_byte.take(0))) # E: {c_byte}
61+
reveal_type(np.ctypeslib.as_ctypes(AR_short.take(0))) # E: {c_short}
62+
reveal_type(np.ctypeslib.as_ctypes(AR_intc.take(0))) # E: {c_int}
63+
reveal_type(np.ctypeslib.as_ctypes(AR_int.take(0))) # E: {c_long}
64+
reveal_type(np.ctypeslib.as_ctypes(AR_longlong.take(0))) # E: {c_longlong}
65+
reveal_type(np.ctypeslib.as_ctypes(AR_single.take(0))) # E: {c_float}
66+
reveal_type(np.ctypeslib.as_ctypes(AR_double.take(0))) # E: {c_double}
67+
reveal_type(np.ctypeslib.as_ctypes(AR_longdouble.take(0))) # E: {c_longdouble}
68+
reveal_type(np.ctypeslib.as_ctypes(AR_void.take(0))) # E: Any
69+
reveal_type(np.ctypeslib.as_ctypes(AR_bool)) # E: ctypes.Array[ctypes.c_bool]
70+
reveal_type(np.ctypeslib.as_ctypes(AR_ubyte)) # E: ctypes.Array[{c_ubyte}]
71+
reveal_type(np.ctypeslib.as_ctypes(AR_ushort)) # E: ctypes.Array[{c_ushort}]
72+
reveal_type(np.ctypeslib.as_ctypes(AR_uintc)) # E: ctypes.Array[{c_uint}]
73+
reveal_type(np.ctypeslib.as_ctypes(AR_uint)) # E: ctypes.Array[{c_ulong}]
74+
reveal_type(np.ctypeslib.as_ctypes(AR_ulonglong)) # E: ctypes.Array[{c_ulonglong}]
75+
reveal_type(np.ctypeslib.as_ctypes(AR_byte)) # E: ctypes.Array[{c_byte}]
76+
reveal_type(np.ctypeslib.as_ctypes(AR_short)) # E: ctypes.Array[{c_short}]
77+
reveal_type(np.ctypeslib.as_ctypes(AR_intc)) # E: ctypes.Array[{c_int}]
78+
reveal_type(np.ctypeslib.as_ctypes(AR_int)) # E: ctypes.Array[{c_long}]
79+
reveal_type(np.ctypeslib.as_ctypes(AR_longlong)) # E: ctypes.Array[{c_longlong}]
80+
reveal_type(np.ctypeslib.as_ctypes(AR_single)) # E: ctypes.Array[{c_float}]
81+
reveal_type(np.ctypeslib.as_ctypes(AR_double)) # E: ctypes.Array[{c_double}]
82+
reveal_type(np.ctypeslib.as_ctypes(AR_longdouble)) # E: ctypes.Array[{c_longdouble}]
83+
reveal_type(np.ctypeslib.as_ctypes(AR_void)) # E: ctypes.Array[Any]
84+
85+
reveal_type(np.ctypeslib.as_array(AR_ubyte)) # E: numpy.ndarray[Any, numpy.dtype[{ubyte}]]
86+
reveal_type(np.ctypeslib.as_array(1)) # E: numpy.ndarray[Any, numpy.dtype[Any]]
87+
reveal_type(np.ctypeslib.as_array(pointer)) # E: numpy.ndarray[Any, numpy.dtype[Any]]

0 commit comments

Comments
 (0)