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

class C_function:
       
"""This class wraps a Python function into its C equivalent in the given library"""

        types
= ctypes.__dict__

       
@classmethod
       
def register_type(cls, typename, obj):
               
"""Add an acceptable argument or retval type to this."""
                cls
.types[typename] = obj

       
def __init__(self, dll, error_check=None):
               
"""Set the library to reference the function name against."""
               
self.library = ctypes.CDLL(dll)
               
self.error_check = error_check
               
       
def __call__(self, f):
               
"""Performs the actual function wrapping.

                This extracts function details from annotations and signature.
                For example, to wrap puts, the following suffices (on Linux):

                        >>> @C_function("
libc.so.6")
                        ... def puts(my_string: "
c_char_p") -> "c_int":
                        ...     return puts.c_function(my_string)
                        ...
                        >>> x = puts("
hello, world!")
                        hello, world!
                        >>> x
                        14

                Note that to call the actual C function, you just reference
                it by asking for the local function's .c_function attribute.
                """


               
# get the function's name, arguments, and arg types
                name
= f.__name__
                args
= f.__code__.co_varnames
                annotations
= f.__annotations__

               
# get the function itself
               
function = self.library[name]

               
# set the function's call signature
                argtypes
= []
               
for arg in args:
                        annotation
= annotations[arg]
                       
if annotation.startswith("*"):
                                argtypes
.append(ctypes.POINTER(self.types[annotation[1:]]))
                       
else:
                                argtypes
.append(self.types[annotation])
               
function.argtypes = argtypes

               
# and its return value
                restype
= annotations['return']
               
if restype.startswith("*"):
                       
function.restype = ctypes.POINTER(self.types[restype[1:]])
               
else:
                       
function.restype = self.types[restype]

               
# set its error handler
               
if self.error_check:
                       
function.errcheck = self.error_check

               
# set the c_function as an attribute of f
                f
.c_function = function

               
return f

History

  • revision 6 (14 years ago)
  • previous revisions are not available