File: ctypesutil.py

package info (click to toggle)
python-can 4.5.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,372 kB
  • sloc: python: 25,840; makefile: 38; sh: 20
file content (91 lines) | stat: -rw-r--r-- 2,463 bytes parent folder | download
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
"""
This module contains common `ctypes` utils.
"""

import ctypes
import logging
import sys
from typing import Any, Callable, Optional, Tuple, Union

log = logging.getLogger("can.ctypesutil")

__all__ = ["CLibrary", "HANDLE", "PHANDLE", "HRESULT"]

if sys.platform == "win32":
    _LibBase = ctypes.WinDLL
    _FUNCTION_TYPE = ctypes.WINFUNCTYPE
else:
    _LibBase = ctypes.CDLL
    _FUNCTION_TYPE = ctypes.CFUNCTYPE


class CLibrary(_LibBase):
    def __init__(self, library_or_path: Union[str, ctypes.CDLL]) -> None:
        self.func_name: Any

        if isinstance(library_or_path, str):
            super().__init__(library_or_path)
        else:
            super().__init__(library_or_path._name, library_or_path._handle)

    def map_symbol(
        self,
        func_name: str,
        restype: Any = None,
        argtypes: Tuple[Any, ...] = (),
        errcheck: Optional[Callable[..., Any]] = None,
    ) -> Any:
        """
        Map and return a symbol (function) from a C library. A reference to the
        mapped symbol is also held in the instance

        :param func_name:
            symbol_name
        :param ctypes.c_* restype:
            function result type (i.e. ctypes.c_ulong...), defaults to void
        :param tuple(ctypes.c_* ... ) argtypes:
            argument types, defaults to no args
        :param callable errcheck:
            optional error checking function, see ctypes docs for _FuncPtr
        """
        if argtypes:
            prototype = _FUNCTION_TYPE(restype, *argtypes)
        else:
            prototype = _FUNCTION_TYPE(restype)
        try:
            func = prototype((func_name, self))
        except AttributeError:
            raise ImportError(
                f'Could not map function "{func_name}" from library {self._name}'
            ) from None

        func._name = func_name  # type: ignore[attr-defined] # pylint: disable=protected-access
        log.debug(
            'Wrapped function "%s", result type: %s, error_check %s',
            func_name,
            type(restype),
            errcheck,
        )

        if errcheck is not None:
            func.errcheck = errcheck

        setattr(self, func_name, func)
        return func


if sys.platform == "win32":
    HRESULT = ctypes.HRESULT

elif sys.platform == "cygwin":

    class HRESULT(ctypes.c_long):
        pass


# Common win32 definitions
class HANDLE(ctypes.c_void_p):
    pass


PHANDLE = ctypes.POINTER(HANDLE)