summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--demo/extern_python_varargs.py61
-rw-r--r--doc/source/using.rst7
-rw-r--r--testing/cffi1/test_new_ffi_1.py7
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'])