cffi-1.11.5/ 0000755 0001750 0001750 00000000000 13245320130 012723 5 ustar arigo arigo 0000000 0000000 cffi-1.11.5/setup.py 0000644 0001750 0001750 00000021060 13245320115 014437 0 ustar arigo arigo 0000000 0000000 import sys, os
import subprocess
import errno
# on Windows we give up and always import setuptools early to fix things for us
if sys.platform == "win32":
import setuptools
sources = ['c/_cffi_backend.c']
libraries = ['ffi']
include_dirs = ['/usr/include/ffi',
'/usr/include/libffi'] # may be changed by pkg-config
define_macros = []
library_dirs = []
extra_compile_args = []
extra_link_args = []
def _ask_pkg_config(resultlist, option, result_prefix='', sysroot=False):
pkg_config = os.environ.get('PKG_CONFIG','pkg-config')
try:
p = subprocess.Popen([pkg_config, option, 'libffi'],
stdout=subprocess.PIPE)
except OSError as e:
if e.errno not in [errno.ENOENT, errno.EACCES]:
raise
else:
t = p.stdout.read().decode().strip()
p.stdout.close()
if p.wait() == 0:
res = t.split()
# '-I/usr/...' -> '/usr/...'
for x in res:
assert x.startswith(result_prefix)
res = [x[len(result_prefix):] for x in res]
#print 'PKG_CONFIG:', option, res
#
sysroot = sysroot and os.environ.get('PKG_CONFIG_SYSROOT_DIR', '')
if sysroot:
# old versions of pkg-config don't support this env var,
# so here we emulate its effect if needed
res = [path if path.startswith(sysroot)
else sysroot + path
for path in res]
#
resultlist[:] = res
def no_working_compiler_found():
sys.stderr.write("""
No working compiler found, or bogus compiler options passed to
the compiler from Python's standard "distutils" module. See
the error messages above. Likely, the problem is not related
to CFFI but generic to the setup.py of any Python package that
tries to compile C code. (Hints: on OS/X 10.8, for errors about
-mno-fused-madd see http://stackoverflow.com/questions/22313407/
Otherwise, see https://wiki.python.org/moin/CompLangPython or
the IRC channel #python on irc.freenode.net.)\n""")
sys.exit(1)
def get_config():
from distutils.core import Distribution
from distutils.sysconfig import get_config_vars
get_config_vars() # workaround for a bug of distutils, e.g. on OS/X
config = Distribution().get_command_obj('config')
return config
def ask_supports_thread():
config = get_config()
ok = (sys.platform != 'win32' and
config.try_compile('__thread int some_threadlocal_variable_42;'))
if ok:
define_macros.append(('USE__THREAD', None))
else:
ok1 = config.try_compile('int some_regular_variable_42;')
if not ok1:
no_working_compiler_found()
sys.stderr.write("Note: will not use '__thread' in the C code\n")
_safe_to_ignore()
def ask_supports_sync_synchronize():
if sys.platform == 'win32':
return
config = get_config()
ok = config.try_link('int main(void) { __sync_synchronize(); return 0; }')
if ok:
define_macros.append(('HAVE_SYNC_SYNCHRONIZE', None))
else:
sys.stderr.write("Note: will not use '__sync_synchronize()'"
" in the C code\n")
_safe_to_ignore()
def _safe_to_ignore():
sys.stderr.write("***** The above error message can be safely ignored.\n\n")
def uses_msvc():
config = get_config()
return config.try_compile('#ifndef _MSC_VER\n#error "not MSVC"\n#endif')
def use_pkg_config():
if sys.platform == 'darwin' and os.path.exists('/usr/local/bin/brew'):
use_homebrew_for_libffi()
_ask_pkg_config(include_dirs, '--cflags-only-I', '-I', sysroot=True)
_ask_pkg_config(extra_compile_args, '--cflags-only-other')
_ask_pkg_config(library_dirs, '--libs-only-L', '-L', sysroot=True)
_ask_pkg_config(extra_link_args, '--libs-only-other')
_ask_pkg_config(libraries, '--libs-only-l', '-l')
def use_homebrew_for_libffi():
# We can build by setting:
# PKG_CONFIG_PATH = $(brew --prefix libffi)/lib/pkgconfig
with os.popen('brew --prefix libffi') as brew_prefix_cmd:
prefix = brew_prefix_cmd.read().strip()
pkgconfig = os.path.join(prefix, 'lib', 'pkgconfig')
os.environ['PKG_CONFIG_PATH'] = (
os.environ.get('PKG_CONFIG_PATH', '') + ':' + pkgconfig)
if sys.platform == 'win32' and uses_msvc():
COMPILE_LIBFFI = 'c/libffi_msvc' # from the CPython distribution
else:
COMPILE_LIBFFI = None
if COMPILE_LIBFFI:
assert os.path.isdir(COMPILE_LIBFFI), "directory not found!"
include_dirs[:] = [COMPILE_LIBFFI]
libraries[:] = []
_filenames = [filename.lower() for filename in os.listdir(COMPILE_LIBFFI)]
_filenames = [filename for filename in _filenames
if filename.endswith('.c')]
if sys.maxsize > 2**32:
# 64-bit: unlist win32.c, and add instead win64.obj. If the obj
# happens to get outdated at some point in the future, you need to
# rebuild it manually from win64.asm.
_filenames.remove('win32.c')
extra_link_args.append(os.path.join(COMPILE_LIBFFI, 'win64.obj'))
sources.extend(os.path.join(COMPILE_LIBFFI, filename)
for filename in _filenames)
else:
use_pkg_config()
ask_supports_thread()
ask_supports_sync_synchronize()
if 'freebsd' in sys.platform:
include_dirs.append('/usr/local/include')
if 'darwin' in sys.platform:
try:
p = subprocess.Popen(['xcrun', '--show-sdk-path'],
stdout=subprocess.PIPE)
except OSError as e:
if e.errno not in [errno.ENOENT, errno.EACCES]:
raise
else:
t = p.stdout.read().decode().strip()
p.stdout.close()
if p.wait() == 0:
include_dirs.append(t + '/usr/include/ffi')
if __name__ == '__main__':
from setuptools import setup, Distribution, Extension
class CFFIDistribution(Distribution):
def has_ext_modules(self):
# Event if we don't have extension modules (e.g. on PyPy) we want to
# claim that we do so that wheels get properly tagged as Python
# specific. (thanks dstufft!)
return True
# On PyPy, cffi is preinstalled and it is not possible, at least for now,
# to install a different version. We work around it by making the setup()
# arguments mostly empty in this case.
cpython = ('_cffi_backend' not in sys.builtin_module_names)
setup(
name='cffi',
description='Foreign Function Interface for Python calling C code.',
long_description="""
CFFI
====
Foreign Function Interface for Python calling C code.
Please see the `Documentation `_.
Contact
-------
`Mailing list `_
""",
version='1.11.5',
packages=['cffi'] if cpython else [],
package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h',
'_embedding.h', '_cffi_errors.h']}
if cpython else {},
zip_safe=False,
url='http://cffi.readthedocs.org',
author='Armin Rigo, Maciej Fijalkowski',
author_email='python-cffi@googlegroups.com',
license='MIT',
distclass=CFFIDistribution,
ext_modules=[Extension(
name='_cffi_backend',
include_dirs=include_dirs,
sources=sources,
libraries=libraries,
define_macros=define_macros,
library_dirs=library_dirs,
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
)] if cpython else [],
install_requires=[
'pycparser',
] if cpython else [],
entry_points = {
"distutils.setup_keywords": [
"cffi_modules = cffi.setuptools_ext:cffi_modules",
],
} if cpython else {},
classifiers=[
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
],
)
cffi-1.11.5/cffi.egg-info/ 0000755 0001750 0001750 00000000000 13245320130 015324 5 ustar arigo arigo 0000000 0000000 cffi-1.11.5/cffi.egg-info/not-zip-safe 0000644 0001750 0001750 00000000001 13245320130 017552 0 ustar arigo arigo 0000000 0000000
cffi-1.11.5/cffi.egg-info/top_level.txt 0000644 0001750 0001750 00000000023 13245320130 020051 0 ustar arigo arigo 0000000 0000000 _cffi_backend
cffi
cffi-1.11.5/cffi.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 13245320130 021372 0 ustar arigo arigo 0000000 0000000
cffi-1.11.5/cffi.egg-info/entry_points.txt 0000644 0001750 0001750 00000000114 13245320130 020616 0 ustar arigo arigo 0000000 0000000 [distutils.setup_keywords]
cffi_modules = cffi.setuptools_ext:cffi_modules
cffi-1.11.5/cffi.egg-info/SOURCES.txt 0000644 0001750 0001750 00000011424 13245320130 017212 0 ustar arigo arigo 0000000 0000000 AUTHORS
LICENSE
MANIFEST.in
README.md
setup.py
setup_base.py
c/_cffi_backend.c
c/call_python.c
c/cdlopen.c
c/cffi1_module.c
c/cglob.c
c/commontypes.c
c/ffi_obj.c
c/file_emulator.h
c/lib_obj.c
c/malloc_closure.h
c/minibuffer.h
c/misc_thread_common.h
c/misc_thread_posix.h
c/misc_win32.h
c/parse_c_type.c
c/realize_c_type.c
c/test_c.py
c/wchar_helper.h
c/wchar_helper_3.h
c/libffi_msvc/ffi.c
c/libffi_msvc/ffi.h
c/libffi_msvc/ffi_common.h
c/libffi_msvc/fficonfig.h
c/libffi_msvc/ffitarget.h
c/libffi_msvc/prep_cif.c
c/libffi_msvc/types.c
c/libffi_msvc/win32.c
c/libffi_msvc/win64.asm
c/libffi_msvc/win64.obj
cffi/__init__.py
cffi/_cffi_errors.h
cffi/_cffi_include.h
cffi/_embedding.h
cffi/api.py
cffi/backend_ctypes.py
cffi/cffi_opcode.py
cffi/commontypes.py
cffi/cparser.py
cffi/error.py
cffi/ffiplatform.py
cffi/lock.py
cffi/model.py
cffi/parse_c_type.h
cffi/recompiler.py
cffi/setuptools_ext.py
cffi/vengine_cpy.py
cffi/vengine_gen.py
cffi/verifier.py
cffi.egg-info/PKG-INFO
cffi.egg-info/SOURCES.txt
cffi.egg-info/dependency_links.txt
cffi.egg-info/entry_points.txt
cffi.egg-info/not-zip-safe
cffi.egg-info/requires.txt
cffi.egg-info/top_level.txt
demo/_curses.py
demo/_curses_build.py
demo/_curses_setup.py
demo/api.py
demo/bsdopendirtype.py
demo/bsdopendirtype_build.py
demo/bsdopendirtype_setup.py
demo/btrfs-snap.py
demo/cffi-cocoa.py
demo/embedding.py
demo/embedding_test.c
demo/extern_python.py
demo/extern_python_varargs.py
demo/fastcsv.py
demo/gmp.py
demo/gmp_build.py
demo/manual.c
demo/manual2.py
demo/pwuid.py
demo/pwuid_build.py
demo/py.cleanup
demo/pyobj.py
demo/readdir.py
demo/readdir2.py
demo/readdir2_build.py
demo/readdir2_setup.py
demo/readdir_build.py
demo/readdir_ctypes.py
demo/readdir_setup.py
demo/recopendirtype.py
demo/recopendirtype_build.py
demo/setup_manual.py
demo/winclipboard.py
demo/winclipboard_build.py
demo/xclient.py
demo/xclient_build.py
doc/Makefile
doc/make.bat
doc/misc/design.rst
doc/misc/grant-cffi-1.0.rst
doc/misc/parse_c_type.rst
doc/source/cdef.rst
doc/source/conf.py
doc/source/embedding.rst
doc/source/goals.rst
doc/source/index.rst
doc/source/installation.rst
doc/source/overview.rst
doc/source/ref.rst
doc/source/using.rst
doc/source/whatsnew.rst
testing/__init__.py
testing/support.py
testing/udir.py
testing/cffi0/__init__.py
testing/cffi0/backend_tests.py
testing/cffi0/callback_in_thread.py
testing/cffi0/test_cdata.py
testing/cffi0/test_ctypes.py
testing/cffi0/test_ffi_backend.py
testing/cffi0/test_function.py
testing/cffi0/test_model.py
testing/cffi0/test_ownlib.py
testing/cffi0/test_parsing.py
testing/cffi0/test_platform.py
testing/cffi0/test_unicode_literals.py
testing/cffi0/test_verify.py
testing/cffi0/test_verify2.py
testing/cffi0/test_version.py
testing/cffi0/test_vgen.py
testing/cffi0/test_vgen2.py
testing/cffi0/test_zdistutils.py
testing/cffi0/test_zintegration.py
testing/cffi0/snippets/distutils_module/setup.py
testing/cffi0/snippets/distutils_module/snip_basic_verify.py
testing/cffi0/snippets/distutils_package_1/setup.py
testing/cffi0/snippets/distutils_package_1/snip_basic_verify1/__init__.py
testing/cffi0/snippets/distutils_package_2/setup.py
testing/cffi0/snippets/distutils_package_2/snip_basic_verify2/__init__.py
testing/cffi0/snippets/infrastructure/setup.py
testing/cffi0/snippets/infrastructure/snip_infrastructure/__init__.py
testing/cffi0/snippets/setuptools_module/setup.py
testing/cffi0/snippets/setuptools_module/snip_setuptools_verify.py
testing/cffi0/snippets/setuptools_package_1/setup.py
testing/cffi0/snippets/setuptools_package_1/snip_setuptools_verify1/__init__.py
testing/cffi0/snippets/setuptools_package_2/setup.py
testing/cffi0/snippets/setuptools_package_2/snip_setuptools_verify2/__init__.py
testing/cffi1/__init__.py
testing/cffi1/test_cffi_binary.py
testing/cffi1/test_commontypes.py
testing/cffi1/test_dlopen.py
testing/cffi1/test_dlopen_unicode_literals.py
testing/cffi1/test_ffi_obj.py
testing/cffi1/test_new_ffi_1.py
testing/cffi1/test_parse_c_type.py
testing/cffi1/test_re_python.py
testing/cffi1/test_realize_c_type.py
testing/cffi1/test_recompiler.py
testing/cffi1/test_unicode_literals.py
testing/cffi1/test_verify1.py
testing/cffi1/test_zdist.py
testing/embedding/__init__.py
testing/embedding/add1-test.c
testing/embedding/add1.py
testing/embedding/add2-test.c
testing/embedding/add2.py
testing/embedding/add3.py
testing/embedding/add_recursive-test.c
testing/embedding/add_recursive.py
testing/embedding/empty.py
testing/embedding/initerror.py
testing/embedding/perf-test.c
testing/embedding/perf.py
testing/embedding/test_basic.py
testing/embedding/test_performance.py
testing/embedding/test_recursive.py
testing/embedding/test_thread.py
testing/embedding/test_tlocal.py
testing/embedding/thread-test.h
testing/embedding/thread1-test.c
testing/embedding/thread2-test.c
testing/embedding/thread3-test.c
testing/embedding/tlocal-test.c
testing/embedding/tlocal.py cffi-1.11.5/cffi.egg-info/requires.txt 0000644 0001750 0001750 00000000012 13245320130 017715 0 ustar arigo arigo 0000000 0000000 pycparser
cffi-1.11.5/cffi.egg-info/PKG-INFO 0000644 0001750 0001750 00000002340 13245320130 016420 0 ustar arigo arigo 0000000 0000000 Metadata-Version: 1.1
Name: cffi
Version: 1.11.5
Summary: Foreign Function Interface for Python calling C code.
Home-page: http://cffi.readthedocs.org
Author: Armin Rigo, Maciej Fijalkowski
Author-email: python-cffi@googlegroups.com
License: MIT
Description-Content-Type: UNKNOWN
Description:
CFFI
====
Foreign Function Interface for Python calling C code.
Please see the `Documentation `_.
Contact
-------
`Mailing list `_
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.2
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
cffi-1.11.5/testing/ 0000755 0001750 0001750 00000000000 13245320130 014400 5 ustar arigo arigo 0000000 0000000 cffi-1.11.5/testing/cffi0/ 0000755 0001750 0001750 00000000000 13245320130 015367 5 ustar arigo arigo 0000000 0000000 cffi-1.11.5/testing/cffi0/test_zintegration.py 0000644 0001750 0001750 00000014621 13245320115 021524 0 ustar arigo arigo 0000000 0000000 import py, os, sys, shutil
import subprocess
from testing.udir import udir
if sys.platform == 'win32':
py.test.skip('snippets do not run on win32')
if sys.version_info < (2, 7):
py.test.skip('fails e.g. on a Debian/Ubuntu which patches virtualenv'
' in a non-2.6-friendly way')
def create_venv(name):
tmpdir = udir.join(name)
try:
subprocess.check_call(['virtualenv',
#'--never-download', <= could be added, but causes failures
# in random cases on random machines
'-p', os.path.abspath(sys.executable),
str(tmpdir)])
except OSError as e:
py.test.skip("Cannot execute virtualenv: %s" % (e,))
site_packages = None
for dirpath, dirnames, filenames in os.walk(str(tmpdir)):
if os.path.basename(dirpath) == 'site-packages':
site_packages = dirpath
break
paths = ""
if site_packages:
try:
from cffi import _pycparser
modules = ('cffi', '_cffi_backend')
except ImportError:
modules = ('cffi', '_cffi_backend', 'pycparser')
try:
import ply
except ImportError:
pass
else:
modules += ('ply',) # needed for older versions of pycparser
paths = []
for module in modules:
target = __import__(module, None, None, [])
if not hasattr(target, '__file__'): # for _cffi_backend on pypy
continue
src = os.path.abspath(target.__file__)
for end in ['__init__.pyc', '__init__.pyo', '__init__.py']:
if src.lower().endswith(end):
src = src[:-len(end)-1]
break
paths.append(os.path.dirname(src))
paths = os.pathsep.join(paths)
return tmpdir, paths
SNIPPET_DIR = py.path.local(__file__).join('..', 'snippets')
def really_run_setup_and_program(dirname, venv_dir_and_paths, python_snippet):
venv_dir, paths = venv_dir_and_paths
def remove(dir):
dir = str(SNIPPET_DIR.join(dirname, dir))
shutil.rmtree(dir, ignore_errors=True)
remove('build')
remove('__pycache__')
for basedir in os.listdir(str(SNIPPET_DIR.join(dirname))):
remove(os.path.join(basedir, '__pycache__'))
olddir = os.getcwd()
python_f = udir.join('x.py')
python_f.write(py.code.Source(python_snippet))
try:
os.chdir(str(SNIPPET_DIR.join(dirname)))
if os.name == 'nt':
bindir = 'Scripts'
else:
bindir = 'bin'
vp = str(venv_dir.join(bindir).join('python'))
env = os.environ.copy()
env['PYTHONPATH'] = paths
subprocess.check_call((vp, 'setup.py', 'clean'), env=env)
subprocess.check_call((vp, 'setup.py', 'install'), env=env)
subprocess.check_call((vp, str(python_f)), env=env)
finally:
os.chdir(olddir)
def run_setup_and_program(dirname, python_snippet):
venv_dir = create_venv(dirname + '-cpy')
really_run_setup_and_program(dirname, venv_dir, python_snippet)
#
sys._force_generic_engine_ = True
try:
venv_dir = create_venv(dirname + '-gen')
really_run_setup_and_program(dirname, venv_dir, python_snippet)
finally:
del sys._force_generic_engine_
# the two files lextab.py and yacctab.py are created by not-correctly-
# installed versions of pycparser.
assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'lextab.py')))
assert not os.path.exists(str(SNIPPET_DIR.join(dirname, 'yacctab.py')))
class TestZIntegration(object):
def teardown_class(self):
if udir.isdir():
udir.remove(ignore_errors=True)
udir.ensure(dir=1)
def test_infrastructure(self):
run_setup_and_program('infrastructure', '''
import snip_infrastructure
assert snip_infrastructure.func() == 42
''')
def test_distutils_module(self):
run_setup_and_program("distutils_module", '''
import snip_basic_verify
p = snip_basic_verify.C.getpwuid(0)
assert snip_basic_verify.ffi.string(p.pw_name) == b"root"
''')
def test_distutils_package_1(self):
run_setup_and_program("distutils_package_1", '''
import snip_basic_verify1
p = snip_basic_verify1.C.getpwuid(0)
assert snip_basic_verify1.ffi.string(p.pw_name) == b"root"
''')
def test_distutils_package_2(self):
run_setup_and_program("distutils_package_2", '''
import snip_basic_verify2
p = snip_basic_verify2.C.getpwuid(0)
assert snip_basic_verify2.ffi.string(p.pw_name) == b"root"
''')
def test_setuptools_module(self):
run_setup_and_program("setuptools_module", '''
import snip_setuptools_verify
p = snip_setuptools_verify.C.getpwuid(0)
assert snip_setuptools_verify.ffi.string(p.pw_name) == b"root"
''')
def test_setuptools_package_1(self):
run_setup_and_program("setuptools_package_1", '''
import snip_setuptools_verify1
p = snip_setuptools_verify1.C.getpwuid(0)
assert snip_setuptools_verify1.ffi.string(p.pw_name) == b"root"
''')
def test_setuptools_package_2(self):
run_setup_and_program("setuptools_package_2", '''
import snip_setuptools_verify2
p = snip_setuptools_verify2.C.getpwuid(0)
assert snip_setuptools_verify2.ffi.string(p.pw_name) == b"root"
''')
def test_set_py_limited_api(self):
from cffi.setuptools_ext import _set_py_limited_api
try:
import setuptools
except ImportError as e:
py.test.skip(str(e))
orig_version = setuptools.__version__
expecting_limited_api = not hasattr(sys, 'gettotalrefcount')
try:
setuptools.__version__ = '26.0.0'
from setuptools import Extension
kwds = _set_py_limited_api(Extension, {})
assert kwds.get('py_limited_api', False) == expecting_limited_api
setuptools.__version__ = '25.0'
kwds = _set_py_limited_api(Extension, {})
assert kwds.get('py_limited_api', False) == False
setuptools.__version__ = 'development'
kwds = _set_py_limited_api(Extension, {})
assert kwds.get('py_limited_api', False) == expecting_limited_api
finally:
setuptools.__version__ = orig_version
cffi-1.11.5/testing/cffi0/test_function.py 0000644 0001750 0001750 00000043646 13245320115 020645 0 ustar arigo arigo 0000000 0000000 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
from .backend_tests import needs_dlopen_none
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
lib_m = 'm'
if sys.platform == 'win32':
#there is a small chance this fails on Mingw via environ $CC
import distutils.ccompiler
if distutils.ccompiler.get_default_compiler() == 'msvc':
lib_m = 'msvcrt'
class TestFunction(object):
Backend = CTypesBackend
def test_sin(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
double sin(double x);
""")
m = ffi.dlopen(lib_m)
x = m.sin(1.23)
assert x == math.sin(1.23)
def test_sinf(self):
if sys.platform == 'win32':
py.test.skip("no sinf found in the Windows stdlib")
ffi = FFI(backend=self.Backend())
ffi.cdef("""
float sinf(float x);
""")
m = ffi.dlopen(lib_m)
x = m.sinf(1.23)
assert type(x) is float
assert x != math.sin(1.23) # rounding effects
assert abs(x - math.sin(1.23)) < 1E-6
def test_sin_no_return_value(self):
# check that 'void'-returning functions work too
ffi = FFI(backend=self.Backend())
ffi.cdef("""
void sin(double x);
""")
m = ffi.dlopen(lib_m)
x = m.sin(1.23)
assert x is None
def test_dlopen_filename(self):
path = ctypes.util.find_library(lib_m)
if not path:
py.test.skip("%s not found" % lib_m)
ffi = FFI(backend=self.Backend())
ffi.cdef("""
double cos(double x);
""")
m = ffi.dlopen(path)
x = m.cos(1.23)
assert x == math.cos(1.23)
m = ffi.dlopen(os.path.basename(path))
x = m.cos(1.23)
assert x == math.cos(1.23)
def test_dlopen_flags(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
double cos(double x);
""")
m = ffi.dlopen(lib_m, ffi.RTLD_LAZY | ffi.RTLD_LOCAL)
x = m.cos(1.23)
assert x == math.cos(1.23)
def test_dlopen_constant(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
#define FOOBAR 42
static const float baz = 42.5; /* not visible */
double sin(double x);
""")
m = ffi.dlopen(lib_m)
assert m.FOOBAR == 42
py.test.raises(NotImplementedError, "m.baz")
def test_tlsalloc(self):
if sys.platform != 'win32':
py.test.skip("win32 only")
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()
assert x != 0
y = lib.TlsFree(x)
assert y != 0
def test_fputs(self):
if not sys.platform.startswith('linux'):
py.test.skip("probably no symbol 'stderr' in the lib")
ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fputs(const char *, void *);
void *stderr;
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
ffi.C.fputs # fetch before capturing, for easier debugging
with FdWriteCapture() as fd:
ffi.C.fputs(b"hello\n", ffi.C.stderr)
ffi.C.fputs(b" world\n", ffi.C.stderr)
res = fd.getvalue()
assert res == b'hello\n world\n'
def test_fputs_without_const(self):
if not sys.platform.startswith('linux'):
py.test.skip("probably no symbol 'stderr' in the lib")
ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fputs(char *, void *);
void *stderr;
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
ffi.C.fputs # fetch before capturing, for easier debugging
with FdWriteCapture() as fd:
ffi.C.fputs(b"hello\n", ffi.C.stderr)
ffi.C.fputs(b" world\n", ffi.C.stderr)
res = fd.getvalue()
assert res == b'hello\n world\n'
def test_vararg(self):
if not sys.platform.startswith('linux'):
py.test.skip("probably no symbol 'stderr' in the lib")
ffi = FFI(backend=self.Backend())
ffi.cdef("""
int fprintf(void *, const char *format, ...);
void *stderr;
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
with FdWriteCapture() as fd:
ffi.C.fprintf(ffi.C.stderr, b"hello with no arguments\n")
ffi.C.fprintf(ffi.C.stderr,
b"hello, %s!\n", ffi.new("char[]", b"world"))
ffi.C.fprintf(ffi.C.stderr,
ffi.new("char[]", b"hello, %s!\n"),
ffi.new("char[]", b"world2"))
ffi.C.fprintf(ffi.C.stderr,
b"hello int %d long %ld long long %lld\n",
ffi.cast("int", 42),
ffi.cast("long", 84),
ffi.cast("long long", 168))
ffi.C.fprintf(ffi.C.stderr, b"hello %p\n", ffi.NULL)
res = fd.getvalue()
assert res == (b"hello with no arguments\n"
b"hello, world!\n"
b"hello, world2!\n"
b"hello int 42 long 84 long long 168\n"
b"hello (nil)\n")
def test_must_specify_type_of_vararg(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
int printf(const char *format, ...);
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
e = py.test.raises(TypeError, ffi.C.printf, b"hello %d\n", 42)
assert str(e.value) == ("argument 2 passed in the variadic part "
"needs to be a cdata object (got int)")
def test_function_has_a_c_type(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
int puts(const char *);
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
fptr = ffi.C.puts
assert ffi.typeof(fptr) == ffi.typeof("int(*)(const char*)")
if self.Backend is CTypesBackend:
assert repr(fptr).startswith("" % (cb,)
res = fptr(b"Hello")
assert res == 42
#
if not sys.platform.startswith('linux'):
py.test.skip("probably no symbol 'stderr' in the lib")
ffi.cdef("""
int fputs(const char *, void *);
void *stderr;
""")
needs_dlopen_none()
ffi.C = ffi.dlopen(None)
fptr = ffi.cast("int(*)(const char *txt, void *)", ffi.C.fputs)
assert fptr == ffi.C.fputs
assert repr(fptr).startswith(" lambda (closure) -> container -> callback
return callback
class Data(object):
pass
ffi = FFI(backend=self.Backend())
data = Data()
callback = make_callback(data)
wr = weakref.ref(data)
del callback, data
for i in range(3):
if wr() is not None:
import gc; gc.collect()
assert wr() is None # 'data' does not leak
def test_windows_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")
ffi = FFI(backend=self.Backend())
ffi.cdef("""
BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
""")
m = ffi.dlopen("Kernel32.dll")
p_freq = ffi.new("LONGLONG *")
res = m.QueryPerformanceFrequency(p_freq)
assert res != 0
assert p_freq[0] != 0
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(backend=self.Backend())
ffi.cdef("""
BOOL QueryPerformanceFrequency(LONGLONG *lpFrequency);
""")
m = ffi.dlopen("Kernel32.dll")
tp = ffi.typeof(m.QueryPerformanceFrequency)
assert str(tp) == ""
#
ffi = FFI(backend=self.Backend())
ffi.cdef("""
BOOL __cdecl QueryPerformanceFrequency(LONGLONG *lpFrequency);
""")
m = ffi.dlopen("Kernel32.dll")
tpc = ffi.typeof(m.QueryPerformanceFrequency)
assert tpc is tp
#
ffi = FFI(backend=self.Backend())
ffi.cdef("""
BOOL WINAPI QueryPerformanceFrequency(LONGLONG *lpFrequency);
""")
m = ffi.dlopen("Kernel32.dll")
tps = ffi.typeof(m.QueryPerformanceFrequency)
if win64:
assert tps is tpc
else:
assert tps is not tpc
assert str(tps) == ""
#
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")
tps = ffi.typeof("fns_t")
assert str(tpc) == ""
if win64:
assert tps is tpc
else:
assert str(tps) == ""
#
fnc = ffi.cast("fnc_t", 0)
fns = ffi.cast("fns_t", 0)
ffi.new("fnc_t[]", [fnc])
if not win64:
py.test.raises(TypeError, ffi.new, "fnc_t[]", [fns])
py.test.raises(TypeError, ffi.new, "fns_t[]", [fnc])
ffi.new("fns_t[]", [fns])
def test_stdcall_only_on_windows(self):
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 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))
x = m.sin(1.23)
assert x == math.sin(1.23)
def test_dir_on_dlopen_lib(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
typedef enum { MYE1, MYE2 } myenum_t;
double myfunc(double);
double myvar;
const double myconst;
#define MYFOO 42
""")
m = ffi.dlopen(lib_m)
assert dir(m) == ['MYE1', 'MYE2', 'MYFOO', 'myconst', 'myfunc', 'myvar']
def test_dlclose(self):
if self.Backend is CTypesBackend:
py.test.skip("not with the ctypes backend")
ffi = FFI(backend=self.Backend())
ffi.cdef("int foobar(void); int foobaz;")
lib = ffi.dlopen(lib_m)
ffi.dlclose(lib)
e = py.test.raises(ValueError, ffi.dlclose, lib)
assert str(e.value).startswith("library '")
assert str(e.value).endswith("' has already been closed")
e = py.test.raises(ValueError, getattr, lib, 'foobar')
assert str(e.value).startswith("library '")
assert str(e.value).endswith("' has already been closed")
e = py.test.raises(ValueError, getattr, lib, 'foobaz')
assert str(e.value).startswith("library '")
assert str(e.value).endswith("' has already been closed")
e = py.test.raises(ValueError, setattr, lib, 'foobaz', 42)
assert str(e.value).startswith("library '")
assert str(e.value).endswith("' has already been closed")
cffi-1.11.5/testing/cffi0/test_verify2.py 0000644 0001750 0001750 00000000474 13245320115 020376 0 ustar arigo arigo 0000000 0000000 from .test_verify import *
# This test file runs normally after test_verify. We only clean up the .c
# sources, to check that it also works when we have only the .so. The
# tests should run much faster than test_verify.
def setup_module():
import cffi.verifier
cffi.verifier.cleanup_tmpdir(keep_so=True)
cffi-1.11.5/testing/cffi0/test_parsing.py 0000644 0001750 0001750 00000037006 13245320115 020454 0 ustar arigo arigo 0000000 0000000 import py, sys, re
from cffi import FFI, FFIError, CDefError, VerificationError
from .backend_tests import needs_dlopen_none
class FakeBackend(object):
def nonstandard_integer_types(self):
return {}
def sizeof(self, name):
return 1
def load_library(self, name, flags):
if sys.platform == 'win32':
assert name is None or "msvcr" in name
else:
assert name is None or "libc" in name or "libm" in name
return FakeLibrary()
def new_function_type(self, args, result, has_varargs):
args = [arg.cdecl for arg in args]
result = result.cdecl
return FakeType(
'' % (', '.join(args), result, has_varargs))
def new_primitive_type(self, name):
assert name == name.lower()
return FakeType('<%s>' % name)
def new_pointer_type(self, itemtype):
return FakeType('' % (itemtype,))
def new_struct_type(self, name):
return FakeStruct(name)
def complete_struct_or_union(self, s, fields, tp=None,
totalsize=-1, totalalignment=-1, sflags=0):
assert isinstance(s, FakeStruct)
s.fields = fields
def new_array_type(self, ptrtype, length):
return FakeType('' % (ptrtype, length))
def new_void_type(self):
return FakeType("")
def cast(self, x, y):
return 'casted!'
def _get_types(self):
return "CData", "CType"
buffer = "buffer type"
class FakeType(object):
def __init__(self, cdecl):
self.cdecl = cdecl
def __str__(self):
return self.cdecl
class FakeStruct(object):
def __init__(self, name):
self.name = name
def __str__(self):
return ', '.join([str(y) + str(x) for x, y, z in self.fields])
class FakeLibrary(object):
def load_function(self, BType, name):
return FakeFunction(BType, name)
class FakeFunction(object):
def __init__(self, BType, name):
self.BType = str(BType)
self.name = name
lib_m = "m"
if sys.platform == 'win32':
#there is a small chance this fails on Mingw via environ $CC
import distutils.ccompiler
if distutils.ccompiler.get_default_compiler() == 'msvc':
lib_m = 'msvcrt'
def test_simple():
ffi = FFI(backend=FakeBackend())
ffi.cdef("double sin(double x);")
m = ffi.dlopen(lib_m)
func = m.sin # should be a callable on real backends
assert func.name == 'sin'
assert func.BType == '), , False>'
def test_pipe():
ffi = FFI(backend=FakeBackend())
ffi.cdef("int pipe(int pipefd[2]);")
needs_dlopen_none()
C = ffi.dlopen(None)
func = C.pipe
assert func.name == 'pipe'
assert func.BType == '>), , False>'
def test_vararg():
ffi = FFI(backend=FakeBackend())
ffi.cdef("short foo(int, ...);")
needs_dlopen_none()
C = ffi.dlopen(None)
func = C.foo
assert func.name == 'foo'
assert func.BType == '), , True>'
def test_no_args():
ffi = FFI(backend=FakeBackend())
ffi.cdef("""
int foo(void);
""")
needs_dlopen_none()
C = ffi.dlopen(None)
assert C.foo.BType == ', False>'
def test_typedef():
ffi = FFI(backend=FakeBackend())
ffi.cdef("""
typedef unsigned int UInt;
typedef UInt UIntReally;
UInt foo(void);
""")
needs_dlopen_none()
C = ffi.dlopen(None)
assert str(ffi.typeof("UIntReally")) == ''
assert C.foo.BType == ', False>'
def test_typedef_more_complex():
ffi = FFI(backend=FakeBackend())
ffi.cdef("""
typedef struct { int a, b; } foo_t, *foo_p;
int foo(foo_p[]);
""")
needs_dlopen_none()
C = ffi.dlopen(None)
assert str(ffi.typeof("foo_t")) == 'a, b'
assert str(ffi.typeof("foo_p")) == 'a, b>'
assert C.foo.BType == ('a, b>>), , False>')
def test_typedef_array_convert_array_to_pointer():
ffi = FFI(backend=FakeBackend())
ffi.cdef("""
typedef int (*fn_t)(int[5]);
""")
with ffi._lock:
type = ffi._parser.parse_type("fn_t")
BType = ffi._get_cached_btype(type)
assert str(BType) == '>), , False>'
def test_remove_comments():
ffi = FFI(backend=FakeBackend())
ffi.cdef("""
double /*comment here*/ sin // blah blah
/* multi-
line-
//comment */ (
// foo
double // bar /* <- ignored, because it's in a comment itself
x, double/*several*//*comment*/y) /*on the same line*/
;
""")
m = ffi.dlopen(lib_m)
func = m.sin
assert func.name == 'sin'
assert func.BType == ', ), , False>'
def test_remove_line_continuation_comments():
ffi = FFI(backend=FakeBackend())
ffi.cdef("""
double // blah \\
more comments
x(void);
double // blah\\\\
y(void);
double // blah\\ \
etc
z(void);
""")
m = ffi.dlopen(lib_m)
m.x
m.y
m.z
def test_line_continuation_in_defines():
ffi = FFI(backend=FakeBackend())
ffi.cdef("""
#define ABC\\
42
#define BCD \\
43
""")
m = ffi.dlopen(lib_m)
assert m.ABC == 42
assert m.BCD == 43
def test_define_not_supported_for_now():
ffi = FFI(backend=FakeBackend())
e = py.test.raises(CDefError, ffi.cdef, '#define FOO "blah"')
assert str(e.value) == (
'only supports one of the following syntax:\n'
' #define FOO ... (literally dot-dot-dot)\n'
' #define FOO NUMBER (with NUMBER an integer'
' constant, decimal/hex/octal)\n'
'got:\n'
' #define FOO "blah"')
def test_unnamed_struct():
ffi = FFI(backend=FakeBackend())
ffi.cdef("typedef struct { int x; } foo_t;\n"
"typedef struct { int y; } *bar_p;\n")
assert 'typedef foo_t' in ffi._parser._declarations
assert 'typedef bar_p' in ffi._parser._declarations
assert 'anonymous foo_t' in ffi._parser._declarations
type_foo = ffi._parser.parse_type("foo_t")
type_bar = ffi._parser.parse_type("bar_p").totype
assert repr(type_foo) == ""
assert repr(type_bar) == ""
py.test.raises(VerificationError, type_bar.get_c_name)
assert type_foo.get_c_name() == "foo_t"
def test_override():
ffi = FFI(backend=FakeBackend())
needs_dlopen_none()
C = ffi.dlopen(None)
ffi.cdef("int foo(void);")
py.test.raises(FFIError, ffi.cdef, "long foo(void);")
assert C.foo.BType == ', False>'
ffi.cdef("long foo(void);", override=True)
assert C.foo.BType == ', False>'
def test_cannot_have_only_variadic_part():
# this checks that we get a sensible error if we try "int foo(...);"
ffi = FFI()
e = py.test.raises(CDefError, ffi.cdef, "int foo(...);")
assert str(e.value) == (
":1: foo: a function with only '(...)' "
"as argument is not correct C")
def test_parse_error():
ffi = FFI()
e = py.test.raises(CDefError, ffi.cdef, " x y z ")
assert str(e.value).startswith(
'cannot parse "x y z"\n:1:')
e = py.test.raises(CDefError, ffi.cdef, "\n\n\n x y z ")
assert str(e.value).startswith(
'cannot parse "x y z"\n:4:')
def test_error_custom_lineno():
ffi = FFI()
e = py.test.raises(CDefError, ffi.cdef, """
# 42 "foobar"
a b c d
""")
assert str(e.value).startswith('parse error\nfoobar:43:')
def test_cannot_declare_enum_later():
ffi = FFI()
e = py.test.raises(NotImplementedError, ffi.cdef,
"typedef enum foo_e foo_t; enum foo_e { AA, BB };")
assert str(e.value) == (
"enum foo_e: the '{}' declaration should appear on the "
"first time the enum is mentioned, not later")
def test_unknown_name():
ffi = FFI()
e = py.test.raises(CDefError, ffi.cast, "foobarbazunknown", 0)
assert str(e.value) == "unknown identifier 'foobarbazunknown'"
e = py.test.raises(CDefError, ffi.cast, "foobarbazunknown*", 0)
assert str(e.value).startswith('cannot parse "foobarbazunknown*"')
e = py.test.raises(CDefError, ffi.cast, "int(*)(foobarbazunknown)", 0)
assert str(e.value).startswith('cannot parse "int(*)(foobarbazunknown)"')
def test_redefine_common_type():
prefix = "" if sys.version_info < (3,) else "b"
ffi = FFI()
ffi.cdef("typedef char FILE;")
assert repr(ffi.cast("FILE", 123)) == "" % prefix
ffi.cdef("typedef char int32_t;")
assert repr(ffi.cast("int32_t", 123)) == "" % prefix
ffi = FFI()
ffi.cdef("typedef int bool, *FILE;")
assert repr(ffi.cast("bool", 123)) == ""
assert re.match(r"",
repr(ffi.cast("FILE", 123)))
ffi = FFI()
ffi.cdef("typedef bool (*fn_t)(bool, bool);") # "bool," but within "( )"
def test_bool():
ffi = FFI()
ffi.cdef("void f(bool);")
#
ffi = FFI()
ffi.cdef("typedef _Bool bool; void f(bool);")
def test_unknown_argument_type():
ffi = FFI()
e = py.test.raises(CDefError, ffi.cdef, "void f(foobarbazzz);")
assert str(e.value) == (":1: f arg 1:"
" unknown type 'foobarbazzz' (if you meant"
" to use the old C syntax of giving untyped"
" arguments, it is not supported)")
def test_void_renamed_as_only_arg():
ffi = FFI()
ffi.cdef("typedef void void_t1;"
"typedef void_t1 void_t;"
"typedef int (*func_t)(void_t);")
assert ffi.typeof("func_t").args == ()
def test_WPARAM_on_windows():
if sys.platform != 'win32':
py.test.skip("Only for Windows")
ffi = FFI()
ffi.cdef("void f(WPARAM);")
#
# WPARAM -> UINT_PTR -> unsigned 32/64-bit integer
ffi = FFI()
value = int(ffi.cast("WPARAM", -42))
assert value == sys.maxsize * 2 - 40
def test__is_constant_globalvar():
for input, expected_output in [
("int a;", False),
("const int a;", True),
("int *a;", False),
("const int *a;", False),
("int const *a;", False),
("int *const a;", True),
("int a[5];", False),
("const int a[5];", False),
("int *a[5];", False),
("const int *a[5];", False),
("int const *a[5];", False),
("int *const a[5];", False),
("int a[5][6];", False),
("const int a[5][6];", False),
]:
ffi = FFI()
ffi.cdef(input)
declarations = ffi._parser._declarations
assert ('constant a' in declarations) == expected_output
assert ('variable a' in declarations) == (not expected_output)
def test_restrict():
from cffi import model
for input, expected_output in [
("int a;", False),
("restrict int a;", True),
("int *a;", False),
]:
ffi = FFI()
ffi.cdef(input)
tp, quals = ffi._parser._declarations['variable a']
assert bool(quals & model.Q_RESTRICT) == expected_output
def test_different_const_funcptr_types():
lst = []
for input in [
"int(*)(int *a)",
"int(*)(int const *a)",
"int(*)(int * const a)",
"int(*)(int const a[])"]:
ffi = FFI(backend=FakeBackend())
lst.append(ffi._parser.parse_type(input))
assert lst[0] != lst[1]
assert lst[0] == lst[2]
assert lst[1] == lst[3]
def test_const_pointer_to_pointer():
from cffi import model
ffi = FFI(backend=FakeBackend())
#
tp, qual = ffi._parser.parse_type_and_quals("char * * (* const)")
assert (str(tp), qual) == ("", model.Q_CONST)
tp, qual = ffi._parser.parse_type_and_quals("char * (* const (*))")
assert (str(tp), qual) == ("", 0)
tp, qual = ffi._parser.parse_type_and_quals("char (* const (* (*)))")
assert (str(tp), qual) == ("", 0)
tp, qual = ffi._parser.parse_type_and_quals("char const * * *")
assert (str(tp), qual) == ("", 0)
tp, qual = ffi._parser.parse_type_and_quals("const char * * *")
assert (str(tp), qual) == ("", 0)
#
tp, qual = ffi._parser.parse_type_and_quals("char * * * const const")
assert (str(tp), qual) == ("", model.Q_CONST)
tp, qual = ffi._parser.parse_type_and_quals("char * * volatile *")
assert (str(tp), qual) == ("", 0)
tp, qual = ffi._parser.parse_type_and_quals("char * volatile restrict * *")
assert (str(tp), qual) == ("", 0)
tp, qual = ffi._parser.parse_type_and_quals("char const volatile * * *")
assert (str(tp), qual) == ("", 0)
tp, qual = ffi._parser.parse_type_and_quals("const char * * *")
assert (str(tp), qual) == ("", 0)
#
tp, qual = ffi._parser.parse_type_and_quals(
"int(char*const*, short****const*)")
assert (str(tp), qual) == (
"", 0)
tp, qual = ffi._parser.parse_type_and_quals(
"char*const*(short*const****)")
assert (str(tp), qual) == (
"", 0)
def test_enum():
ffi = FFI()
ffi.cdef("""
enum Enum { POS = +1, TWO = 2, NIL = 0, NEG = -1, OP = (POS+TWO)-1};
""")
needs_dlopen_none()
C = ffi.dlopen(None)
assert C.POS == 1
assert C.TWO == 2
assert C.NIL == 0
assert C.NEG == -1
assert C.OP == 2
def test_stdcall():
ffi = FFI()
tp = ffi.typeof("int(*)(int __stdcall x(int),"
" long (__cdecl*y)(void),"
" short(WINAPI *z)(short))")
if sys.platform == 'win32' and sys.maxsize < 2**32:
stdcall = '__stdcall '
else:
stdcall = ''
assert str(tp) == (
"" % (stdcall, stdcall))
def test_extern_python():
ffi = FFI()
ffi.cdef("""
int bok(int, int);
extern "Python" int foobar(int, int);
int baz(int, int);
""")
assert sorted(ffi._parser._declarations) == [
'extern_python foobar', 'function baz', 'function bok']
assert (ffi._parser._declarations['function bok'] ==
ffi._parser._declarations['extern_python foobar'] ==
ffi._parser._declarations['function baz'])
def test_extern_python_group():
ffi = FFI()
ffi.cdef("""
int bok(int);
extern "Python" {int foobar(int, int);int bzrrr(int);}
int baz(int, int);
""")
assert sorted(ffi._parser._declarations) == [
'extern_python bzrrr', 'extern_python foobar',
'function baz', 'function bok']
assert (ffi._parser._declarations['function baz'] ==
ffi._parser._declarations['extern_python foobar'] !=
ffi._parser._declarations['function bok'] ==
ffi._parser._declarations['extern_python bzrrr'])
def test_error_invalid_syntax_for_cdef():
ffi = FFI()
e = py.test.raises(CDefError, ffi.cdef, 'void foo(void) {}')
assert str(e.value) == (':1: unexpected : '
'this construct is valid C but not valid in cdef()')
cffi-1.11.5/testing/cffi0/backend_tests.py 0000644 0001750 0001750 00000212003 13245320115 020553 0 ustar arigo arigo 0000000 0000000 import py
import platform
import sys, ctypes
from cffi import FFI, CDefError, FFIError, VerificationMissing
from testing.support import *
SIZE_OF_INT = ctypes.sizeof(ctypes.c_int)
SIZE_OF_LONG = ctypes.sizeof(ctypes.c_long)
SIZE_OF_SHORT = ctypes.sizeof(ctypes.c_short)
SIZE_OF_PTR = ctypes.sizeof(ctypes.c_void_p)
SIZE_OF_WCHAR = ctypes.sizeof(ctypes.c_wchar)
def needs_dlopen_none():
if sys.platform == 'win32' and sys.version_info >= (3,):
py.test.skip("dlopen(None) cannot work on Windows for Python 3")
class BackendTests:
def test_integer_ranges(self):
ffi = FFI(backend=self.Backend())
for (c_type, size) in [('char', 1),
('short', 2),
('short int', 2),
('', 4),
('int', 4),
('long', SIZE_OF_LONG),
('long int', SIZE_OF_LONG),
('long long', 8),
('long long int', 8),
]:
for unsigned in [None, False, True]:
c_decl = {None: '',
False: 'signed ',
True: 'unsigned '}[unsigned] + c_type
if c_decl == 'char' or c_decl == '':
continue
self._test_int_type(ffi, c_decl, size, unsigned)
def test_fixedsize_int(self):
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)
self._test_int_type(ffi, 'intptr_t', SIZE_OF_PTR, False)
self._test_int_type(ffi, 'uintptr_t', SIZE_OF_PTR, True)
self._test_int_type(ffi, 'ptrdiff_t', SIZE_OF_PTR, False)
self._test_int_type(ffi, 'size_t', SIZE_OF_PTR, True)
self._test_int_type(ffi, 'ssize_t', SIZE_OF_PTR, False)
def _test_int_type(self, ffi, c_decl, size, unsigned):
if unsigned:
min = 0
max = (1 << (8*size)) - 1
else:
min = -(1 << (8*size-1))
max = (1 << (8*size-1)) - 1
min = int(min)
max = int(max)
p = ffi.cast(c_decl, min)
assert p == min
assert hash(p) == hash(min)
assert bool(p) is bool(min)
assert int(p) == min
p = ffi.cast(c_decl, max)
assert int(p) == max
p = ffi.cast(c_decl, long(max))
assert int(p) == max
q = ffi.cast(c_decl, min - 1)
assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
q = ffi.cast(c_decl, long(min - 1))
assert ffi.typeof(q) is ffi.typeof(p) and int(q) == max
assert q == p
assert int(q) == int(p)
assert hash(q) == hash(p)
c_decl_ptr = '%s *' % c_decl
py.test.raises(OverflowError, ffi.new, c_decl_ptr, min - 1)
py.test.raises(OverflowError, ffi.new, c_decl_ptr, max + 1)
py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(min - 1))
py.test.raises(OverflowError, ffi.new, c_decl_ptr, long(max + 1))
assert ffi.new(c_decl_ptr, min)[0] == min
assert ffi.new(c_decl_ptr, max)[0] == max
assert ffi.new(c_decl_ptr, long(min))[0] == min
assert ffi.new(c_decl_ptr, long(max))[0] == max
def test_new_unsupported_type(self):
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(backend=self.Backend())
p = ffi.new("int *") # similar to ffi.new("int[1]")
assert p[0] == 0
p[0] = -123
assert p[0] == -123
p = ffi.new("int *", -42)
assert p[0] == -42
assert repr(p) == "" % SIZE_OF_INT
def test_new_array_no_arg(self):
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(backend=self.Backend())
p = ffi.new("int[10]")
p[0] = 42
p[9] = 43
assert p[0] == 42
assert p[9] == 43
py.test.raises(IndexError, "p[10]")
py.test.raises(IndexError, "p[10] = 44")
py.test.raises(IndexError, "p[-1]")
py.test.raises(IndexError, "p[-1] = 44")
def test_new_array_args(self):
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])
assert p[0] == 10
assert p[1] == 20
assert p[2] == 30
assert p[3] == 40
assert p[4] == 50
p = ffi.new("int[4]", [25])
assert p[0] == 25
assert p[1] == 0 # follow C convention rather than LuaJIT's
assert p[2] == 0
assert p[3] == 0
p = ffi.new("int[4]", [ffi.cast("int", -5)])
assert p[0] == -5
assert repr(p) == "" % (4*SIZE_OF_INT)
def test_new_array_varsize(self):
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]")
#
py.test.raises(TypeError, ffi.new, "int[]")
#
p = ffi.new("int[]", [-6, -7]) # a list is all the items, like C
assert p[0] == -6
assert p[1] == -7
py.test.raises(IndexError, "p[2]")
assert repr(p) == "" % (2*SIZE_OF_INT)
#
p = ffi.new("int[]", 0)
py.test.raises(IndexError, "p[0]")
py.test.raises(ValueError, ffi.new, "int[]", -1)
assert repr(p) == ""
def test_pointer_init(self):
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):
if i not in (2, 3):
assert a[i] == ffi.NULL
assert a[2] == a[3] == n
def test_cannot_cast(self):
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(backend=self.Backend())
a = ffi.new("int[4]", [100, 102, 104, 106])
p = ffi.new("int **", a)
assert p[0] == ffi.cast("int *", a)
assert p[0][2] == 104
p = ffi.cast("int *", a)
assert p[0] == 100
assert p[1] == 102
assert p[2] == 104
assert p[3] == 106
# keepalive: a
def test_pointer_direct(self):
ffi = FFI(backend=self.Backend())
p = ffi.cast("int*", 0)
assert p is not None
assert bool(p) is False
assert p == ffi.cast("int*", 0)
assert p != None
assert repr(p) == ""
a = ffi.new("int[]", [123, 456])
p = ffi.cast("int*", a)
assert bool(p) is True
assert p == ffi.cast("int*", a)
assert p != ffi.cast("int*", 0)
assert p[0] == 123
assert p[1] == 456
def test_repr(self):
typerepr = self.TypeRepr
ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { short a, b, c; };")
p = ffi.cast("short unsigned int", 0)
assert repr(p) == ""
assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
p = ffi.cast("unsigned short int", 0)
assert repr(p) == ""
assert repr(ffi.typeof(p)) == typerepr % "unsigned short"
p = ffi.cast("int*", 0)
assert repr(p) == ""
assert repr(ffi.typeof(p)) == typerepr % "int *"
#
p = ffi.new("int*")
assert repr(p) == "" % SIZE_OF_INT
assert repr(ffi.typeof(p)) == typerepr % "int *"
p = ffi.new("int**")
assert repr(p) == "" % SIZE_OF_PTR
assert repr(ffi.typeof(p)) == typerepr % "int * *"
p = ffi.new("int [2]")
assert repr(p) == "" % (2*SIZE_OF_INT)
assert repr(ffi.typeof(p)) == typerepr % "int[2]"
p = ffi.new("int*[2][3]")
assert repr(p) == "" % (
6*SIZE_OF_PTR)
assert repr(ffi.typeof(p)) == typerepr % "int *[2][3]"
p = ffi.new("struct foo *")
assert repr(p) == "" % (
3*SIZE_OF_SHORT)
assert repr(ffi.typeof(p)) == typerepr % "struct foo *"
#
q = ffi.cast("short", -123)
assert repr(q) == ""
assert repr(ffi.typeof(q)) == typerepr % "short"
p = ffi.new("int*")
q = ffi.cast("short*", p)
assert repr(q).startswith(" 2:
assert ffi.new("wchar_t*", u+'\U00012345')[0] == u+'\U00012345'
else:
py.test.raises(TypeError, ffi.new, "wchar_t*", u+'\U00012345')
assert ffi.new("wchar_t*")[0] == u+'\x00'
assert int(ffi.cast("wchar_t", 300)) == 300
assert not bool(ffi.cast("wchar_t", 0))
assert bool(ffi.cast("wchar_t", 1))
assert bool(ffi.cast("wchar_t", 65535))
if SIZE_OF_WCHAR > 2:
assert bool(ffi.cast("wchar_t", 65536))
py.test.raises(TypeError, ffi.new, "wchar_t*", 32)
py.test.raises(TypeError, ffi.new, "wchar_t*", "foo")
#
p = ffi.new("wchar_t[]", [u+'a', u+'b', u+'\u1234'])
assert len(p) == 3
assert p[0] == u+'a'
assert p[1] == u+'b' and type(p[1]) is unicode
assert p[2] == u+'\u1234'
p[0] = u+'x'
assert p[0] == u+'x' and type(p[0]) is unicode
p[1] = u+'\u1357'
assert p[1] == u+'\u1357'
p = ffi.new("wchar_t[]", u+"abcd")
assert len(p) == 5
assert p[4] == u+'\x00'
p = ffi.new("wchar_t[]", u+"a\u1234b")
assert len(p) == 4
assert p[1] == u+'\u1234'
#
p = ffi.new("wchar_t[]", u+'\U00023456')
if SIZE_OF_WCHAR == 2:
assert len(p) == 3
assert p[0] == u+'\ud84d'
assert p[1] == u+'\udc56'
assert p[2] == u+'\x00'
else:
assert len(p) == 2
assert p[0] == u+'\U00023456'
assert p[1] == u+'\x00'
#
p = ffi.new("wchar_t[4]", u+"ab")
assert len(p) == 4
assert [p[i] for i in range(4)] == [u+'a', u+'b', u+'\x00', u+'\x00']
p = ffi.new("wchar_t[2]", u+"ab")
assert len(p) == 2
assert [p[i] for i in range(2)] == [u+'a', u+'b']
py.test.raises(IndexError, ffi.new, "wchar_t[2]", u+"abc")
def test_none_as_null_doesnt_work(self):
ffi = FFI(backend=self.Backend())
p = ffi.new("int*[1]")
assert p[0] is not None
assert p[0] != None
assert p[0] == ffi.NULL
assert repr(p[0]) == ""
#
n = ffi.new("int*", 99)
p = ffi.new("int*[]", [n])
assert p[0][0] == 99
py.test.raises(TypeError, "p[0] = None")
p[0] = ffi.NULL
assert p[0] == ffi.NULL
def test_float(self):
ffi = FFI(backend=self.Backend())
p = ffi.new("float[]", [-2, -2.5])
assert p[0] == -2.0
assert p[1] == -2.5
p[1] += 17.75
assert p[1] == 15.25
#
p = ffi.new("float*", 15.75)
assert p[0] == 15.75
py.test.raises(TypeError, int, p)
py.test.raises(TypeError, float, p)
p[0] = 0.0
assert bool(p) is True
#
p = ffi.new("float*", 1.1)
f = p[0]
assert f != 1.1 # because of rounding effect
assert abs(f - 1.1) < 1E-7
#
INF = 1E200 * 1E200
assert 1E200 != INF
p[0] = 1E200
assert p[0] == INF # infinite, not enough precision
def test_struct_simple(self):
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
s.b = -23
assert s.b == -23
py.test.raises(OverflowError, "s.b = 32768")
#
s = ffi.new("struct foo*", [-2, -3])
assert s.a == -2
assert s.b == -3
assert s.c == 0
py.test.raises((AttributeError, TypeError), "del s.a")
assert repr(s) == "" % (
SIZE_OF_INT + 2 * SIZE_OF_SHORT)
#
py.test.raises(ValueError, ffi.new, "struct foo*", [1, 2, 3, 4])
def test_constructor_struct_from_dict(self):
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
assert s.b == 123
assert s.c == 456
py.test.raises(KeyError, ffi.new, "struct foo*", {'d': 456})
def test_struct_pointer(self):
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
s[0].b = -23
assert s[0].b == s.b == -23
py.test.raises(OverflowError, "s[0].b = -32769")
py.test.raises(IndexError, "s[1]")
def test_struct_opaque(self):
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(backend=self.Backend())
ffi.cdef("struct foo { int a; short b, c; };")
s = ffi.new("struct foo *")
s.a = -42
assert s[0].a == -42
p = ffi.new("struct foo **", s)
assert p[0].a == -42
assert p[0][0].a == -42
p[0].a = -43
assert s.a == -43
assert s[0].a == -43
p[0][0].a = -44
assert s.a == -44
assert s[0].a == -44
s.a = -45
assert p[0].a == -45
assert p[0][0].a == -45
s[0].a = -46
assert p[0].a == -46
assert p[0][0].a == -46
def test_constructor_struct_of_array(self):
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
assert s.b[2] == b'c'
s.b[1] = b'X'
assert s.b[0] == b'a'
assert s.b[1] == b'X'
assert s.b[2] == b'c'
def test_recursive_struct(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int value; struct foo *next; };")
s = ffi.new("struct foo*")
t = ffi.new("struct foo*")
s.value = 123
s.next = t
t.value = 456
assert s.value == 123
assert s.next.value == 456
def test_union_simple(self):
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
u.b = -23
assert u.b == -23
assert u.a != 0
py.test.raises(OverflowError, "u.b = 32768")
#
u = ffi.new("union foo*", [-2])
assert u.a == -2
py.test.raises((AttributeError, TypeError), "del u.a")
assert repr(u) == "" % SIZE_OF_INT
def test_union_opaque(self):
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(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)
py.test.raises(ValueError, ffi.new, "union foo*", [b'A', 5])
u = ffi.new("union foo*", [b'A'])
assert u.a == b'A'
py.test.raises(TypeError, ffi.new, "union foo*", [1005])
u = ffi.new("union foo*", {'b': 12345})
assert u.b == 12345
u = ffi.new("union foo*", [])
assert u.a == b'\x00'
assert u.b == 0
def test_sizeof_type(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
struct foo { int a; short b, c, d; };
union foo { int a; short b, c, d; };
""")
for c_type, expected_size in [
('char', 1),
('unsigned int', 4),
('char *', SIZE_OF_PTR),
('int[5]', 20),
('struct foo', 12),
('union foo', 4),
]:
size = ffi.sizeof(c_type)
assert size == expected_size, (size, expected_size, ctype)
def test_sizeof_cdata(self):
ffi = FFI(backend=self.Backend())
assert ffi.sizeof(ffi.new("short*")) == SIZE_OF_PTR
assert ffi.sizeof(ffi.cast("short", 123)) == SIZE_OF_SHORT
#
a = ffi.new("int[]", [10, 11, 12, 13, 14])
assert len(a) == 5
assert ffi.sizeof(a) == 5 * SIZE_OF_INT
def test_string_from_char_pointer(self):
ffi = FFI(backend=self.Backend())
x = ffi.new("char*", b"x")
assert str(x) == repr(x)
assert ffi.string(x) == b"x"
assert ffi.string(ffi.new("char*", b"\x00")) == b""
py.test.raises(TypeError, ffi.new, "char*", unicode("foo"))
def test_unicode_from_wchar_pointer(self):
ffi = FFI(backend=self.Backend())
self.check_wchar_t(ffi)
x = ffi.new("wchar_t*", u+"x")
assert unicode(x) == unicode(repr(x))
assert ffi.string(x) == u+"x"
assert ffi.string(ffi.new("wchar_t*", u+"\x00")) == u+""
def test_string_from_char_array(self):
ffi = FFI(backend=self.Backend())
p = ffi.new("char[]", b"hello.")
p[5] = b'!'
assert ffi.string(p) == b"hello!"
p[6] = b'?'
assert ffi.string(p) == b"hello!?"
p[3] = b'\x00'
assert ffi.string(p) == b"hel"
assert ffi.string(p, 2) == b"he"
py.test.raises(IndexError, "p[7] = b'X'")
#
a = ffi.new("char[]", b"hello\x00world")
assert len(a) == 12
p = ffi.cast("char *", a)
assert ffi.string(p) == b'hello'
def test_string_from_wchar_array(self):
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"
x = ffi.cast("wchar_t", "x")
assert str(x) == repr(x)
assert ffi.string(x) == u+"x"
#
p = ffi.new("wchar_t[]", u+"hello.")
p[5] = u+'!'
assert ffi.string(p) == u+"hello!"
p[6] = u+'\u04d2'
assert ffi.string(p) == u+"hello!\u04d2"
p[3] = u+'\x00'
assert ffi.string(p) == u+"hel"
assert ffi.string(p, 123) == u+"hel"
py.test.raises(IndexError, "p[7] = u+'X'")
#
a = ffi.new("wchar_t[]", u+"hello\x00world")
assert len(a) == 12
p = ffi.cast("wchar_t *", a)
assert ffi.string(p) == u+'hello'
assert ffi.string(p, 123) == u+'hello'
assert ffi.string(p, 5) == u+'hello'
assert ffi.string(p, 2) == u+'he'
def test_fetch_const_char_p_field(self):
# 'const' is ignored so far
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])
assert type(s.name) not in (bytes, str, unicode)
assert ffi.string(s.name) == b"testing"
py.test.raises(TypeError, "s.name = None")
s.name = ffi.NULL
assert s.name == ffi.NULL
def test_fetch_const_wchar_p_field(self):
# 'const' is ignored so far
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")
s = ffi.new("struct foo*", [t])
assert type(s.name) not in (bytes, str, unicode)
assert ffi.string(s.name) == u+"testing"
s.name = ffi.NULL
assert s.name == ffi.NULL
def test_voidp(self):
ffi = FFI(backend=self.Backend())
py.test.raises(TypeError, ffi.new, "void*")
p = ffi.new("void **")
assert p[0] == ffi.NULL
a = ffi.new("int[]", [10, 11, 12])
p = ffi.new("void **", a)
vp = p[0]
py.test.raises(TypeError, "vp[0]")
py.test.raises(TypeError, ffi.new, "short **", a)
#
ffi.cdef("struct foo { void *p; int *q; short *r; };")
s = ffi.new("struct foo *")
s.p = a # works
s.q = a # works
py.test.raises(TypeError, "s.r = a") # fails
b = ffi.cast("int *", a)
s.p = b # works
s.q = b # works
py.test.raises(TypeError, "s.r = b") # fails
def test_functionptr_simple(self):
ffi = FFI(backend=self.Backend())
py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0)
def cb(n):
return n + 1
cb.__qualname__ = 'cb'
p = ffi.callback("int(*)(int)", cb)
res = p(41) # calling an 'int(*)(int)', i.e. a function pointer
assert res == 42 and type(res) is int
res = p(ffi.cast("int", -41))
assert res == -40 and type(res) is int
assert repr(p).startswith(
"" % (
SIZE_OF_PTR)
py.test.raises(TypeError, "q(43)")
res = q[0](43)
assert res == 44
q = ffi.cast("int(*)(int)", p)
assert repr(q).startswith(""
assert repr(ffi.cast("enum foo", -1)) == ( # enums are unsigned, if
"") # they contain no neg value
ffi.cdef("enum baz { A2=0x1000, B2=0x2000 };")
assert ffi.string(ffi.cast("enum baz", 0x1000)) == "A2"
assert ffi.string(ffi.cast("enum baz", 0x2000)) == "B2"
def test_enum_in_struct(self):
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
assert s.e == 0
s.e = 3
assert s.e == 3
assert s[0].e == 3
s[0].e = 2
assert s.e == 2
assert s[0].e == 2
s.e = ffi.cast("enum foo", -1)
assert s.e == 4294967295
assert s[0].e == 4294967295
s.e = s.e
py.test.raises(TypeError, "s.e = 'B'")
py.test.raises(TypeError, "s.e = '2'")
py.test.raises(TypeError, "s.e = '#2'")
py.test.raises(TypeError, "s.e = '#7'")
def test_enum_non_contiguous(self):
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"
assert ffi.string(ffi.cast("enum foo", 43)) == "C"
invalid_value = ffi.cast("enum foo", 2)
assert int(invalid_value) == 2
assert ffi.string(invalid_value) == "2"
def test_enum_char_hex_oct(self):
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"
assert ffi.string(ffi.cast("enum foo", 16)) == "C"
assert ffi.string(ffi.cast("enum foo", 8)) == "D"
assert ffi.string(ffi.cast("enum foo", -16)) == "E"
assert ffi.string(ffi.cast("enum foo", -8)) == "F"
def test_enum_partial(self):
ffi = FFI(backend=self.Backend())
ffi.cdef(r"enum foo {A, ...}; enum bar { B, C };")
needs_dlopen_none()
lib = ffi.dlopen(None)
assert lib.B == 0
py.test.raises(VerificationMissing, getattr, lib, "A")
assert lib.C == 1
def test_array_of_struct(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("struct foo { int a, b; };")
s = ffi.new("struct foo[1]")
py.test.raises(AttributeError, 's.b')
py.test.raises(AttributeError, 's.b = 412')
s[0].b = 412
assert s[0].b == 412
py.test.raises(IndexError, 's[1]')
def test_pointer_to_array(self):
ffi = FFI(backend=self.Backend())
p = ffi.new("int(**)[5]")
assert repr(p) == "" % SIZE_OF_PTR
def test_iterate_array(self):
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"]
#
py.test.raises(TypeError, iter, ffi.cast("char *", a))
py.test.raises(TypeError, list, ffi.cast("char *", a))
py.test.raises(TypeError, iter, ffi.new("int *"))
py.test.raises(TypeError, list, ffi.new("int *"))
def test_offsetof(self):
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(backend=self.Backend())
ffi.cdef("struct foo { int a, b, c; };"
"struct bar { struct foo d, e; };")
assert ffi.offsetof("struct bar", "e") == 12
py.test.raises(KeyError, ffi.offsetof, "struct bar", "e.a")
assert ffi.offsetof("struct bar", "e", "a") == 12
assert ffi.offsetof("struct bar", "e", "b") == 16
assert ffi.offsetof("struct bar", "e", "c") == 20
def test_offsetof_array(self):
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]; };")
assert ffi.offsetof("struct bar", "c") == 2 * ffi.sizeof("int")
assert ffi.offsetof("struct bar", "c", 0) == 2 * ffi.sizeof("int")
assert ffi.offsetof("struct bar", "c", 51) == 53 * ffi.sizeof("int")
def test_alignof(self):
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(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 *")
s.a = 511
py.test.raises(OverflowError, "s.a = 512")
py.test.raises(OverflowError, "s[0].a = 512")
assert s.a == 511
s.a = -512
py.test.raises(OverflowError, "s.a = -513")
py.test.raises(OverflowError, "s[0].a = -513")
assert s.a == -512
s.c = 3
assert s.c == 3
py.test.raises(OverflowError, "s.c = 4")
py.test.raises(OverflowError, "s[0].c = 4")
s.c = -4
assert s.c == -4
def test_bitfield_enum(self):
ffi = FFI(backend=self.Backend())
ffi.cdef("""
typedef enum { AA, BB, CC } foo_e;
typedef struct { foo_e f:2; } foo_s;
""")
s = ffi.new("foo_s *")
s.f = 2
assert s.f == 2
def test_anonymous_struct(self):
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])
b = ffi.new("bar_t *", [b"B", b"C"])
assert f.a == 12345
assert b.b == b"B"
assert b.c == b"C"
assert repr(b).startswith(" s) is False
assert (p >= s) is True
assert (s < p) is False
assert (s <= p) is True
assert (s == p) is True
assert (s != p) is False
assert (s > p) is False
assert (s >= p) is True
q = p + 1
assert (q < s) is False
assert (q <= s) is False
assert (q == s) is False
assert (q != s) is True
assert (q > s) is True
assert (q >= s) is True
assert (s < q) is True
assert (s <= q) is True
assert (s == q) is False
assert (s != q) is True
assert (s > q) is False
assert (s >= q) is False
assert (q < p) is False
assert (q <= p) is False
assert (q == p) is False
assert (q != p) is True
assert (q > p) is True
assert (q >= p) is True
assert (p < q) is True
assert (p <= q) is True
assert (p == q) is False
assert (p != q) is True
assert (p > q) is False
assert (p >= q) is False
#
assert (None == s) is False
assert (None != s) is True
assert (s == None) is False
assert (s != None) is True
assert (None == q) is False
assert (None != q) is True
assert (q == None) is False
assert (q != None) is True
def test_integer_comparison(self):
ffi = FFI(backend=self.Backend())
x = ffi.cast("int", 123)
y = ffi.cast("int", 456)
assert x < y
#
z = ffi.cast("double", 78.9)
assert x > z
assert y > z
def test_ffi_buffer_ptr(self):
ffi = FFI(backend=self.Backend())
a = ffi.new("short *", 100)
try:
b = ffi.buffer(a)
except NotImplementedError as e:
py.test.skip(str(e))
assert type(b) is ffi.buffer
content = b[:]
assert len(content) == len(b) == 2
if sys.byteorder == 'little':
assert content == b'\x64\x00'
assert b[0] == b'\x64'
b[0] = b'\x65'
else:
assert content == b'\x00\x64'
assert b[1] == b'\x64'
b[1] = b'\x65'
assert a[0] == 101
def test_ffi_buffer_array(self):
ffi = FFI(backend=self.Backend())
a = ffi.new("int[]", list(range(100, 110)))
try:
b = ffi.buffer(a)
except NotImplementedError as e:
py.test.skip(str(e))
content = b[:]
if sys.byteorder == 'little':
assert content.startswith(b'\x64\x00\x00\x00\x65\x00\x00\x00')
b[4] = b'\x45'
else:
assert content.startswith(b'\x00\x00\x00\x64\x00\x00\x00\x65')
b[7] = b'\x45'
assert len(content) == 4 * 10
assert a[1] == 0x45
def test_ffi_buffer_ptr_size(self):
ffi = FFI(backend=self.Backend())
a = ffi.new("short *", 0x4243)
try:
b = ffi.buffer(a, 1)
except NotImplementedError as e:
py.test.skip(str(e))
content = b[:]
assert len(content) == 1
if sys.byteorder == 'little':
assert content == b'\x43'
b[0] = b'\x62'
assert a[0] == 0x4262
else:
assert content == b'\x42'
b[0] = b'\x63'
assert a[0] == 0x6343
def test_ffi_buffer_array_size(self):
ffi = FFI(backend=self.Backend())
a1 = ffi.new("int[]", list(range(100, 110)))
a2 = ffi.new("int[]", list(range(100, 115)))
try:
ffi.buffer(a1)
except NotImplementedError as e:
py.test.skip(str(e))
assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:]
def test_ffi_buffer_with_file(self):
ffi = FFI(backend=self.Backend())
import tempfile, os, array
fd, filename = tempfile.mkstemp()
f = os.fdopen(fd, 'r+b')
a = ffi.new("int[]", list(range(1005)))
try:
ffi.buffer(a, 512)
except NotImplementedError as e:
py.test.skip(str(e))
f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
f.seek(0)
assert f.read() == array.array('i', range(1000)).tostring()
f.seek(0)
b = ffi.new("int[]", 1005)
f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
f.close()
os.unlink(filename)
def test_ffi_buffer_with_io(self):
ffi = FFI(backend=self.Backend())
import io, array
f = io.BytesIO()
a = ffi.new("int[]", list(range(1005)))
try:
ffi.buffer(a, 512)
except NotImplementedError as e:
py.test.skip(str(e))
f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
f.seek(0)
assert f.read() == array.array('i', range(1000)).tostring()
f.seek(0)
b = ffi.new("int[]", 1005)
f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
f.close()
def test_ffi_buffer_comparisons(self):
ffi = FFI(backend=self.Backend())
ba = bytearray(range(100, 110))
if sys.version_info >= (2, 7):
assert ba == memoryview(ba) # justification for the following
a = ffi.new("uint8_t[]", list(ba))
c = ffi.new("uint8_t[]", [99] + list(ba))
try:
b_full = ffi.buffer(a)
b_short = ffi.buffer(a, 3)
b_mid = ffi.buffer(a, 6)
b_other = ffi.buffer(c, 6)
except NotImplementedError as e:
py.test.skip(str(e))
else:
content = b_full[:]
assert content == b_full == ba
assert b_other < b_short < b_mid < b_full
assert ba > b_mid > ba[0:2]
assert b_short != ba[1:4]
def test_array_in_struct(self):
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
assert p.data[3] == 5
assert repr(p.data).startswith("