Is there a way to ensure that all my ctypes have argtypes?

I know what I have to specify argtypesfor my C / C ++ functions, as some of my calls would otherwise damage the stack.

    myCfunc.argtypes = [ct.c_void_p, ct.POINTER(ct.c_void_p)]
    myCfunc.errcheck = my_error_check

In fact, I would like to confirm that I did not forget to specify function prototypes ( argtypes/ errcheck) for any of my 100 function calls ...

Right now, I'm just browsing through Python files and visually comparing with my file containing prototype definitions.

Is there a better way to check that I have defined argtypes/ errcheckfor all my calls?

+4
source share
2 answers

by @eryksun dll , . DLL "" "_error_check" ( ), :

import ctypes as ct

class MyWinDll:
    def __init__(self, dll_filename):
        self._dll = ct.WinDLL(dll_filename)
        # Specify function prototypes using the annotate function
        self.annotate(self._dll.myCfunc, [ct.POINTER(ct.c_void_p)], self._error_check)
        self.annotate(self._dll.myCfunc2, [ct.c_void_p], self._error_check)
        ...

    def annotate(self, function, argtypes, errcheck):
        # note that "annotate" may not be used as a function name in the dll...
        function.argtypes = argtypes
        function.errcheck = errcheck
        setattr(self, function.__name__, function)

    def _error_check(self, result, func, arguments):
        if result != 0:
            raise Exception

if __name__ == '__main__':
    dll = MyWinDll('myWinDll.dll')
    handle = ct.c_void_p(None)
    # Now call the dll functions using the wrapper object
    dll.myCfunc(ct.byref(handle))
    dll.myCfunc2(handle)

: @eryksun , WinDLL :

import ctypes as ct

DEFAULT = object()

def annotate(dll_object, function_name, argtypes, restype=DEFAULT, errcheck=DEFAULT):
    function = getattr(dll_object._dll, function_name)
    function.argtypes = argtypes
    # restype and errcheck is optional in the function_prototypes list
    if restype is DEFAULT:
        restype = dll_object.default_restype
    function.restype = restype
    if errcheck is DEFAULT:
        errcheck = dll_object.default_errcheck
    function.errcheck = errcheck
    setattr(dll_object, function_name, function)


class MyDll:
    def __init__(self, ct_dll, **function_prototypes):
        self._dll = ct_dll
        for name, prototype in function_prototypes.items():
            annotate(self, name, *prototype)


class OneDll(MyDll):
    def __init__(self, ct_dll):
        # set default values for function_prototypes
        self.default_restype = ct.c_int
        self.default_errcheck = self._error_check
        function_prototypes = {
            'myCfunc': [[ct.POINTER(ct.c_void_p)]],
            'myCfunc2': [[ct.c_void_p]],
            # ...
            'myCgetErrTxt': [[ct.c_int, ct.c_char_p, ct.c_size_t], DEFAULT, None]
        }
        super().__init__(ct_dll, **function_prototypes)

    # My error check function actually calls the dll, so I keep it here...
    def _error_check(self, result, func, arguments):
        msg = ct.create_string_buffer(255)
        if result != 0:
            raise Exception(self.myCgetErrTxt(result, msg, ct.sizeof(msg)))


if __name__ == '__main__':
    ct_dll = ct.WinDLL('myWinDll.dll')
    dll = OneDll(ct_dll)
    handle = ct.c_void_p(None)
    dll.myCfunc(ct.byref(handle))
    dll.myCfunc2(handle)

( , , .)

+1

, DLL , :

class DummyFuncPtr(object):
    restype = False
    argtypes = False
    errcheck = False

    def __call__(self, *args, **kwargs):
        assert self.restype
        assert self.argtypes
        assert self.errcheck

    def __init__(self, *args):
        pass

    def __setattr__(self, key, value):
        super(DummyFuncPtr, self).__setattr__(key, True)

, DLL _FuncPtr, , :

dll = ctypes.cdll.LoadLibrary(r'path/to/dll')

# replace the DLL function pointer
# comment out this line to disable the dummy class
dll._FuncPtr = DummyFuncPtr

some_func = dll.someFunc
some_func.restype = None
some_func.argtypes = None
some_func.errcheck = None

another_func = dll.anotherFunc
another_func.restype = None
another_func.argtypes = None

some_func()     # no error
another_func()  # Assertion error due to errcheck not defined

- , , .

, , unit test -, .

0

Source: https://habr.com/ru/post/1685206/


All Articles