Welcome, guest | Sign In | My Account | Store | Cart

This class extends ctypes.CDLL with automatic checking of errno and automatically raises an exception when set by the function.

Python, 21 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import ctypes

class CDLL_errno(ctypes.CDLL):

    class _FuncPtr(ctypes._CFuncPtr):
        _flags_ = ctypes._FUNCFLAG_CDECL | ctypes._FUNCFLAG_USE_ERRNO
        _restype_ = ctypes.c_int

        def __call__(self, *args):
            ctypes.set_errno(0)
            try:
                return ctypes._CFuncPtr.__call__(self, *args)
            finally:
                errno = ctypes.get_errno()
                if errno:
                    import os
                    raise IOError(errno, os.strerror(errno))

    def __init__(self, *args, **kw):
        ctypes.CDLL.__init__(self, *args, **kw)
        del self._FuncPtr

The ctypes modules provides a useful feature for Windows users: if a DLL contains function that follow the calling convention of returning HRESULT you can use the WinDLL() class to load it. This installs a _check_retval_ checker for the function result and when is != S_OK it will automatically raise a WindowsError exception and automatically set the error code and description.

For POSIX there is no single standard value to indicate that errno should be checked. For some functions it is a null pointer. For others it is -1, etc. This means that a _check_retval_ checker cannot be used to implement such automatic exception handling.

This class works around this limitation by wrapping __call__ instead of using _check_retval_. Before the call errno is zeroed and if it is non-zero after the call an exception is raised.

1 comment

Oren Tirosh (author) 4 years, 11 months ago  # | flag

Why del self._FuncPtr :

The CDLL.__init__ sets a _FuncPtr as an instance member. Deleting it re-exposes the one in this class.