[pypy-svn] pypy default: Improved ctypes.CFUNCTYPE prototype and paramflags handling.

tav commits-noreply at bitbucket.org
Sat Mar 12 19:09:26 CET 2011


Author: tav <tav at espians.com>
Branch: 
Changeset: r42528:04456b424578
Date: 2011-03-12 18:09 +0000
http://bitbucket.org/pypy/pypy/changeset/04456b424578/

Log:	Improved ctypes.CFUNCTYPE prototype and paramflags handling.

diff --git a/lib-python/modified-2.7.0/ctypes/__init__.py b/lib-python/modified-2.7.0/ctypes/__init__.py
--- a/lib-python/modified-2.7.0/ctypes/__init__.py
+++ b/lib-python/modified-2.7.0/ctypes/__init__.py
@@ -355,11 +355,12 @@
             self._handle = handle
 
     def __repr__(self):
-        return "<%s '%s', handle %x at %x>" % \
+        return "<%s '%s', handle %r at %x>" % \
                (self.__class__.__name__, self._name,
-                (self._handle & (_sys.maxint*2 + 1)),
+                (self._handle),
                 id(self) & (_sys.maxint*2 + 1))
 
+
     def __getattr__(self, name):
         if name.startswith('__') and name.endswith('__'):
             raise AttributeError(name)

diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -110,53 +110,73 @@
         self.name = None
         self._objects = {keepalive_key(0):self}
         self._needs_free = True
-        argument = None
-        if len(args) == 1:
-            argument = args[0]
 
-        if isinstance(argument, (int, long)):
-            # direct construction from raw address
+        # Empty function object -- this is needed for casts
+        if not args:
+            self._buffer = _rawffi.Array('P')(1)
+            return
+
+        args = list(args)
+        argument = args.pop(0)
+
+        # Direct construction from raw address
+        if isinstance(argument, (int, long)) and not args:
             ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
-            self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires,
-                                        self._flags_)
+            self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires, self._flags_)
             self._buffer = self._ptr.byptr()
-        elif callable(argument):
-            # A callback into python
+            return
+
+        # A callback into python
+        if callable(argument) and not args:
             self.callable = argument
             ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
             if self._restype_ is None:
                 ffires = None
-            self._ptr = _rawffi.CallbackPtr(self._wrap_callable(argument,
-                                                                self.argtypes),
-                                            ffiargs, ffires, self._flags_)
+            self._ptr = _rawffi.CallbackPtr(self._wrap_callable(
+                argument, self.argtypes
+                ), ffiargs, ffires, self._flags_)
             self._buffer = self._ptr.byptr()
-        elif isinstance(argument, tuple) and len(argument) == 2:
-            # function exported from a shared library
+            return
+
+        # Function exported from a shared library
+        if isinstance(argument, tuple) and len(argument) == 2:
             import ctypes
-            self.name, self.dll = argument
-            if isinstance(self.dll, str):
-                self.dll = ctypes.CDLL(self.dll)
+            name, dll = argument
+            # XXX Implement support for foreign function ordinal
+            if not isinstance(name, basestring):
+                raise NotImplementedError(
+                    "Support for foreign functions exported by ordinal "
+                    "hasn't been implemented yet."
+                    )
+            self.name = name
+            if isinstance(dll, str):
+                self.dll = ctypes.CDLL(dll)
+            else:
+                self.dll = dll
+            if args:
+                self._paramflags = args.pop(0)
+                if args:
+                    raise TypeError("Unknown constructor %s" % (args,))
             # we need to check dll anyway
             ptr = self._getfuncptr([], ctypes.c_int)
             self._buffer = ptr.byptr()
+            return
 
-        elif (sys.platform == 'win32' and
-              len(args) >= 2 and isinstance(args[0], (int, long))):
-            # A COM function call, by index
+        # A COM function call, by index
+        if (sys.platform == 'win32' and isinstance(argument, (int, long))
+            and args):
             ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
-            self._com_index =  args[0] + 0x1000
-            self.name = args[1]
-            if len(args) > 2:
-                self._paramflags = args[2]
-            # XXX ignored iid = args[3]
+            self._com_index =  argument + 0x1000
+            self.name = args.pop(0)
+            if args:
+                self._paramflags = args.pop(0)
+                if args:
+                    raise TypeError("Unknown constructor %s" % (args,))
+            # XXX Implement support for the optional ``iid`` pointer to the
+            # interface identifier used in extended error reporting.
+            return
 
