diff options
-rw-r--r-- | demo/extern_python_varargs.py | 61 | ||||
-rw-r--r-- | doc/source/using.rst | 7 | ||||
-rw-r--r-- | testing/cffi1/test_new_ffi_1.py | 7 |
3 files changed, 73 insertions, 2 deletions
diff --git a/demo/extern_python_varargs.py b/demo/extern_python_varargs.py new file mode 100644 index 0000000..ee78079 --- /dev/null +++ b/demo/extern_python_varargs.py @@ -0,0 +1,61 @@ +import cffi + +ffi = cffi.FFI() + +ffi.cdef(""" + int my_algo(int); + typedef ... va_list; + extern "Python" int f(int, va_list *); + + int fetch_int(va_list *); + double fetch_double(va_list *); + void *fetch_ptr(va_list *); +""") + +ffi.set_source("_extern_python_cffi", """ + #include <stdarg.h> + + static int f(int, va_list *); + + static int f1(int n, ...) + { + va_list ap; + va_start(ap, n); + int res = f(n, &ap); + va_end(ap); + return res; + } + + static int fetch_int(va_list *va) { return va_arg((*va), int); } + static double fetch_double(va_list *va) { return va_arg((*va), double); } + static void * fetch_ptr(va_list *va) { return va_arg((*va), void *); } + + static int my_algo(int n) { + return f1(3, n, n+1, n+2) + f1(1, &n) + f1(2, 12.3, 45.6); + } +""") + +ffi.compile() + + +from _extern_python_cffi import ffi, lib + +@ffi.def_extern() +def f(n, va): + if n == 3: + x = lib.fetch_int(va) + y = lib.fetch_int(va) + z = lib.fetch_int(va) + print (x, y, z) + elif n == 1: + ptr = lib.fetch_ptr(va) + print 'ptr to:', ffi.cast("int *", ptr)[0] + elif n == 2: + x = lib.fetch_double(va) + y = lib.fetch_double(va) + print (x, y) + else: + raise AssertionError(n) + return 14 + +print lib.my_algo(10) diff --git a/doc/source/using.rst b/doc/source/using.rst index c7745dd..1c5430c 100644 --- a/doc/source/using.rst +++ b/doc/source/using.rst @@ -476,7 +476,7 @@ Python function object that is, at runtime, attached with ``@ffi.def_extern()``. The ``@ffi.def_extern()`` decorator should be applied to a global -function, once. This is because each function from the cdef with +function, but *only once.* This is because each function from the cdef with ``extern "Python"`` turns into only one C function. To support some corner cases, it is possible to redefine the attached Python function by calling ``@ffi.def_extern()`` again---but this is not recommended! @@ -616,7 +616,10 @@ functions:: } The ``extern "Python"`` functions cannot be variadic for now. This -may be implemented in the future. +may be implemented in the future. (`This demo`__ shows how to do it +anyway, but it is a bit lengthy.) + +.. __: https://bitbucket.org/cffi/cffi/src/default/demo/extern_python_varargs.py Each corresponding Python callback function is defined with the ``@ffi.def_extern()`` decorator. Be careful when writing this diff --git a/testing/cffi1/test_new_ffi_1.py b/testing/cffi1/test_new_ffi_1.py index b1f1b33..d242b18 100644 --- a/testing/cffi1/test_new_ffi_1.py +++ b/testing/cffi1/test_new_ffi_1.py @@ -1718,3 +1718,10 @@ class TestNewFFI1: exec("from _test_import_from_lib.lib import *", d) assert (set(key for key in d if not key.startswith('_')) == set(['myfunc', 'MYFOO'])) + # + # also test "import *" on the module itself, which should be + # equivalent to "import ffi, lib" + d = {} + exec("from _test_import_from_lib import *", d) + assert (sorted([x for x in d.keys() if not x.startswith('__')]) == + ['ffi', 'lib']) |