Repository navigation
Expand file tree
/
Copy pathcustom_binding.py
More file actions
71 lines (55 loc) · 1.85 KB
/
Copy pathcustom_binding.py
File metadata and controls
71 lines (55 loc) · 1.85 KB
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
import ctypes
from functools import wraps
from typing import TYPE_CHECKING, Any, Callable, Optional, Type, TypeVar
from typing_extensions import ParamSpec
from .bindings import binding_base, make_string
if TYPE_CHECKING:
from ctypes import _NamedFuncPointer
from .structure import Struct
T = TypeVar("T")
P = ParamSpec("P")
__all__ = ("binds", "binding")
def binds(
dll_func: "_NamedFuncPointer",
*,
struct: Optional[Type["Struct"]] = None,
):
def decorator(func: Callable[P, T]) -> Callable[P, T]:
@wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
if kwargs:
raise ValueError(
"keyword arguments are not allowed when calling C functions" # noqa
)
restype = dll_func.restype
if (
struct
and (not issubclass(restype, ctypes.Structure)) # type: ignore
and (not (restype or int).__name__.startswith("LP_"))
):
raise ValueError("restype must be a ctypes structure")
return binding_base(
dll_func,
*[
# fmt: off
i if not isinstance(i, str)
else make_string(i)
# fmt: on
for i in args # type: ignore
],
map_extra={
dll_func.restype: struct, # type: ignore
}
if struct
else None,
)
return wrapper
return decorator
def binding(
dll_func: "_NamedFuncPointer",
struct: Optional[Type["Struct"]] = None,
):
@binds(dll_func, struct=struct)
def wrapper(*args, **kwargs) -> Any:
...
return wrapper