-        elif len(args) == 0:
-            # Empty function object.
-            # this is needed for casts
-            self._buffer = _rawffi.Array('P')(1)
-            return
-        else:
-            raise TypeError("Unknown constructor %s" % (args,))
+        raise TypeError("Unknown constructor %s" % (args,))
 
     def _wrap_callable(self, to_call, argtypes):
         def f(*args):
@@ -166,7 +186,7 @@
             return to_call(*args)
         return f
     
-    def __call__(self, *args):
+    def __call__(self, *args, **kwargs):
         if self.callable is not None:
             if len(args) == len(self._argtypes_):
                 pass
@@ -214,7 +234,7 @@
             
         if argtypes is None:
             argtypes = []
-        args = self._convert_args(argtypes, args)
+        args, output_values = self._convert_args(argtypes, args, kwargs)
         argtypes = [type(arg) for arg in args]
         
         restype = self._restype_
@@ -244,6 +264,11 @@
             if v is not args:
                 result = v
 
+        if output_values:
+            if len(output_values) == 1:
+                return output_values[0]
+            return tuple(output_values)
+
         return result
 
 
@@ -289,7 +314,7 @@
             raise
 
     @staticmethod
-    def _conv_param(argtype, arg, index):
+    def _conv_param(argtype, arg):
         from ctypes import c_char_p, c_wchar_p, c_void_p, c_int
         if argtype is not None:
             arg = argtype.from_param(arg)
@@ -312,20 +337,24 @@
 
         return cobj
 
-    def _convert_args(self, argtypes, args):
+    def _convert_args(self, argtypes, args, kwargs):
         wrapped_args = []
+        output_values = []
         consumed = 0
 
+        # XXX Implement support for kwargs/name
         for i, argtype in enumerate(argtypes):
             defaultvalue = None
-            if i > 0 and self._paramflags is not None:
-                paramflag = self._paramflags[i-1]
-                if len(paramflag) == 2:
+            if self._paramflags is not None:
+                paramflag = self._paramflags[i]
+                paramlen = len(paramflag)
+                name = None
+                if paramlen == 1:
+                    idlflag = paramflag[0]
+                elif paramlen == 2:
                     idlflag, name = paramflag
-                elif len(paramflag) == 3:
+                elif paramlen == 3:
                     idlflag, name, defaultvalue = paramflag
-                else:
-                    idlflag = 0
                 idlflag &= (PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID)
 
                 if idlflag in (0, PARAMFLAG_FIN):
@@ -333,8 +362,8 @@
                 elif idlflag == PARAMFLAG_FOUT:
                     import ctypes
                     val = argtype._type_()
-                    wrapped = (val, ctypes.byref(val))
-                    wrapped_args.append(wrapped)
+                    output_values.append(val)
+                    wrapped_args.append(ctypes.byref(val))
                     continue
                 elif idlflag == PARAMFLAG_FIN | PARAMFLAG_FLCID:
                     # Always taken from defaultvalue if given,
@@ -342,12 +371,12 @@
                     val = defaultvalue
                     if val is None:
                         val = 0
-                    wrapped = self._conv_param(argtype, val, consumed)
+                    wrapped = self._conv_param(argtype, val)
                     wrapped_args.append(wrapped)
                     continue
                 else:
                     raise NotImplementedError(
-                        "paramflags = %s" % (self._paramflags[i-1],))
+                        "paramflags = %s" % (self._paramflags[i],))
 
             if consumed < len(args):
                 arg = args[consumed]
@@ -357,7 +386,7 @@
                 raise TypeError("Not enough arguments")
 
             try:
-                wrapped = self._conv_param(argtype, arg, consumed)
+                wrapped = self._conv_param(argtype, arg)
             except (UnicodeError, TypeError, ValueError), e:
                 raise ArgumentError(str(e))
             wrapped_args.append(wrapped)
@@ -368,11 +397,11 @@
             argtypes = list(argtypes)
             for i, arg in enumerate(extra):
                 try:
-                    wrapped = self._conv_param(None, arg, i)
+                    wrapped = self._conv_param(None, arg)
                 except (UnicodeError, TypeError, ValueError), e:
                     raise ArgumentError(str(e))
                 wrapped_args.append(wrapped)
-        return wrapped_args
+        return wrapped_args, output_values
 
     def _build_result(self, restype, resbuffer, argtypes, argsandobjs):
         """Build the function result:


More information about the Pypy-commit mailing list