summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2016-09-03 19:29:47 +0200
committerArmin Rigo <arigo@tunes.org>2016-09-03 19:29:47 +0200
commit3b4972b89c6f5efc62d90e2d5969c280e2bdd613 (patch)
treeea6d513a2baf87bd812ef9678cb831add13e7a60
parentbc99d488c73e2cfc4907088ddf4bf055821864e5 (diff)
downloadcffi-3b4972b89c6f5efc62d90e2d5969c280e2bdd613.tar.gz
Backed out changeset 0087e2aec9ef
Un-kill the ctypes backend. Issue #282 for a justification.
-rw-r--r--cffi/api.py30
-rw-r--r--cffi/backend_ctypes.py1097
-rw-r--r--testing/cffi0/backend_tests.py (renamed from testing/cffi0/test_backend.py)274
-rw-r--r--testing/cffi0/test_cdata.py39
-rw-r--r--testing/cffi0/test_ctypes.py40
-rw-r--r--testing/cffi0/test_ffi_backend.py25
-rw-r--r--testing/cffi0/test_function.py93
-rw-r--r--testing/cffi0/test_ownlib.py22
-rw-r--r--testing/cffi0/test_verify.py9
9 files changed, 1431 insertions, 198 deletions
diff --git a/cffi/api.py b/cffi/api.py
index 6d1eb48..eda7209 100644
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -46,21 +46,20 @@ class FFI(object):
'''
def __init__(self, backend=None):
- """Create an FFI instance.
-
- The 'backend' argument is not used any more and must be set to None.
- It is still present only so that 'FFI(None)' still works, and
- for a few tests.
+ """Create an FFI instance. The 'backend' argument is used to
+ select a non-default backend, mostly for tests.
"""
from . import cparser, model
-
if backend is None:
- # You need the corresponding version of PyPy, or CPython
- # with the '_cffi_backend' C extension module compiled.
+ # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with
+ # _cffi_backend.so compiled.
import _cffi_backend as backend
from . import __version__
assert backend.__version__ == __version__, \
"version mismatch, %s != %s" % (backend.__version__, __version__)
+ # (If you insist you can also try to pass the option
+ # 'backend=backend_ctypes.CTypesBackend()', but don't
+ # rely on it! It's probably not going to work well.)
self._backend = backend
self._lock = allocate_lock()
@@ -76,6 +75,8 @@ class FFI(object):
self._init_once_cache = {}
self._cdef_version = None
self._embedding = None
+ if hasattr(backend, 'set_ffi'):
+ backend.set_ffi(self)
for name in backend.__dict__:
if name.startswith('RTLD_'):
setattr(self, name, getattr(backend, name))
@@ -83,10 +84,15 @@ class FFI(object):
with self._lock:
self.BVoidP = self._get_cached_btype(model.voidp_type)
self.BCharA = self._get_cached_btype(model.char_array_type)
- # attach these constants to the class
- if not hasattr(FFI, 'NULL'):
- FFI.NULL = self.cast(self.BVoidP, 0)
- FFI.CData, FFI.CType = backend._get_types()
+ if isinstance(backend, types.ModuleType):
+ # _cffi_backend: attach these constants to the class
+ if not hasattr(FFI, 'NULL'):
+ FFI.NULL = self.cast(self.BVoidP, 0)
+ FFI.CData, FFI.CType = backend._get_types()
+ else:
+ # ctypes backend: attach these constants to the instance
+ self.NULL = self.cast(self.BVoidP, 0)
+ self.CData, self.CType = backend._get_types()
def cdef(self, csource, override=False, packed=False):
"""Parse the given C source. This registers all declared functions,
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
new file mode 100644
index 0000000..b2579b3
--- /dev/null
+++ b/cffi/backend_ctypes.py
@@ -0,0 +1,1097 @@
+import ctypes, ctypes.util, operator, sys
+from . import model
+
+if sys.version_info < (3,):
+ bytechr = chr
+else:
+ unicode = str
+ long = int
+ xrange = range
+ bytechr = lambda num: bytes([num])
+
+class CTypesType(type):
+ pass
+
+class CTypesData(object):
+ __metaclass__ = CTypesType
+ __slots__ = ['__weakref__']
+ __name__ = '<cdata>'
+
+ def __init__(self, *args):
+ raise TypeError("cannot instantiate %r" % (self.__class__,))
+
+ @classmethod
+ def _newp(cls, init):
+ raise TypeError("expected a pointer or array ctype, got '%s'"
+ % (cls._get_c_name(),))
+
+ @staticmethod
+ def _to_ctypes(value):
+ raise TypeError
+
+ @classmethod
+ def _arg_to_ctypes(cls, *value):
+ try:
+ ctype = cls._ctype
+ except AttributeError:
+ raise TypeError("cannot create an instance of %r" % (cls,))
+ if value:
+ res = cls._to_ctypes(*value)
+ if not isinstance(res, ctype):
+ res = cls._ctype(res)
+ else:
+ res = cls._ctype()
+ return res
+
+ @classmethod
+ def _create_ctype_obj(cls, init):
+ if init is None:
+ return cls._arg_to_ctypes()
+ else:
+ return cls._arg_to_ctypes(init)
+
+ @staticmethod
+ def _from_ctypes(ctypes_value):
+ raise TypeError
+
+ @classmethod
+ def _get_c_name(cls, replace_with=''):
+ return cls._reftypename.replace(' &', replace_with)
+
+ @classmethod
+ def _fix_class(cls):
+ cls.__name__ = 'CData<%s>' % (cls._get_c_name(),)
+ cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),)
+ cls.__module__ = 'ffi'
+
+ def _get_own_repr(self):
+ raise NotImplementedError
+
+ def _addr_repr(self, address):
+ if address == 0:
+ return 'NULL'
+ else:
+ if address < 0:
+ address += 1 << (8*ctypes.sizeof(ctypes.c_void_p))
+ return '0x%x' % address
+
+ def __repr__(self, c_name=None):
+ own = self._get_own_repr()
+ return '<cdata %r %s>' % (c_name or self._get_c_name(), own)
+
+ def _convert_to_address(self, BClass):
+ if BClass is None:
+ raise TypeError("cannot convert %r to an address" % (
+ self._get_c_name(),))
+ else:
+ raise TypeError("cannot convert %r to %r" % (
+ self._get_c_name(), BClass._get_c_name()))
+
+ @classmethod
+ def _get_size(cls):
+ return ctypes.sizeof(cls._ctype)
+
+ def _get_size_of_instance(self):
+ return ctypes.sizeof(self._ctype)
+
+ @classmethod
+ def _cast_from(cls, source):
+ raise TypeError("cannot cast to %r" % (cls._get_c_name(),))
+
+ def _cast_to_integer(self):
+ return self._convert_to_address(None)
+
+ @classmethod
+ def _alignment(cls):
+ return ctypes.alignment(cls._ctype)
+
+ def __iter__(self):
+ raise TypeError("cdata %r does not support iteration" % (
+ self._get_c_name()),)
+
+ def _make_cmp(name):
+ cmpfunc = getattr(operator, name)
+ def cmp(self, other):
+ if isinstance(other, CTypesData):
+ return cmpfunc(self._convert_to_address(None),
+ other._convert_to_address(None))
+ else:
+ return NotImplemented
+ cmp.func_name = name
+ return cmp
+
+ __eq__ = _make_cmp('__eq__')
+ __ne__ = _make_cmp('__ne__')
+ __lt__ = _make_cmp('__lt__')
+ __le__ = _make_cmp('__le__')
+ __gt__ = _make_cmp('__gt__')
+ __ge__ = _make_cmp('__ge__')
+
+ def __hash__(self):
+ return hash(type(self)) ^ hash(self._convert_to_address(None))
+
+ def _to_string(self, maxlen):
+ raise TypeError("string(): %r" % (self,))
+
+
+class CTypesGenericPrimitive(CTypesData):
+ __slots__ = []
+
+ def __eq__(self, other):
+ return self is other
+
+ def __ne__(self, other):
+ return self is not other
+
+ def __hash__(self):
+ return object.__hash__(self)
+
+ def _get_own_repr(self):
+ return repr(self._from_ctypes(self._value))
+
+
+class CTypesGenericArray(CTypesData):
+ __slots__ = []
+
+ @classmethod
+ def _newp(cls, init):
+ return cls(init)
+
+ def __iter__(self):
+ for i in xrange(len(self)):
+ yield self[i]
+
+ def _get_own_repr(self):
+ return self._addr_repr(ctypes.addressof(self._blob))
+
+
+class CTypesGenericPtr(CTypesData):
+ __slots__ = ['_address', '_as_ctype_ptr']
+ _automatic_casts = False
+ kind = "pointer"
+
+ @classmethod
+ def _newp(cls, init):
+ return cls(init)
+
+ @classmethod
+ def _cast_from(cls, source):
+ if source is None:
+ address = 0
+ elif isinstance(source, CTypesData):
+ address = source._cast_to_integer()
+ elif isinstance(source, (int, long)):
+ address = source
+ else:
+ raise TypeError("bad type for cast to %r: %r" %
+ (cls, type(source).__name__))
+ return cls._new_pointer_at(address)
+
+ @classmethod
+ def _new_pointer_at(cls, address):
+ self = cls.__new__(cls)
+ self._address = address
+ self._as_ctype_ptr = ctypes.cast(address, cls._ctype)
+ return self
+
+ def _get_own_repr(self):
+ try:
+ return self._addr_repr(self._address)
+ except AttributeError:
+ return '???'
+
+ def _cast_to_integer(self):
+ return self._address
+
+ def __nonzero__(self):
+ return bool(self._address)
+ __bool__ = __nonzero__
+
+ @classmethod
+ def _to_ctypes(cls, value):
+ if not isinstance(value, CTypesData):
+ raise TypeError("unexpected %s object" % type(value).__name__)
+ address = value._convert_to_address(cls)
+ return ctypes.cast(address, cls._ctype)
+
+ @classmethod
+ def _from_ctypes(cls, ctypes_ptr):
+ address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0
+ return cls._new_pointer_at(address)
+
+ @classmethod
+ def _initialize(cls, ctypes_ptr, value):
+ if value:
+ ctypes_ptr.contents = cls._to_ctypes(value).contents
+
+ def _convert_to_address(self, BClass):
+ if (BClass in (self.__class__, None) or BClass._automatic_casts
+ or self._automatic_casts):
+ return self._address
+ else:
+ return CTypesData._convert_to_address(self, BClass)
+
+
+class CTypesBaseStructOrUnion(CTypesData):
+ __slots__ = ['_blob']
+
+ @classmethod
+ def _create_ctype_obj(cls, init):
+ # may be overridden
+ raise TypeError("cannot instantiate opaque type %s" % (cls,))
+
+ def _get_own_repr(self):
+ return self._addr_repr(ctypes.addressof(self._blob))
+
+ @classmethod
+ def _offsetof(cls, fieldname):
+ return getattr(cls._ctype, fieldname).offset
+
+ def _convert_to_address(self, BClass):
+ if getattr(BClass, '_BItem', None) is self.__class__:
+ return ctypes.addressof(self._blob)
+ else:
+ return CTypesData._convert_to_address(self, BClass)
+
+ @classmethod
+ def _from_ctypes(cls, ctypes_struct_or_union):
+ self = cls.__new__(cls)
+ self._blob = ctypes_struct_or_union
+ return self
+
+ @classmethod
+ def _to_ctypes(cls, value):
+ return value._blob
+
+ def __repr__(self, c_name=None):
+ return CTypesData.__repr__(self, c_name or self._get_c_name(' &'))
+
+
+class CTypesBackend(object):
+
+ PRIMITIVE_TYPES = {
+ 'char': ctypes.c_char,
+ 'short': ctypes.c_short,
+ 'int': ctypes.c_int,
+ 'long': ctypes.c_long,
+ 'long long': ctypes.c_longlong,
+ 'signed char': ctypes.c_byte,
+ 'unsigned char': ctypes.c_ubyte,
+ 'unsigned short': ctypes.c_ushort,
+ 'unsigned int': ctypes.c_uint,
+ 'unsigned long': ctypes.c_ulong,
+ 'unsigned long long': ctypes.c_ulonglong,
+ 'float': ctypes.c_float,
+ 'double': ctypes.c_double,
+ '_Bool': ctypes.c_bool,
+ }
+
+ for _name in ['unsigned long long', 'unsigned long',
+ 'unsigned int', 'unsigned short', 'unsigned char']:
+ _size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
+ PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
+ if _size == ctypes.sizeof(ctypes.c_void_p):
+ PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name]
+ if _size == ctypes.sizeof(ctypes.c_size_t):
+ PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name]
+
+ for _name in ['long long', 'long', 'int', 'short', 'signed char']:
+ _size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
+ PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
+ if _size == ctypes.sizeof(ctypes.c_void_p):
+ PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name]
+ PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name]
+ if _size == ctypes.sizeof(ctypes.c_size_t):
+ PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name]
+
+
+ def __init__(self):
+ self.RTLD_LAZY = 0 # not supported anyway by ctypes
+ self.RTLD_NOW = 0
+ self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL
+ self.RTLD_LOCAL = ctypes.RTLD_LOCAL
+
+ def set_ffi(self, ffi):
+ self.ffi = ffi
+
+ def _get_types(self):
+ return CTypesData, CTypesType
+
+ def load_library(self, path, flags=0):
+ cdll = ctypes.CDLL(path, flags)
+ return CTypesLibrary(self, cdll)
+
+ def new_void_type(self):
+ class CTypesVoid(CTypesData):
+ __slots__ = []
+ _reftypename = 'void &'
+ @staticmethod
+ def _from_ctypes(novalue):
+ return None
+ @staticmethod
+ def _to_ctypes(novalue):
+ if novalue is not None:
+ raise TypeError("None expected, got %s object" %
+ (type(novalue).__name__,))
+ return None
+ CTypesVoid._fix_class()
+ return CTypesVoid
+
+ def new_primitive_type(self, name):
+ if name == 'wchar_t':
+ raise NotImplementedError(name)
+ ctype = self.PRIMITIVE_TYPES[name]
+ if name == 'char':
+ kind = 'char'
+ elif name in ('float', 'double'):
+ kind = 'float'
+ else:
+ if name in ('signed char', 'unsigned char'):
+ kind = 'byte'
+ elif name == '_Bool':
+ kind = 'bool'
+ else:
+ kind = 'int'
+ is_signed = (ctype(-1).value == -1)
+ #
+ def _cast_source_to_int(source):
+ if isinstance(source, (int, long, float)):
+ source = int(source)
+ elif isinstance(source, CTypesData):
+ source = source._cast_to_integer()
+ elif isinstance(source, bytes):
+ source = ord(source)
+ elif source is None:
+ source = 0
+ else:
+ raise TypeError("bad type for cast to %r: %r" %
+ (CTypesPrimitive, type(source).__name__))
+ return source
+ #
+ kind1 = kind
+ class CTypesPrimitive(CTypesGenericPrimitive):
+ __slots__ = ['_value']
+ _ctype = ctype
+ _reftypename = '%s &' % name
+ kind = kind1
+
+ def __init__(self, value):
+ self._value = value
+
+ @staticmethod
+ def _create_ctype_obj(init):
+ if init is None:
+ return ctype()
+ return ctype(CTypesPrimitive._to_ctypes(init))
+
+ if kind == 'int' or kind == 'byte':
+ @classmethod
+ def _cast_from(cls, source):
+ source = _cast_source_to_int(source)
+ source = ctype(source).value # cast within range
+ return cls(source)
+ def __int__(self):
+ return self._value
+
+ if kind == 'bool':
+ @classmethod
+ def _cast_from(cls, source):
+ if not isinstance(source, (int, long, float)):
+ source = _cast_source_to_int(source)
+ return cls(bool(source))
+ def __int__(self):
+ return self._value
+
+ if kind == 'char':
+ @classmethod
+ def _cast_from(cls, source):
+ source = _cast_source_to_int(source)
+ source = bytechr(source & 0xFF)
+ return cls(source)
+ def __int__(self):
+ return ord(self._value)
+
+ if kind == 'float':
+ @classmethod
+ def _cast_from(cls, source):
+ if isinstance(source, float):
+ pass
+ elif isinstance(source, CTypesGenericPrimitive):
+ if hasattr(source, '__float__'):
+ source = float(source)
+ else:
+ source = int(source)
+ else:
+ source = _cast_source_to_int(source)
+ source = ctype(source).value # fix precision
+ return cls(source)
+ def __int__(self):
+ return int(self._value)
+ def __float__(self):
+ return self._value
+
+ _cast_to_integer = __int__
+
+ if kind == 'int' or kind == 'byte' or kind == 'bool':
+ @staticmethod
+ def _to_ctypes(x):
+ if not isinstance(x, (int, long)):
+ if isinstance(x, CTypesData):
+ x = int(x)
+ else:
+ raise TypeError("integer expected, got %s" %
+ type(x).__name__)
+ if ctype(x).value != x:
+ if not is_signed and x < 0:
+ raise OverflowError("%s: negative integer" % name)
+ else:
+ raise OverflowError("%s: integer out of bounds"
+ % name)
+ return x
+
+ if kind == 'char':
+ @staticmethod
+ def _to_ctypes(x):
+ if isinstance(x, bytes) and len(x) == 1:
+ return x
+ if isinstance(x, CTypesPrimitive): # <CData <char>>
+ return x._value
+ raise TypeError("character expected, got %s" %
+ type(x).__name__)
+ def __nonzero__(self):
+ return ord(self._value) != 0
+ else:
+ def __nonzero__(self):
+ return self._value != 0
+ __bool__ = __nonzero__
+
+ if kind == 'float':
+ @staticmethod
+ def _to_ctypes(x):
+ if not isinstance(x, (int, long, float, CTypesData)):
+ raise TypeError("float expected, got %s" %
+ type(x).__name__)
+ return ctype(x).value
+
+ @staticmethod
+ def _from_ctypes(value):
+ return getattr(value, 'value', value)
+
+ @staticmethod
+ def _initialize(blob, init):
+ blob.value = CTypesPrimitive._to_ctypes(init)
+
+ if kind == 'char':
+ def _to_string(self, maxlen):
+ return self._value
+ if kind == 'byte':
+ def _to_string(self, maxlen):
+ return chr(self._value & 0xff)
+ #
+ CTypesPrimitive._fix_class()
+ return CTypesPrimitive
+
+ def new_pointer_type(self, BItem):
+ getbtype = self.ffi._get_cached_btype
+ if BItem is getbtype(model.PrimitiveType('char')):
+ kind = 'charp'
+ elif BItem in (getbtype(model.PrimitiveType('signed char')),
+ getbtype(model.PrimitiveType('unsigned char'))):
+ kind = 'bytep'
+ elif BItem is getbtype(model.void_type):
+ kind = 'voidp'
+ else:
+ kind = 'generic'
+ #
+ class CTypesPtr(CTypesGenericPtr):
+ __slots__ = ['_own']
+ if kind == 'charp':
+ __slots__ += ['__as_strbuf']
+ _BItem = BItem
+ if hasattr(BItem, '_ctype'):
+ _ctype = ctypes.POINTER(BItem._ctype)
+ _bitem_size = ctypes.sizeof(BItem._ctype)
+ else:
+ _ctype = ctypes.c_void_p
+ if issubclass(BItem, CTypesGenericArray):
+ _reftypename = BItem._get_c_name('(* &)')
+ else:
+ _reftypename = BItem._get_c_name(' * &')
+
+ def __init__(self, init):
+ ctypeobj = BItem._create_ctype_obj(init)
+ if kind == 'charp':
+ self.__as_strbuf = ctypes.create_string_buffer(
+ ctypeobj.value + b'\x00')
+ self._as_ctype_ptr = ctypes.cast(
+ self.__as_strbuf, self._ctype)
+ else:
+ self._as_ctype_ptr = ctypes.pointer(ctypeobj)
+ self._address = ctypes.cast(self._as_ctype_ptr,
+ ctypes.c_void_p).value
+ self._own = True
+
+ def __add__(self, other):
+ if isinstance(other, (int, long)):
+ return self._new_pointer_at(self._address +
+ other * self._bitem_size)
+ else:
+ return NotImplemented
+
+ def __sub__(self, other):
+ if isinstance(other, (int, long)):
+ return self._new_pointer_at(self._address -
+ other * self._bitem_size)
+ elif type(self) is type(other):
+ return (self._address - other._address) // self._bitem_size
+ else:
+ return NotImplemented
+
+ def __getitem__(self, index):
+ if getattr(self, '_own', False) and index != 0:
+ raise IndexError
+ return BItem._from_ctypes(self._as_ctype_ptr[index])
+
+ def __setitem__(self, index, value):
+ self._as_ctype_ptr[index] = BItem._to_ctypes(value)
+
+ if kind == 'charp' or kind == 'voidp':
+ @classmethod
+ def _arg_to_ctypes(cls, *value):
+ if value and isinstance(value[0], bytes):
+ return ctypes.c_char_p(value[0])
+ else:
+ return super(CTypesPtr, cls)._arg_to_ctypes(*value)
+
+ if kind == 'charp' or kind == 'bytep':
+ def _to_string(self, maxlen):
+ if maxlen < 0:
+ maxlen = sys.maxsize
+ p = ctypes.cast(self._as_ctype_ptr,
+ ctypes.POINTER(ctypes.c_char))
+ n = 0
+ while n < maxlen and p[n] != b'\x00':
+ n += 1
+ return b''.join([p[i] for i in range(n)])
+
+ def _get_own_repr(self):
+ if getattr(self, '_own', False):
+ return 'owning %d bytes' % (
+ ctypes.sizeof(self._as_ctype_ptr.contents),)
+ return super(CTypesPtr, self)._get_own_repr()
+ #
+ if (BItem is self.ffi._get_cached_btype(model.void_type) or
+ BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))):
+ CTypesPtr._automatic_casts = True
+ #
+ CTypesPtr._fix_class()
+ return CTypesPtr
+
+ def new_array_type(self, CTypesPtr, length):
+ if length is None:
+ brackets = ' &[]'
+ else:
+ brackets = ' &[%d]' % length
+ BItem = CTypesPtr._BItem
+ getbtype = self.ffi._get_cached_btype
+ if BItem is getbtype(model.PrimitiveType('char')):
+ kind = 'char'
+ elif BItem in (getbtype(model.PrimitiveType('signed char')),
+ getbtype(model.PrimitiveType('unsigned char'))):
+ kind = 'byte'
+ else:
+ kind = 'generic'
+ #
+ class CTypesArray(CTypesGenericArray):
+ __slots__ = ['_blob', '_own']
+ if length is not None:
+ _ctype = BItem._ctype * length
+ else:
+ __slots__.append('_ctype')
+ _reftypename = BItem._get_c_name(brackets)
+ _declared_length = length
+ _CTPtr = CTypesPtr
+
+ def __init__(self, init):
+ if length is None:
+ if isinstance(init, (int, long)):
+ len1 = init
+ init = None
+ elif kind == 'char' and isinstance(init, bytes):
+ len1 = len(init) + 1 # extra null
+ else:
+ init = tuple(init)
+ len1 = len(init)
+ self._ctype = BItem._ctype * len1
+ self._blob = self._ctype()
+ self._own = True
+ if init is not None:
+ self._initialize(self._blob, init)
+
+ @staticmethod
+ def _initialize(blob, init):
+ if isinstance(init, bytes):
+ init = [init[i:i+1] for i in range(len(init))]
+ else:
+ init = tuple(init)
+ if len(init) > len(blob):
+ raise IndexError("too many initializers")
+ addr = ctypes.cast(blob, ctypes.c_void_p).value
+ PTR = ctypes.POINTER(BItem._ctype)
+ itemsize = ctypes.sizeof(BItem._ctype)
+ for i, value in enumerate(init):
+ p = ctypes.cast(addr + i * itemsize, PTR)
+ BItem._initialize(p.contents, value)
+
+ def __len__(self):
+ return len(self._blob)
+
+ def __getitem__(self, index):
+ if not (0 <= index < len(self._blob)):
+ raise IndexError
+ return BItem._from_ctypes(self._blob[index])
+
+ def __setitem__(self, index, value):
+ if not (0 <= index < len(self._blob)):
+ raise IndexError
+ self._blob[index] = BItem._to_ctypes(value)
+
+ if kind == 'char' or kind == 'byte':
+ def _to_string(self, maxlen):
+ if maxlen < 0:
+ maxlen = len(self._blob)
+ p = ctypes.cast(self._blob,
+ ctypes.POINTER(ctypes.c_char))
+ n = 0
+ while n < maxlen and p[n] != b'\x00':
+ n += 1
+ return b''.join([p[i] for i in range(n)])
+
+ def _get_own_repr(self):
+ if getattr(self, '_own', False):
+ return 'owning %d bytes' % (ctypes.sizeof(self._blob),)
+ return super(CTypesArray, self)._get_own_repr()
+
+ def _convert_to_address(self, BClass):
+ if BClass in (CTypesPtr, None) or BClass._automatic_casts:
+ return ctypes.addressof(self._blob)
+ else:
+ return CTypesData._convert_to_address(self, BClass)
+
+ @staticmethod
+ def _from_ctypes(ctypes_array):
+ self = CTypesArray.__new__(CTypesArray)
+ self._blob = ctypes_array
+ return self
+
+ @staticmethod
+ def _arg_to_ctypes(value):
+ return CTypesPtr._arg_to_ctypes(value)
+
+ def __add__(self, other):
+ if isinstance(other, (int, long)):
+ return CTypesPtr._new_pointer_at(
+ ctypes.addressof(self._blob) +
+ other * ctypes.sizeof(BItem._ctype))
+ else:
+ return NotImplemented
+
+ @classmethod
+ def _cast_from(cls, source):
+ raise NotImplementedError("casting to %r" % (
+ cls._get_c_name(),))
+ #
+ CTypesArray._fix_class()
+ return CTypesArray
+
+ def _new_struct_or_union(self, kind, name, base_ctypes_class):
+ #
+ class struct_or_union(base_ctypes_class):
+ pass
+ struct_or_union.__name__ = '%s_%s' % (kind, name)
+ kind1 = kind
+ #
+ class CTypesStructOrUnion(CTypesBaseStructOrUnion):
+ __slots__ = ['_blob']
+ _ctype = struct_or_union
+ _reftypename = '%s &' % (name,)
+ _kind = kind = kind1
+ #
+ CTypesStructOrUnion._fix_class()
+ return CTypesStructOrUnion
+
+ def new_struct_type(self, name):
+ return self._new_struct_or_union('struct', name, ctypes.Structure)
+
+ def new_union_type(self, name):
+ return self._new_struct_or_union('union', name, ctypes.Union)
+
+ def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp,
+ totalsize=-1, totalalignment=-1, sflags=0):
+ if totalsize >= 0 or totalalignment >= 0:
+ raise NotImplementedError("the ctypes backend of CFFI does not support "
+ "structures completed by verify(); please "
+ "compile and install the _cffi_backend module.")
+ struct_or_union = CTypesStructOrUnion._ctype
+ fnames = [fname for (fname, BField, bitsize) in fields]
+ btypes = [BField for (fname, BField, bitsize) in fields]
+ bitfields = [bitsize for (fname, BField, bitsize) in fields]
+ #
+ bfield_types = {}
+ cfields = []
+ for (fname, BField, bitsize) in fields:
+ if bitsize < 0:
+ cfields.append((fname, BField._ctype))
+ bfield_types[fname] = BField
+ else:
+ cfields.append((fname, BField._ctype, bitsize))
+ bfield_types[fname] = Ellipsis
+ if sflags & 8:
+ struct_or_union._pack_ = 1
+ struct_or_union._fields_ = cfields
+ CTypesStructOrUnion._bfield_types = bfield_types
+ #
+ @staticmethod
+ def _create_ctype_obj(init):
+ result = struct_or_union()
+ if init is not None:
+ initialize(result, init)
+ return result
+ CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj
+ #
+ def initialize(blob, init):
+ if is_union:
+ if len(init) > 1:
+ raise ValueError("union initializer: %d items given, but "
+ "only one supported (use a dict if needed)"
+ % (len(init),))
+ if not isinstance(init, dict):
+ if isinstance(init, (bytes, unicode)):
+ raise TypeError("union initializer: got a str")
+ init = tuple(init)
+ if len(init) > len(fnames):
+ raise ValueError("too many values for %s initializer" %
+ CTypesStructOrUnion._get_c_name())
+ init = dict(zip(fnames, init))
+ addr = ctypes.addressof(blob)
+ for fname, value in init.items():
+ BField, bitsize = name2fieldtype[fname]
+ assert bitsize < 0, \
+ "not implemented: initializer with bit fields"
+ offset = CTypesStructOrUnion._offsetof(fname)
+ PTR = ctypes.POINTER(BField._ctype)
+ p = ctypes.cast(addr + offset, PTR)
+ BField._initialize(p.contents, value)
+ is_union = CTypesStructOrUnion._kind == 'union'
+ name2fieldtype = dict(zip(fnames, zip(btypes, bitfields)))
+ #
+ for fname, BField, bitsize in fields:
+ if fname == '':
+ raise NotImplementedError("nested anonymous structs/unions")
+ if hasattr(CTypesStructOrUnion, fname):
+ raise ValueError("the field name %r conflicts in "
+ "the ctypes backend" % fname)
+ if bitsize < 0:
+ def getter(self, fname=fname, BField=BField,
+ offset=CTypesStructOrUnion._offsetof(fname),
+ PTR=ctypes.POINTER(BField._ctype)):
+ addr = ctypes.addressof(self._blob)
+ p = ctypes.cast(addr + offset, PTR)
+ return BField._from_ctypes(p.contents)
+ def setter(self, value, fname=fname, BField=BField):
+ setattr(self._blob, fname, BField._to_ctypes(value))
+ #
+ if issubclass(BField, CTypesGenericArray):
+ setter = None
+ if BField._declared_length == 0:
+ def getter(self, fname=fname, BFieldPtr=BField._CTPtr,
+ offset=CTypesStructOrUnion._offsetof(fname),
+ PTR=ctypes.POINTER(BField._ctype)):
+ addr = ctypes.addressof(self._blob)
+ p = ctypes.cast(addr + offset, PTR)
+ return BFieldPtr._from_ctypes(p)
+ #
+ else:
+ def getter(self, fname=fname, BField=BField):
+ return BField._from_ctypes(getattr(self._blob, fname))
+ def setter(self, value, fname=fname, BField=BField):
+ # xxx obscure workaround
+ value = BField._to_ctypes(value)
+ oldvalue = getattr(self._blob, fname)
+ setattr(self._blob, fname, value)
+ if value != getattr(self._blob, fname):
+ setattr(self._blob, fname, oldvalue)
+ raise OverflowError("value too large for bitfield")
+ setattr(CTypesStructOrUnion, fname, property(getter, setter))
+ #
+ CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp))
+ for fname in fnames:
+ if hasattr(CTypesPtr, fname):
+ raise ValueError("the field name %r conflicts in "
+ "the ctypes backend" % fname)
+ def getter(self, fname=fname):
+ return getattr(self[0], fname)
+ def setter(self, value, fname=fname):
+ setattr(self[0], fname, value)
+ setattr(CTypesPtr, fname, property(getter, setter))
+
+ def new_function_type(self, BArgs, BResult, has_varargs):
+ nameargs = [BArg._get_c_name() for BArg in BArgs]
+ if has_varargs:
+ nameargs.append('...')
+ nameargs = ', '.join(nameargs)
+ #
+ class CTypesFunctionPtr(CTypesGenericPtr):
+ __slots__ = ['_own_callback', '_name']
+ _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None),
+ *[BArg._ctype for BArg in BArgs],
+ use_errno=True)
+ _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,))
+
+ def __init__(self, init, error=None):
+ # create a callback to the Python callable init()
+ import traceback
+ assert not has_varargs, "varargs not supported for callbacks"
+ if getattr(BResult, '_ctype', None) is not None:
+ error = BResult._from_ctypes(
+ BResult._create_ctype_obj(error))
+ else:
+ error = None
+ def callback(*args):
+ args2 = []
+ for arg, BArg in zip(args, BArgs):
+ args2.append(BArg._from_ctypes(arg))
+ try:
+ res2 = init(*args2)
+ res2 = BResult._to_ctypes(res2)
+ except:
+ traceback.print_exc()
+ res2 = error
+ if issubclass(BResult, CTypesGenericPtr):
+ if res2:
+ res2 = ctypes.cast(res2, ctypes.c_void_p).value
+ # .value: http://bugs.python.org/issue1574593
+ else:
+ res2 = None
+ #print repr(res2)
+ return res2
+ if issubclass(BResult, CTypesGenericPtr):
+ # The only pointers callbacks can return are void*s:
+ # http://bugs.python.org/issue5710
+ callback_ctype = ctypes.CFUNCTYPE(
+ ctypes.c_void_p,
+ *[BArg._ctype for BArg in BArgs],
+ use_errno=True)
+ else:
+ callback_ctype = CTypesFunctionPtr._ctype
+ self._as_ctype_ptr = callback_ctype(callback)
+ self._address = ctypes.cast(self._as_ctype_ptr,
+ ctypes.c_void_p).value
+ self._own_callback = init
+
+ @staticmethod
+ def _initialize(ctypes_ptr, value):
+ if value:
+ raise NotImplementedError("ctypes backend: not supported: "
+ "initializers for function pointers")
+
+ def __repr__(self):
+ c_name = getattr(self, '_name', None)
+ if c_name:
+ i = self._reftypename.index('(* &)')
+ if self._reftypename[i-1] not in ' )*':
+ c_name = ' ' + c_name
+ c_name = self._reftypename.replace('(* &)', c_name)
+ return CTypesData.__repr__(self, c_name)
+
+ def _get_own_repr(self):
+ if getattr(self, '_own_callback', None) is not None:
+ return 'calling %r' % (self._own_callback,)
+ return super(CTypesFunctionPtr, self)._get_own_repr()
+
+ def __call__(self, *args):
+ if has_varargs:
+ assert len(args) >= len(BArgs)
+ extraargs = args[len(BArgs):]
+ args = args[:len(BArgs)]
+ else:
+ assert len(args) == len(BArgs)
+ ctypes_args = []
+ for arg, BArg in zip(args, BArgs):
+ ctypes_args.append(BArg._arg_to_ctypes(arg))
+ if has_varargs:
+ for i, arg in enumerate(extraargs):
+ if arg is None:
+ ctypes_args.append(ctypes.c_void_p(0)) # NULL
+ continue
+ if not isinstance(arg, CTypesData):
+ raise TypeError(
+ "argument %d passed in the variadic part "
+ "needs to be a cdata object (got %s)" %
+ (1 + len(BArgs) + i, type(arg).__name__))
+ ctypes_args.append(arg._arg_to_ctypes(arg))
+ result = self._as_ctype_ptr(*ctypes_args)
+ return BResult._from_ctypes(result)
+ #
+ CTypesFunctionPtr._fix_class()
+ return CTypesFunctionPtr
+
+ def new_enum_type(self, name, enumerators, enumvalues, CTypesInt):
+ assert isinstance(name, str)
+ reverse_mapping = dict(zip(reversed(enumvalues),
+ reversed(enumerators)))
+ #
+ class CTypesEnum(CTypesInt):
+ __slots__ = []
+ _reftypename = '%s &' % name
+
+ def _get_own_repr(self):
+ value = self._value
+ try:
+ return '%d: %s' % (value, reverse_mapping[value])
+ except KeyError:
+ return str(value)
+
+ def _to_string(self, maxlen):
+ value = self._value
+ try:
+ return reverse_mapping[value]
+ except KeyError:
+ return str(value)
+ #
+ CTypesEnum._fix_class()
+ return CTypesEnum
+
+ def get_errno(self):
+ return ctypes.get_errno()
+
+ def set_errno(self, value):
+ ctypes.set_errno(value)
+
+ def string(self, b, maxlen=-1):
+ return b._to_string(maxlen)
+
+ def buffer(self, bptr, size=-1):
+ raise NotImplementedError("buffer() with ctypes backend")
+
+ def sizeof(self, cdata_or_BType):
+ if isinstance(cdata_or_BType, CTypesData):
+ return cdata_or_BType._get_size_of_instance()
+ else:
+ assert issubclass(cdata_or_BType, CTypesData)
+ return cdata_or_BType._get_size()
+
+ def alignof(self, BType):
+ assert issubclass(BType, CTypesData)
+ return BType._alignment()
+
+ def newp(self, BType, source):
+ if not issubclass(BType, CTypesData):
+ raise TypeError
+ return BType._newp(source)
+
+ def cast(self, BType, source):
+ return BType._cast_from(source)
+
+ def callback(self, BType, source, error, onerror):
+ assert onerror is None # XXX not implemented
+ return BType(source, error)
+
+ def gcp(self, cdata, destructor):
+ BType = self.typeof(cdata)
+
+ if destructor is None:
+ if not (hasattr(BType, '_gcp_type') and
+ BType._gcp_type is BType):
+ raise TypeError("Can remove destructor only on a object "
+ "previously returned by ffi.gc()")
+ cdata._destructor = None
+ return None
+
+ try:
+ gcp_type = BType._gcp_type
+ except AttributeError:
+ class CTypesDataGcp(BType):
+ __slots__ = ['_orig', '_destructor']
+ def __del__(self):
+ if self._destructor is not None:
+ self._destructor(self._orig)
+ gcp_type = BType._gcp_type = CTypesDataGcp
+ new_cdata = self.cast(gcp_type, cdata)
+ new_cdata._orig = cdata
+ new_cdata._destructor = destructor
+ return new_cdata
+
+ typeof = type
+
+ def getcname(self, BType, replace_with):
+ return BType._get_c_name(replace_with)
+
+ def typeoffsetof(self, BType, fieldname, num=0):
+ if isinstance(fieldname, str):
+ if num == 0 and issubclass(BType, CTypesGenericPtr):
+ BType = BType._BItem
+ if not issubclass(BType, CTypesBaseStructOrUnion):
+ raise TypeError("expected a struct or union ctype")
+ BField = BType._bfield_types[fieldname]
+ if BField is Ellipsis:
+ raise TypeError("not supported for bitfields")
+ return (BField, BType._offsetof(fieldname))
+ elif isinstance(fieldname, (int, long)):
+ if issubclass(BType, CTypesGenericArray):
+ BType = BType._CTPtr
+ if not issubclass(BType, CTypesGenericPtr):
+ raise TypeError("expected an array or ptr ctype")
+ BItem = BType._BItem
+ offset = BItem._get_size() * fieldname
+ if offset > sys.maxsize:
+ raise OverflowError
+ return (BItem, offset)
+ else:
+ raise TypeError(type(fieldname))
+
+ def rawaddressof(self, BTypePtr, cdata, offset=None):
+ if isinstance(cdata, CTypesBaseStructOrUnion):
+ ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata))
+ elif isinstance(cdata, CTypesGenericPtr):
+ if offset is None or not issubclass(type(cdata)._BItem,
+ CTypesBaseStructOrUnion):
+ raise TypeError("unexpected cdata type")
+ ptr = type(cdata)._to_ctypes(cdata)
+ elif isinstance(cdata, CTypesGenericArray):
+ ptr = type(cdata)._to_ctypes(cdata)
+ else:
+ raise TypeError("expected a <cdata 'struct-or-union'>")
+ if offset:
+ ptr = ctypes.cast(
+ ctypes.c_void_p(
+ ctypes.cast(ptr, ctypes.c_void_p).value + offset),
+ type(ptr))
+ return BTypePtr._from_ctypes(ptr)
+
+
+class CTypesLibrary(object):
+
+ def __init__(self, backend, cdll):
+ self.backend = backend
+ self.cdll = cdll
+
+ def load_function(self, BType, name):
+ c_func = getattr(self.cdll, name)
+ funcobj = BType._from_ctypes(c_func)
+ funcobj._name = name
+ return funcobj
+
+ def read_variable(self, BType, name):
+ try:
+ ctypes_obj = BType._ctype.in_dll(self.cdll, name)
+ except AttributeError as e:
+ raise NotImplementedError(e)
+ return BType._from_ctypes(ctypes_obj)
+
+ def write_variable(self, BType, name, value):
+ new_ctypes_obj = BType._to_ctypes(value)
+ ctypes_obj = BType._ctype.in_dll(self.cdll, name)
+ ctypes.memmove(ctypes.addressof(ctypes_obj),
+ ctypes.addressof(new_ctypes_obj),
+ ctypes.sizeof(BType._ctype))
diff --git a/testing/cffi0/test_backend.py b/testing/cffi0/backend_tests.py
index 8eee5c1..9f51988 100644
--- a/testing/cffi0/test_backend.py
+++ b/testing/cffi0/backend_tests.py
@@ -11,10 +11,10 @@ SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p)
SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
-class TestBackend(object):
+class BackendTests:
def test_integer_ranges(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
for (c_type, size) in [('char', 1),
('short', 2),
('short int', 2),
@@ -34,7 +34,7 @@ class TestBackend(object):
self._test_int_type(ffi, c_decl, size, unsigned)
def test_fixedsize_int(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
for size in [1, 2, 4, 8]:
self._test_int_type(ffi, 'int%d_t' % (8*size), size, False)
self._test_int_type(ffi, 'uint%d_t' % (8*size), size, True)
@@ -79,12 +79,12 @@ class TestBackend(object):
assert ffi.new(c_decl_ptr, long(max))[0] == max
def test_new_unsupported_type(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
e = py.test.raises(TypeError, ffi.new, "int")
assert str(e.value) == "expected a pointer or array ctype, got 'int'"
def test_new_single_integer(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int *") # similar to ffi.new("int[1]")
assert p[0] == 0
p[0] = -123
@@ -94,14 +94,14 @@ class TestBackend(object):
assert repr(p) == "<cdata 'int *' owning %d bytes>" % SIZE_OF_INT
def test_new_array_no_arg(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int[10]")
# the object was zero-initialized:
for i in range(10):
assert p[i] == 0
def test_array_indexing(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int[10]")
p[0] = 42
p[9] = 43
@@ -113,7 +113,7 @@ class TestBackend(object):
py.test.raises(IndexError, "p[-1] = 44")
def test_new_array_args(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
# this tries to be closer to C: where we say "int x[5] = {10, 20, ..}"
# then here we must enclose the items in a list
p = ffi.new("int[5]", [10, 20, 30, 40, 50])
@@ -132,7 +132,7 @@ class TestBackend(object):
assert repr(p) == "<cdata 'int[4]' owning %d bytes>" % (4*SIZE_OF_INT)
def test_new_array_varsize(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int[]", 10) # a single integer is the length
assert p[9] == 0
py.test.raises(IndexError, "p[10]")
@@ -151,7 +151,7 @@ class TestBackend(object):
assert repr(p) == "<cdata 'int[]' owning 0 bytes>"
def test_pointer_init(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
n = ffi.new("int *", 24)
a = ffi.new("int *[10]", [ffi.NULL, ffi.NULL, n, n, ffi.NULL])
for i in range(10):
@@ -160,14 +160,14 @@ class TestBackend(object):
assert a[2] == a[3] == n
def test_cannot_cast(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("short int[10]")
e = py.test.raises(TypeError, ffi.new, "long int **", a)
msg = str(e.value)
assert "'short[10]'" in msg and "'long *'" in msg
def test_new_pointer_to_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("int[4]", [100, 102, 104, 106])
p = ffi.new("int **", a)
assert p[0] == ffi.cast("int *", a)
@@ -180,7 +180,7 @@ class TestBackend(object):
# keepalive: a
def test_pointer_direct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.cast("int*", 0)
assert p is not None
assert bool(p) is False
@@ -195,11 +195,9 @@ class TestBackend(object):
assert p[0] == 123
assert p[1] == 456
- TypeRepr = "<ctype '%s'>"
-
def test_repr(self):
typerepr = self.TypeRepr
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { short a, b, c; };")
p = ffi.cast("short unsigned int", 0)
assert repr(p) == "<cdata 'unsigned short' 0>"
@@ -250,7 +248,7 @@ class TestBackend(object):
assert repr(ffi.typeof(q)) == typerepr % "struct foo"
def test_new_array_of_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int[3][4]")
p[0][0] = 10
p[2][3] = 33
@@ -259,12 +257,12 @@ class TestBackend(object):
py.test.raises(IndexError, "p[1][-1]")
def test_constructor_array_of_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int[3][2]", [[10, 11], [12, 13], [14, 15]])
assert p[2][1] == 15
def test_new_array_of_pointer_1(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
n = ffi.new("int*", 99)
p = ffi.new("int*[4]")
p[3] = n
@@ -273,7 +271,7 @@ class TestBackend(object):
assert a[0] == 99
def test_new_array_of_pointer_2(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
n = ffi.new("int[1]", [99])
p = ffi.new("int*[4]")
p[3] = n
@@ -282,7 +280,7 @@ class TestBackend(object):
assert a[0] == 99
def test_char(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert ffi.new("char*", b"\xff")[0] == b'\xff'
assert ffi.new("char*")[0] == b'\x00'
assert int(ffi.cast("char", 300)) == 300 - 256
@@ -319,7 +317,7 @@ class TestBackend(object):
py.test.skip("NotImplementedError: wchar_t")
def test_wchar_t(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
self.check_wchar_t(ffi)
assert ffi.new("wchar_t*", u+'x')[0] == u+'x'
assert ffi.new("wchar_t*", u+'\u1234')[0] == u+'\u1234'
@@ -374,7 +372,7 @@ class TestBackend(object):
py.test.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc")
def test_none_as_null_doesnt_work(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int*[1]")
assert p[0] is not None
assert p[0] != None
@@ -389,7 +387,7 @@ class TestBackend(object):
assert p[0] == ffi.NULL
def test_float(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("float[]", [-2, -2.5])
assert p[0] == -2.0
assert p[1] == -2.5
@@ -414,7 +412,7 @@ class TestBackend(object):
assert p[0] == INF # infinite, not enough precision
def test_struct_simple(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a; short b, c; };")
s = ffi.new("struct foo*")
assert s.a == s.b == s.c == 0
@@ -433,7 +431,7 @@ class TestBackend(object):
py.test.raises(ValueError, ffi.new, "struct foo*", [1, 2, 3, 4])
def test_constructor_struct_from_dict(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a; short b, c; };")
s = ffi.new("struct foo*", {'b': 123, 'c': 456})
assert s.a == 0
@@ -442,7 +440,7 @@ class TestBackend(object):
py.test.raises(KeyError, ffi.new, "struct foo*", {'d': 456})
def test_struct_pointer(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a; short b, c; };")
s = ffi.new("struct foo*")
assert s[0].a == s[0].b == s[0].c == 0
@@ -452,13 +450,13 @@ class TestBackend(object):
py.test.raises(IndexError, "s[1]")
def test_struct_opaque(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
py.test.raises(TypeError, ffi.new, "struct baz*")
p = ffi.new("struct baz **") # this works
assert p[0] == ffi.NULL
def test_pointer_to_struct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a; short b, c; };")
s = ffi.new("struct foo *")
s.a = -42
@@ -480,7 +478,7 @@ class TestBackend(object):
assert p[0][0].a == -46
def test_constructor_struct_of_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a[2]; char b[3]; };")
s = ffi.new("struct foo *", [[10, 11], [b'a', b'b', b'c']])
assert s.a[1] == 11
@@ -491,7 +489,7 @@ class TestBackend(object):
assert s.b[2] == b'c'
def test_recursive_struct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int value; struct foo *next; };")
s = ffi.new("struct foo*")
t = ffi.new("struct foo*")
@@ -502,7 +500,7 @@ class TestBackend(object):
assert s.next.value == 456
def test_union_simple(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("union foo { int a; short b, c; };")
u = ffi.new("union foo*")
assert u.a == u.b == u.c == 0
@@ -517,13 +515,13 @@ class TestBackend(object):
assert repr(u) == "<cdata 'union foo *' owning %d bytes>" % SIZE_OF_INT
def test_union_opaque(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
py.test.raises(TypeError, ffi.new, "union baz *")
u = ffi.new("union baz **") # this works
assert u[0] == ffi.NULL
def test_union_initializer(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("union foo { char a; int b; };")
py.test.raises(TypeError, ffi.new, "union foo*", b'A')
py.test.raises(TypeError, ffi.new, "union foo*", 5)
@@ -538,7 +536,7 @@ class TestBackend(object):
assert u.b == 0
def test_sizeof_type(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
struct foo { int a; short b, c, d; };
union foo { int a; short b, c, d; };
@@ -555,7 +553,7 @@ class TestBackend(object):
assert size == expected_size, (size, expected_size, ctype)
def test_sizeof_cdata(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR
assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT
#
@@ -564,7 +562,7 @@ class TestBackend(object):
assert ffi.sizeof(a) == 5 * SIZE_OF_INT
def test_string_from_char_pointer(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
x = ffi.new("char*", b"x")
assert str(x) == repr(x)
assert ffi.string(x) == b"x"
@@ -572,7 +570,7 @@ class TestBackend(object):
py.test.raises(TypeError, ffi.new, "char*", unicode("foo"))
def test_unicode_from_wchar_pointer(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
self.check_wchar_t(ffi)
x = ffi.new("wchar_t*", u+"x")
assert unicode(x) == unicode(repr(x))
@@ -580,7 +578,7 @@ class TestBackend(object):
assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+""
def test_string_from_char_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("char[]", b"hello.")
p[5] = b'!'
assert ffi.string(p) == b"hello!"
@@ -597,7 +595,7 @@ class TestBackend(object):
assert ffi.string(p) == b'hello'
def test_string_from_wchar_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
self.check_wchar_t(ffi)
assert ffi.string(ffi.cast("wchar_t", "x")) == u+"x"
assert ffi.string(ffi.cast("wchar_t", u+"x")) == u+"x"
@@ -625,7 +623,7 @@ class TestBackend(object):
def test_fetch_const_char_p_field(self):
# 'const' is ignored so far
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { const char *name; };")
t = ffi.new("const char[]", b"testing")
s = ffi.new("struct foo*", [t])
@@ -637,7 +635,7 @@ class TestBackend(object):
def test_fetch_const_wchar_p_field(self):
# 'const' is ignored so far
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
self.check_wchar_t(ffi)
ffi.cdef("struct foo { const wchar_t *name; };")
t = ffi.new("const wchar_t[]", u+"testing")
@@ -648,7 +646,7 @@ class TestBackend(object):
assert s.name == ffi.NULL
def test_voidp(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
py.test.raises(TypeError, ffi.new, "void*")
p = ffi.new("void **")
assert p[0] == ffi.NULL
@@ -669,7 +667,7 @@ class TestBackend(object):
py.test.raises(TypeError, "s.r = b") # fails
def test_functionptr_simple(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0)
def cb(n):
return n + 1
@@ -694,12 +692,12 @@ class TestBackend(object):
assert res == 46
def test_functionptr_advanced(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
t = ffi.typeof("int(*(*)(int))(int)")
assert repr(t) == self.TypeRepr % "int(*(*)(int))(int)"
def test_functionptr_voidptr_return(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
def cb():
return ffi.NULL
p = ffi.callback("void*(*)()", cb)
@@ -715,7 +713,7 @@ class TestBackend(object):
assert res == void_ptr
def test_functionptr_intptr_return(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
def cb():
return ffi.NULL
p = ffi.callback("int*(*)()", cb)
@@ -737,7 +735,7 @@ class TestBackend(object):
assert res == int_array_ptr
def test_functionptr_void_return(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
def foo():
pass
foo_cb = ffi.callback("void foo()", foo)
@@ -745,7 +743,7 @@ class TestBackend(object):
assert result is None
def test_char_cast(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.cast("int", b'\x01')
assert ffi.typeof(p) is ffi.typeof("int")
assert int(p) == 1
@@ -757,7 +755,7 @@ class TestBackend(object):
assert int(p) == 0x81
def test_wchar_cast(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
self.check_wchar_t(ffi)
p = ffi.cast("int", ffi.cast("wchar_t", u+'\u1234'))
assert int(p) == 0x1234
@@ -773,7 +771,7 @@ class TestBackend(object):
assert int(p) == 0x1234
def test_cast_array_to_charp(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("short int[]", [0x1234, 0x5678])
p = ffi.cast("char*", a)
data = b''.join([p[i] for i in range(4)])
@@ -783,7 +781,7 @@ class TestBackend(object):
assert data == b'\x12\x34\x56\x78'
def test_cast_between_pointers(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("short int[]", [0x1234, 0x5678])
p = ffi.cast("short*", a)
p2 = ffi.cast("int*", p)
@@ -795,7 +793,7 @@ class TestBackend(object):
assert data == b'\x12\x34\x56\x78'
def test_cast_pointer_and_int(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("short int[]", [0x1234, 0x5678])
l1 = ffi.cast("intptr_t", a)
p = ffi.cast("short*", a)
@@ -807,7 +805,7 @@ class TestBackend(object):
assert int(ffi.cast("intptr_t", ffi.NULL)) == 0
def test_cast_functionptr_and_int(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
def cb(n):
return n + 1
a = ffi.callback("int(*)(int)", cb)
@@ -819,7 +817,7 @@ class TestBackend(object):
assert hash(a) == hash(b)
def test_callback_crash(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
def cb(n):
raise Exception
a = ffi.callback("int(*)(int)", cb, error=42)
@@ -827,7 +825,7 @@ class TestBackend(object):
assert res == 42
def test_structptr_argument(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int a, b; };")
def cb(p):
return p[0].a * 1000 + p[0].b * 100 + p[1].a * 10 + p[1].b
@@ -838,7 +836,7 @@ class TestBackend(object):
assert res == 5008
def test_array_argument_as_list(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int a, b; };")
seen = []
def cb(argv):
@@ -849,7 +847,7 @@ class TestBackend(object):
assert seen == [b"foobar", b"baz"]
def test_cast_float(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.cast("float", 12)
assert float(a) == 12.0
a = ffi.cast("float", 12.5)
@@ -873,7 +871,7 @@ class TestBackend(object):
assert ffi.string(a) == b"B"
def test_enum(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("enum foo { A0, B0, CC0, D0 };")
assert ffi.string(ffi.cast("enum foo", 0)) == "A0"
assert ffi.string(ffi.cast("enum foo", 2)) == "CC0"
@@ -895,7 +893,7 @@ class TestBackend(object):
assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2"
def test_enum_in_struct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("enum foo { A, B, C, D }; struct bar { enum foo e; };")
s = ffi.new("struct bar *")
s.e = 0
@@ -916,7 +914,7 @@ class TestBackend(object):
py.test.raises(TypeError, "s.e = '#7'")
def test_enum_non_contiguous(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("enum foo { A, B=42, C };")
assert ffi.string(ffi.cast("enum foo", 0)) == "A"
assert ffi.string(ffi.cast("enum foo", 42)) == "B"
@@ -926,7 +924,7 @@ class TestBackend(object):
assert ffi.string(invalid_value) == "2"
def test_enum_char_hex_oct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef(r"enum foo{A='!', B='\'', C=0x10, D=010, E=- 0x10, F=-010};")
assert ffi.string(ffi.cast("enum foo", ord('!'))) == "A"
assert ffi.string(ffi.cast("enum foo", ord("'"))) == "B"
@@ -936,7 +934,7 @@ class TestBackend(object):
assert ffi.string(ffi.cast("enum foo", -8)) == "F"
def test_enum_partial(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };")
lib = ffi.dlopen(None)
assert lib.B == 0
@@ -944,7 +942,7 @@ class TestBackend(object):
assert lib.C == 1
def test_array_of_struct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a, b; };")
s = ffi.new("struct foo[1]")
py.test.raises(AttributeError, 's.b')
@@ -954,12 +952,12 @@ class TestBackend(object):
py.test.raises(IndexError, 's[1]')
def test_pointer_to_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int(**)[5]")
assert repr(p) == "<cdata 'int(* *)[5]' owning %d bytes>" % SIZE_OF_PTR
def test_iterate_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("char[]", b"hello")
assert list(a) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
assert list(iter(a)) == [b"h", b"e", b"l", b"l", b"o", b"\0"]
@@ -970,14 +968,14 @@ class TestBackend(object):
py.test.raises(TypeError, list, ffi.new("int *"))
def test_offsetof(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a, b, c; };")
assert ffi.offsetof("struct foo", "a") == 0
assert ffi.offsetof("struct foo", "b") == 4
assert ffi.offsetof("struct foo", "c") == 8
def test_offsetof_nested(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a, b, c; };"
"struct bar { struct foo d, e; };")
assert ffi.offsetof("struct bar", "e") == 12
@@ -987,7 +985,7 @@ class TestBackend(object):
assert ffi.offsetof("struct bar", "e", "c") == 20
def test_offsetof_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert ffi.offsetof("int[]", 51) == 51 * ffi.sizeof("int")
assert ffi.offsetof("int *", 51) == 51 * ffi.sizeof("int")
ffi.cdef("struct bar { int a, b; int c[99]; };")
@@ -996,14 +994,14 @@ class TestBackend(object):
assert ffi.offsetof("struct bar", "c", 51) == 53 * ffi.sizeof("int")
def test_alignof(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { char a; short b; char c; };")
assert ffi.alignof("int") == 4
assert ffi.alignof("double") in (4, 8)
assert ffi.alignof("struct foo") == 2
def test_bitfield(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a:10, b:20, c:3; };")
assert ffi.sizeof("struct foo") == 8
s = ffi.new("struct foo *")
@@ -1023,7 +1021,7 @@ class TestBackend(object):
assert s.c == -4
def test_bitfield_enum(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
typedef enum { AA, BB, CC } foo_e;
typedef struct { foo_e f:2; } foo_s;
@@ -1033,7 +1031,7 @@ class TestBackend(object):
assert s.f == 2
def test_anonymous_struct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("typedef struct { int a; } foo_t;")
ffi.cdef("typedef struct { char b, c; } bar_t;")
f = ffi.new("foo_t *", [12345])
@@ -1045,13 +1043,13 @@ class TestBackend(object):
def test_struct_with_two_usages(self):
for name in ['foo_s', '']: # anonymous or not
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("typedef struct %s { int a; } foo_t, *foo_p;" % name)
f = ffi.new("foo_t *", [12345])
ps = ffi.new("foo_p[]", [f])
def test_pointer_arithmetic(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
s = ffi.new("short[]", list(range(100, 110)))
p = ffi.cast("short *", s)
assert p[2] == 102
@@ -1065,7 +1063,7 @@ class TestBackend(object):
assert p+1 == s+1
def test_pointer_comparison(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
s = ffi.new("short[]", list(range(100)))
p = ffi.cast("short *", s)
assert (p < s) is False
@@ -1116,7 +1114,7 @@ class TestBackend(object):
assert (q != None) is True
def test_no_integer_comparison(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
x = ffi.cast("int", 123)
y = ffi.cast("int", 456)
py.test.raises(TypeError, "x < y")
@@ -1126,7 +1124,7 @@ class TestBackend(object):
py.test.raises(TypeError, "z < y")
def test_ffi_buffer_ptr(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("short *", 100)
try:
b = ffi.buffer(a)
@@ -1145,7 +1143,7 @@ class TestBackend(object):
assert a[0] == 101
def test_ffi_buffer_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("int[]", list(range(100, 110)))
try:
b = ffi.buffer(a)
@@ -1162,7 +1160,7 @@ class TestBackend(object):
assert a[1] == 0x45
def test_ffi_buffer_ptr_size(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a = ffi.new("short *", 0x4243)
try:
b = ffi.buffer(a, 1)
@@ -1180,7 +1178,7 @@ class TestBackend(object):
assert a[0] == 0x6343
def test_ffi_buffer_array_size(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
a1 = ffi.new("int[]", list(range(100, 110)))
a2 = ffi.new("int[]", list(range(100, 115)))
try:
@@ -1190,7 +1188,7 @@ class TestBackend(object):
assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:]
def test_ffi_buffer_with_file(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
import tempfile, os, array
fd, filename = tempfile.mkstemp()
f = os.fdopen(fd, 'r+b')
@@ -1210,7 +1208,7 @@ class TestBackend(object):
os.unlink(filename)
def test_ffi_buffer_with_io(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
import io, array
f = io.BytesIO()
a = ffi.new("int[]", list(range(1005)))
@@ -1228,7 +1226,7 @@ class TestBackend(object):
f.close()
def test_array_in_struct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int len; short data[5]; };")
p = ffi.new("struct foo_s *")
p.data[3] = 5
@@ -1236,7 +1234,7 @@ class TestBackend(object):
assert repr(p.data).startswith("<cdata 'short[5]' 0x")
def test_struct_containing_array_varsize_workaround(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int len; short data[0]; };")
p = ffi.new("char[]", ffi.sizeof("struct foo_s") + 7 * SIZE_OF_SHORT)
q = ffi.cast("struct foo_s *", p)
@@ -1249,7 +1247,7 @@ class TestBackend(object):
def test_new_struct_containing_array_varsize(self):
py.test.skip("later?")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int len; short data[]; };")
p = ffi.new("struct foo_s *", 10) # a single integer is the length
assert p.len == 0
@@ -1257,7 +1255,7 @@ class TestBackend(object):
py.test.raises(IndexError, "p.data[10]")
def test_ffi_typeof_getcname(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert ffi.getctype("int") == "int"
assert ffi.getctype("int", 'x') == "int x"
assert ffi.getctype("int*") == "int *"
@@ -1275,7 +1273,7 @@ class TestBackend(object):
assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]"
def test_array_of_func_ptr(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
f = ffi.cast("int(*)(int)", 42)
assert f != ffi.NULL
py.test.raises(CDefError, ffi.cast, "int(int)", 42)
@@ -1296,7 +1294,7 @@ class TestBackend(object):
def test_callback_as_function_argument(self):
# In C, function arguments can be declared with a function type,
# which is automatically replaced with the ptr-to-function type.
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
def cb(a, b):
return chr(ord(a) + ord(b)).encode()
f = ffi.callback("char cb(char, char)", cb)
@@ -1308,7 +1306,7 @@ class TestBackend(object):
def test_vararg_callback(self):
py.test.skip("callback with '...'")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
def cb(i, va_list):
j = ffi.va_arg(va_list, "int")
k = ffi.va_arg(va_list, "long long")
@@ -1318,7 +1316,7 @@ class TestBackend(object):
assert res == 20 + 300 + 5000
def test_callback_decorator(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
#
@ffi.callback("long(long, long)", error=42)
def cb(a, b):
@@ -1329,8 +1327,8 @@ class TestBackend(object):
assert cb((1 << (sz*8-1)) - 1, -10) == 42
def test_unique_types(self):
- ffi1 = FFI()
- ffi2 = FFI()
+ ffi1 = FFI(backend=self.Backend())
+ ffi2 = FFI(backend=self.Backend())
assert ffi1.typeof("char") is ffi2.typeof("char ")
assert ffi1.typeof("long") is ffi2.typeof("signed long int")
assert ffi1.typeof("double *") is ffi2.typeof("double*")
@@ -1349,7 +1347,7 @@ class TestBackend(object):
assert ffi1.typeof("struct foo*") is ffi1.typeof("struct foo *")
def test_anonymous_enum(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("typedef enum { Value0 = 0 } e, *pe;\n"
"typedef enum { Value1 = 1 } e1;")
assert ffi.getctype("e*") == 'e *'
@@ -1357,7 +1355,7 @@ class TestBackend(object):
assert ffi.getctype("e1*") == 'e1 *'
def test_opaque_enum(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("enum foo;")
from cffi import __version_info__
if __version_info__ < (1, 8):
@@ -1368,20 +1366,20 @@ class TestBackend(object):
"which integer type it is meant to be (unsigned/signed, int/long)")
def test_new_ctype(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int *")
py.test.raises(TypeError, ffi.new, p)
p = ffi.new(ffi.typeof("int *"), 42)
assert p[0] == 42
def test_enum_with_non_injective_mapping(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("enum e { AA=0, BB=0, CC=0, DD=0 };")
e = ffi.cast("enum e", 0)
assert ffi.string(e) == "AA" # pick the first one arbitrarily
def test_enum_refer_previous_enum_value(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("enum e { AA, BB=2, CC=4, DD=BB, EE, FF=CC, GG=FF };")
assert ffi.string(ffi.cast("enum e", 2)) == "BB"
assert ffi.string(ffi.cast("enum e", 3)) == "EE"
@@ -1391,7 +1389,7 @@ class TestBackend(object):
assert ffi.sizeof("char[GG]") == 4
def test_nested_anonymous_struct(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
struct foo_s {
struct { int a, b; };
@@ -1418,7 +1416,7 @@ class TestBackend(object):
assert p.d == 14
def test_nested_field_offset_align(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
struct foo_s {
struct { int a; char b; };
@@ -1429,7 +1427,7 @@ class TestBackend(object):
assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
def test_nested_anonymous_union(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
union foo_u {
struct { int a, b; };
@@ -1465,14 +1463,14 @@ class TestBackend(object):
# to give both 'a' and 'b'
def test_cast_to_array_type(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int[4]", [-5])
q = ffi.cast("int[3]", p)
assert q[0] == -5
assert repr(q).startswith("<cdata 'int[3]' 0x")
def test_gc(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int *", 123)
seen = []
def destructor(p1):
@@ -1487,7 +1485,7 @@ class TestBackend(object):
assert seen == [1]
def test_gc_2(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int *", 123)
seen = []
q1 = ffi.gc(p, lambda p: seen.append(1))
@@ -1499,7 +1497,7 @@ class TestBackend(object):
assert seen == [2, 1]
def test_gc_3(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int *", 123)
r = ffi.new("int *", 123)
seen = []
@@ -1518,7 +1516,7 @@ class TestBackend(object):
assert seen_r == [5, 4]
def test_gc_4(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int *", 123)
seen = []
q1 = ffi.gc(p, lambda p: seen.append(1))
@@ -1531,7 +1529,7 @@ class TestBackend(object):
assert seen == [3]
def test_gc_disable(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int *", 123)
py.test.raises(TypeError, ffi.gc, p, None)
seen = []
@@ -1545,7 +1543,7 @@ class TestBackend(object):
assert seen == [2]
def test_gc_finite_list(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
p = ffi.new("int *", 123)
keepalive = []
for i in range(10):
@@ -1556,7 +1554,7 @@ class TestBackend(object):
keepalive.append(ffi.gc(p, lambda p: None))
def test_CData_CType(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert isinstance(ffi.cast("int", 0), ffi.CData)
assert isinstance(ffi.new("int *"), ffi.CData)
assert not isinstance(ffi.typeof("int"), ffi.CData)
@@ -1564,11 +1562,11 @@ class TestBackend(object):
assert not isinstance(ffi.new("int *"), ffi.CType)
def test_CData_CType_2(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert isinstance(ffi.typeof("int"), ffi.CType)
def test_bool(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert int(ffi.cast("_Bool", 0.1)) == 1
assert int(ffi.cast("_Bool", -0.0)) == 0
assert int(ffi.cast("_Bool", b'\x02')) == 1
@@ -1580,11 +1578,11 @@ class TestBackend(object):
py.test.raises(TypeError, ffi.string, ffi.cast("_Bool", 2))
def test_use_own_bool(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""typedef int bool;""")
def test_ordering_bug1(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
struct foo_s {
struct bar_s *p;
@@ -1599,7 +1597,7 @@ class TestBackend(object):
assert q.p.foo.p == ffi.NULL
def test_ordering_bug2(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
struct bar_s;
@@ -1614,7 +1612,7 @@ class TestBackend(object):
q = ffi.new("struct foo_s *")
def test_addressof(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int x, y; };")
p = ffi.new("struct foo_s *")
a = ffi.addressof(p[0])
@@ -1625,7 +1623,7 @@ class TestBackend(object):
py.test.raises(TypeError, ffi.addressof, ffi.cast("int", 5))
def test_addressof_field(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int x, y; };")
p = ffi.new("struct foo_s *")
a = ffi.addressof(p[0], 'y')
@@ -1636,7 +1634,7 @@ class TestBackend(object):
assert a != ffi.addressof(p, 'x')
def test_addressof_field_nested(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int x, y; };"
"struct bar_s { struct foo_s a, b; };")
p = ffi.new("struct bar_s *")
@@ -1706,38 +1704,43 @@ class TestBackend(object):
assert foo2.z == 30
def test_missing_include(self):
- ffi1 = FFI()
- ffi2 = FFI()
+ backend = self.Backend()
+ ffi1 = FFI(backend=backend)
+ ffi2 = FFI(backend=backend)
ffi1.cdef("typedef signed char schar_t;")
py.test.raises(CDefError, ffi2.cast, "schar_t", 142)
def test_include_typedef(self):
- ffi1 = FFI()
- ffi2 = FFI()
+ backend = self.Backend()
+ ffi1 = FFI(backend=backend)
+ ffi2 = FFI(backend=backend)
ffi1.cdef("typedef signed char schar_t;")
ffi2.include(ffi1)
p = ffi2.cast("schar_t", 142)
assert int(p) == 142 - 256
def test_include_struct(self):
- ffi1 = FFI()
- ffi2 = FFI()
+ backend = self.Backend()
+ ffi1 = FFI(backend=backend)
+ ffi2 = FFI(backend=backend)
ffi1.cdef("struct foo { int x; };")
ffi2.include(ffi1)
p = ffi2.new("struct foo *", [142])
assert p.x == 142
def test_include_union(self):
- ffi1 = FFI()
- ffi2 = FFI()
+ backend = self.Backend()
+ ffi1 = FFI(backend=backend)
+ ffi2 = FFI(backend=backend)
ffi1.cdef("union foo { int x; };")
ffi2.include(ffi1)
p = ffi2.new("union foo *", [142])
assert p.x == 142
def test_include_enum(self):
- ffi1 = FFI()
- ffi2 = FFI()
+ backend = self.Backend()
+ ffi1 = FFI(backend=backend)
+ ffi2 = FFI(backend=backend)
ffi1.cdef("enum foo { FA, FB, FC };")
ffi2.include(ffi1)
p = ffi2.cast("enum foo", 1)
@@ -1745,21 +1748,22 @@ class TestBackend(object):
assert ffi2.sizeof("char[FC]") == 2
def test_include_typedef_2(self):
- ffi1 = FFI()
- ffi2 = FFI()
+ backend = self.Backend()
+ ffi1 = FFI(backend=backend)
+ ffi2 = FFI(backend=backend)
ffi1.cdef("typedef struct { int x; } *foo_p;")
ffi2.include(ffi1)
p = ffi2.new("foo_p", [142])
assert p.x == 142
def test_ignore_multiple_declarations_of_constant(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("#define FOO 42")
ffi.cdef("#define FOO 42")
py.test.raises(FFIError, ffi.cdef, "#define FOO 43")
def test_struct_packed(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct nonpacked { char a; int b; };")
ffi.cdef("struct is_packed { char a; int b; };", packed=True)
assert ffi.sizeof("struct nonpacked") == 8
@@ -1777,7 +1781,7 @@ class TestBackend(object):
assert s[1].a == b'Y'
def test_define_integer_constant(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
#define DOT_0 0
#define DOT 100
@@ -1800,14 +1804,14 @@ class TestBackend(object):
# Issue #193: if we use a struct between the first cdef() where it is
# declared and another cdef() where its fields are defined, then the
# definition was ignored.
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s;")
py.test.raises(TypeError, ffi.new, "struct foo_s *")
ffi.cdef("struct foo_s { int x; };")
ffi.new("struct foo_s *")
def test_ffi_self_include(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
py.test.raises(ValueError, ffi.include, ffi)
def test_anonymous_enum_include(self):
@@ -1860,5 +1864,5 @@ class TestBackend(object):
def test_sizeof_struct_directly(self):
# only works with the Python FFI instances
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert ffi.sizeof("struct{int a;}") == ffi.sizeof("int")
diff --git a/testing/cffi0/test_cdata.py b/testing/cffi0/test_cdata.py
new file mode 100644
index 0000000..116d0b3
--- /dev/null
+++ b/testing/cffi0/test_cdata.py
@@ -0,0 +1,39 @@
+import py
+from cffi import FFI
+
+class FakeBackend(object):
+
+ def nonstandard_integer_types(self):
+ return {}
+
+ def sizeof(self, name):
+ return 1
+
+ def load_library(self, path):
+ return "fake library"
+
+ def new_primitive_type(self, name):
+ return FakeType("primitive " + name)
+
+ def new_void_type(self):
+ return FakeType("void")
+ def new_pointer_type(self, x):
+ return FakeType('ptr-to-%r' % (x,))
+ def new_array_type(self, x, y):
+ return FakeType('array-from-%r-len-%r' % (x, y))
+ def cast(self, x, y):
+ return 'casted!'
+ def _get_types(self):
+ return "CData", "CType"
+
+
+class FakeType(object):
+ def __init__(self, cdecl):
+ self.cdecl = cdecl
+
+
+def test_typeof():
+ ffi = FFI(backend=FakeBackend())
+ clong = ffi.typeof("signed long int")
+ assert isinstance(clong, FakeType)
+ assert clong.cdecl == 'primitive long'
diff --git a/testing/cffi0/test_ctypes.py b/testing/cffi0/test_ctypes.py
new file mode 100644
index 0000000..1b88473
--- /dev/null
+++ b/testing/cffi0/test_ctypes.py
@@ -0,0 +1,40 @@
+import py, sys
+from testing.cffi0 import backend_tests
+from cffi.backend_ctypes import CTypesBackend
+
+
+class TestCTypes(backend_tests.BackendTests):
+ # for individual tests see
+ # ====> backend_tests.py
+
+ Backend = CTypesBackend
+ TypeRepr = "<class 'ffi.CData<%s>'>"
+
+ def test_array_of_func_ptr(self):
+ py.test.skip("ctypes backend: not supported: "
+ "initializers for function pointers")
+
+ def test_structptr_argument(self):
+ py.test.skip("ctypes backend: not supported: passing a list "
+ "for a pointer argument")
+
+ def test_array_argument_as_list(self):
+ py.test.skip("ctypes backend: not supported: passing a list "
+ "for a pointer argument")
+
+ def test_cast_to_array_type(self):
+ py.test.skip("ctypes backend: not supported: casting to array")
+
+ def test_nested_anonymous_struct(self):
+ py.test.skip("ctypes backend: not supported: nested anonymous struct")
+
+ def test_nested_field_offset_align(self):
+ py.test.skip("ctypes backend: not supported: nested anonymous struct")
+
+ def test_nested_anonymous_union(self):
+ py.test.skip("ctypes backend: not supported: nested anonymous union")
+
+ def test_CData_CType_2(self):
+ if sys.version_info >= (3,):
+ py.test.skip("ctypes backend: not supported in Python 3: CType")
+ backend_tests.BackendTests.test_CData_CType_2(self)
diff --git a/testing/cffi0/test_ffi_backend.py b/testing/cffi0/test_ffi_backend.py
index 5a34876..0d25a0d 100644
--- a/testing/cffi0/test_ffi_backend.py
+++ b/testing/cffi0/test_ffi_backend.py
@@ -1,12 +1,21 @@
import py, sys, platform
import pytest
+from testing.cffi0 import backend_tests, test_function, test_ownlib
from cffi import FFI
+import _cffi_backend
-class TestFFI(object):
+class TestFFI(backend_tests.BackendTests,
+ test_function.TestFunction,
+ test_ownlib.TestOwnLib):
+ TypeRepr = "<ctype '%s'>"
+
+ @staticmethod
+ def Backend():
+ return _cffi_backend
def test_not_supported_bitfield_in_result(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo_s { int a,b,c,d,e; int x:1; };")
e = py.test.raises(NotImplementedError, ffi.callback,
"struct foo_s foo(void)", lambda: 42)
@@ -14,14 +23,14 @@ class TestFFI(object):
"callback with unsupported argument or return type or with '...'")
def test_inspecttype(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
assert ffi.typeof("long").kind == "primitive"
assert ffi.typeof("long(*)(long, long**, ...)").cname == (
"long(*)(long, long * *, ...)")
assert ffi.typeof("long(*)(long, long**, ...)").ellipsis is True
def test_new_handle(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
o = [2, 3, 4]
p = ffi.new_handle(o)
assert ffi.typeof(p) == ffi.typeof("void *")
@@ -30,7 +39,7 @@ class TestFFI(object):
py.test.raises(RuntimeError, ffi.from_handle, ffi.NULL)
def test_callback_onerror(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
seen = []
def oops(*args):
seen.append(args)
@@ -49,7 +58,7 @@ class TestFFI(object):
assert tb.tb_frame.f_locals['n'] == 234
def test_ffi_new_allocator_2(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
seen = []
def myalloc(size):
seen.append(size)
@@ -81,7 +90,7 @@ class TestFFI(object):
assert repr(seen[3]) == "<cdata 'char[]' owning 41 bytes>"
def test_ffi_new_allocator_3(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
seen = []
def myalloc(size):
seen.append(size)
@@ -94,7 +103,7 @@ class TestFFI(object):
assert p1[5] == 0
def test_ffi_new_allocator_4(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
py.test.raises(TypeError, ffi.new_allocator, free=lambda x: None)
#
def myalloc2(size):
diff --git a/testing/cffi0/test_function.py b/testing/cffi0/test_function.py
index c5bc3d1..0150703 100644
--- a/testing/cffi0/test_function.py
+++ b/testing/cffi0/test_function.py
@@ -2,6 +2,7 @@ import py
from cffi import FFI, CDefError
import math, os, sys
import ctypes.util
+from cffi.backend_ctypes import CTypesBackend
from testing.udir import udir
from testing.support import FdWriteCapture
@@ -19,9 +20,10 @@ if sys.platform == 'win32':
lib_m = 'msvcrt'
class TestFunction(object):
+ Backend = CTypesBackend
def test_sin(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
double sin(double x);
""")
@@ -32,7 +34,7 @@ class TestFunction(object):
def test_sinf(self):
if sys.platform == 'win32':
py.test.skip("no sinf found in the Windows stdlib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
float sinf(float x);
""")
@@ -44,7 +46,7 @@ class TestFunction(object):
def test_sin_no_return_value(self):
# check that 'void'-returning functions work too
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
void sin(double x);
""")
@@ -56,7 +58,7 @@ class TestFunction(object):
path = ctypes.util.find_library(lib_m)
if not path:
py.test.skip("%s not found" % lib_m)
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
double cos(double x);
""")
@@ -69,7 +71,7 @@ class TestFunction(object):
assert x == math.cos(1.23)
def test_dlopen_flags(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
double cos(double x);
""")
@@ -78,7 +80,7 @@ class TestFunction(object):
assert x == math.cos(1.23)
def test_dlopen_constant(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
#define FOOBAR 42
static const float baz = 42.5; /* not visible */
@@ -91,7 +93,9 @@ class TestFunction(object):
def test_tlsalloc(self):
if sys.platform != 'win32':
py.test.skip("win32 only")
- ffi = FFI()
+ if self.Backend is CTypesBackend:
+ py.test.skip("ctypes complains on wrong calling conv")
+ ffi = FFI(backend=self.Backend())
ffi.cdef("long TlsAlloc(void); int TlsFree(long);")
lib = ffi.dlopen('KERNEL32.DLL')
x = lib.TlsAlloc()
@@ -102,7 +106,7 @@ class TestFunction(object):
def test_fputs(self):
if not sys.platform.startswith('linux'):
py.test.skip("probably no symbol 'stderr' in the lib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fputs(const char *, void *);
void *stderr;
@@ -118,7 +122,7 @@ class TestFunction(object):
def test_fputs_without_const(self):
if not sys.platform.startswith('linux'):
py.test.skip("probably no symbol 'stderr' in the lib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fputs(char *, void *);
void *stderr;
@@ -134,7 +138,7 @@ class TestFunction(object):
def test_vararg(self):
if not sys.platform.startswith('linux'):
py.test.skip("probably no symbol 'stderr' in the lib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fprintf(void *, const char *format, ...);
void *stderr;
@@ -161,7 +165,7 @@ class TestFunction(object):
b"hello (nil)\n")
def test_must_specify_type_of_vararg(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int printf(const char *format, ...);
""")
@@ -171,17 +175,18 @@ class TestFunction(object):
"needs to be a cdata object (got int)")
def test_function_has_a_c_type(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int puts(const char *);
""")
ffi.C = ffi.dlopen(None)
fptr = ffi.C.puts
assert ffi.typeof(fptr) == ffi.typeof("int(*)(const char*)")
- assert repr(fptr).startswith("<cdata 'int(*)(char *)' 0x")
+ if self.Backend is CTypesBackend:
+ assert repr(fptr).startswith("<cdata 'int puts(char *)' 0x")
def test_function_pointer(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
def cb(charp):
assert repr(charp).startswith("<cdata 'char *' 0x")
return 42
@@ -207,7 +212,7 @@ class TestFunction(object):
assert res == b'world\n'
def test_callback_returning_void(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
for returnvalue in [None, 42]:
def cb():
return returnvalue
@@ -226,7 +231,7 @@ class TestFunction(object):
assert "None" in printed
def test_passing_array(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int strlen(char[]);
""")
@@ -238,7 +243,7 @@ class TestFunction(object):
def test_write_variable(self):
if not sys.platform.startswith('linux'):
py.test.skip("probably no symbol 'stdout' in the lib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
void *stdout;
""")
@@ -250,7 +255,7 @@ class TestFunction(object):
assert C.stdout == pout
def test_strchr(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
char *strchr(const char *s, int c);
""")
@@ -262,7 +267,10 @@ class TestFunction(object):
def test_function_with_struct_argument(self):
if sys.platform == 'win32':
py.test.skip("no 'inet_ntoa'")
- ffi = FFI()
+ if (self.Backend is CTypesBackend and
+ '__pypy__' in sys.builtin_module_names):
+ py.test.skip("ctypes limitation on pypy")
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
struct in_addr { unsigned int s_addr; };
char *inet_ntoa(struct in_addr in);
@@ -273,7 +281,7 @@ class TestFunction(object):
assert ffi.string(a) == b'4.4.4.4'
def test_function_typedef(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
typedef double func_t(double);
func_t sin;
@@ -283,8 +291,10 @@ class TestFunction(object):
assert x == math.sin(1.23)
def test_fputs_custom_FILE(self):
+ if self.Backend is CTypesBackend:
+ py.test.skip("FILE not supported with the ctypes backend")
filename = str(udir.join('fputs_custom_FILE'))
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("int fputs(const char *, FILE *);")
C = ffi.dlopen(None)
with open(filename, 'wb') as f:
@@ -298,7 +308,7 @@ class TestFunction(object):
assert res == b'[hello from custom file][some more output]'
def test_constants_on_lib(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""enum foo_e { AA, BB, CC=5, DD };
typedef enum { EE=-5, FF } some_enum_t;""")
lib = ffi.dlopen(None)
@@ -310,28 +320,32 @@ class TestFunction(object):
assert lib.FF == -4
def test_void_star_accepts_string(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""int strlen(const void *);""")
lib = ffi.dlopen(None)
res = lib.strlen(b"hello")
assert res == 5
def test_signed_char_star_accepts_string(self):
- ffi = FFI()
+ if self.Backend is CTypesBackend:
+ py.test.skip("not supported by the ctypes backend")
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""int strlen(signed char *);""")
lib = ffi.dlopen(None)
res = lib.strlen(b"hello")
assert res == 5
def test_unsigned_char_star_accepts_string(self):
- ffi = FFI()
+ if self.Backend is CTypesBackend:
+ py.test.skip("not supported by the ctypes backend")
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""int strlen(unsigned char *);""")
lib = ffi.dlopen(None)
res = lib.strlen(b"hello")
assert res == 5
def test_missing_function(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int nonexistent();
""")
@@ -340,7 +354,7 @@ class TestFunction(object):
def test_wraps_from_stdlib(self):
import functools
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
double sin(double x);
""")
@@ -355,6 +369,8 @@ class TestFunction(object):
assert x == math.sin(1.23) + 100
def test_free_callback_cycle(self):
+ if self.Backend is CTypesBackend:
+ py.test.skip("seems to fail with the ctypes backend on windows")
import weakref
def make_callback(data):
container = [data]
@@ -365,7 +381,7 @@ class TestFunction(object):
class Data(object):
pass
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
data = Data()
callback = make_callback(data)
wr = weakref.ref(data)
@@ -378,7 +394,9 @@ class TestFunction(object):
def test_windows_stdcall(self):
if sys.platform != 'win32':
py.test.skip("Windows-only test")
- ffi = FFI()
+ if self.Backend is CTypesBackend:
+ py.test.skip("not with the ctypes backend")
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
""")
@@ -391,9 +409,11 @@ class TestFunction(object):
def test_explicit_cdecl_stdcall(self):
if sys.platform != 'win32':
py.test.skip("Windows-only test")
+ if self.Backend is CTypesBackend:
+ py.test.skip("not with the ctypes backend")
win64 = (sys.maxsize > 2**32)
#
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
""")
@@ -401,7 +421,7 @@ class TestFunction(object):
tp = ffi.typeof(m.QueryPerformanceFrequency)
assert str(tp) == "<ctype 'int(*)(long long *)'>"
#
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
BOOL __cdecl QueryPerformanceFrequency(LONGLONG *lpFrequency);
""")
@@ -409,7 +429,7 @@ class TestFunction(object):
tpc = ffi.typeof(m.QueryPerformanceFrequency)
assert tpc is tp
#
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
BOOL WINAPI QueryPerformanceFrequency(LONGLONG *lpFrequency);
""")
@@ -421,7 +441,7 @@ class TestFunction(object):
assert tps is not tpc
assert str(tps) == "<ctype 'int(__stdcall *)(long long *)'>"
#
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("typedef int (__cdecl *fnc_t)(int);")
ffi.cdef("typedef int (__stdcall *fns_t)(int);")
tpc = ffi.typeof("fnc_t")
@@ -441,10 +461,11 @@ class TestFunction(object):
ffi.new("fns_t[]", [fns])
def test_stdcall_only_on_windows(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("double __stdcall sin(double x);") # stdcall ignored
m = ffi.dlopen(lib_m)
- if sys.platform == 'win32' and sys.maxsize < 2**32:
+ if (sys.platform == 'win32' and sys.maxsize < 2**32 and
+ self.Backend is not CTypesBackend):
assert "double(__stdcall *)(double)" in str(ffi.typeof(m.sin))
else:
assert "double(*)(double)" in str(ffi.typeof(m.sin))
@@ -452,7 +473,7 @@ class TestFunction(object):
assert x == math.sin(1.23)
def test_dir_on_dlopen_lib(self):
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
typedef enum { MYE1, MYE2 } myenum_t;
double myfunc(double);
diff --git a/testing/cffi0/test_ownlib.py b/testing/cffi0/test_ownlib.py
index aa85ad6..afda543 100644
--- a/testing/cffi0/test_ownlib.py
+++ b/testing/cffi0/test_ownlib.py
@@ -1,6 +1,7 @@
import py, sys
import subprocess, weakref
from cffi import FFI
+from cffi.backend_ctypes import CTypesBackend
SOURCE = """\
@@ -94,6 +95,7 @@ EXPORT int my_array[7] = {0, 1, 2, 3, 4, 5, 6};
"""
class TestOwnLib(object):
+ Backend = CTypesBackend
def setup_class(cls):
cls.module = None
@@ -136,7 +138,7 @@ class TestOwnLib(object):
py.test.skip("fix the auto-generation of the tiny test lib")
if sys.platform == 'win32':
py.test.skip("fails, errno at multiple addresses")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int test_getting_errno(void);
""")
@@ -150,7 +152,9 @@ class TestOwnLib(object):
py.test.skip("fix the auto-generation of the tiny test lib")
if sys.platform == 'win32':
py.test.skip("fails, errno at multiple addresses")
- ffi = FFI()
+ if self.Backend is CTypesBackend and '__pypy__' in sys.modules:
+ py.test.skip("XXX errno issue with ctypes on pypy?")
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int test_setting_errno(void);
""")
@@ -163,7 +167,7 @@ class TestOwnLib(object):
def test_my_array_7(self):
if self.module is None:
py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int my_array[7];
""")
@@ -171,6 +175,8 @@ class TestOwnLib(object):
for i in range(7):
assert ownlib.my_array[i] == i
assert len(ownlib.my_array) == 7
+ if self.Backend is CTypesBackend:
+ py.test.skip("not supported by the ctypes backend")
ownlib.my_array = list(range(10, 17))
for i in range(7):
assert ownlib.my_array[i] == 10 + i
@@ -181,7 +187,9 @@ class TestOwnLib(object):
def test_my_array_no_length(self):
if self.module is None:
py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI()
+ if self.Backend is CTypesBackend:
+ py.test.skip("not supported by the ctypes backend")
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int my_array[];
""")
@@ -199,7 +207,7 @@ class TestOwnLib(object):
def test_keepalive_lib(self):
if self.module is None:
py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int test_getting_errno(void);
""")
@@ -217,7 +225,7 @@ class TestOwnLib(object):
def test_keepalive_ffi(self):
if self.module is None:
py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
int test_getting_errno(void);
""")
@@ -237,7 +245,7 @@ class TestOwnLib(object):
def test_struct_by_value(self):
if self.module is None:
py.test.skip("fix the auto-generation of the tiny test lib")
- ffi = FFI()
+ ffi = FFI(backend=self.Backend())
ffi.cdef("""
typedef struct {
long x;
diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py
index 9a8d671..73eb5c3 100644
--- a/testing/cffi0/test_verify.py
+++ b/testing/cffi0/test_verify.py
@@ -920,6 +920,15 @@ def test_access_callback_function_typedef():
lib.cb = my_callback
assert lib.foo(4) == 887
+def test_ctypes_backend_forces_generic_engine():
+ from cffi.backend_ctypes import CTypesBackend
+ ffi = FFI(backend=CTypesBackend())
+ ffi.cdef("int func(int a);")
+ lib = ffi.verify("int func(int a) { return a * 42; }")
+ assert not hasattr(lib, '_cffi_python_module')
+ assert hasattr(lib, '_cffi_generic_module')
+ assert lib.func(100) == 4200
+
def test_call_with_struct_ptr():
ffi = FFI()
ffi.cdef("typedef struct { int x; ...; } foo_t; int foo(foo_t *);")