Author: Armin Rigo <[email protected]>
Branch:
Changeset: r938:f4aed9ff91d6
Date: 2012-09-18 11:07 +0200
http://bitbucket.org/cffi/cffi/changeset/f4aed9ff91d6/
Log: Make ffi.callback work both in normal mode and in "decorator mode".
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -207,17 +207,25 @@
"""
return self._backend.buffer(cdata, size)
- def callback(self, cdecl, python_callable, error=None):
- """Return a callback object. 'cdecl' must name a C function pointer
- type. The callback invokes the specified 'python_callable'.
- Important: the callback object must be manually kept alive for as
- long as the callback may be invoked from the C level.
+ def callback(self, cdecl, python_callable=None, error=None):
+ """Return a callback object or a decorator making such a
+ callback object. 'cdecl' must name a C function pointer type.
+ The callback invokes the specified 'python_callable' (which may
+ be provided either directly or via a decorator). Important: the
+ callback object must be manually kept alive for as long as the
+ callback may be invoked from the C level.
"""
- if not callable(python_callable):
- raise TypeError("the 'python_callable' argument is not callable")
+ def callback_decorator_wrap(python_callable):
+ if not callable(python_callable):
+ raise TypeError("the 'python_callable' argument "
+ "is not callable")
+ return self._backend.callback(cdecl, python_callable, error)
if isinstance(cdecl, str):
cdecl = self._typeof(cdecl, consider_function_as_funcptr=True)
- return self._backend.callback(cdecl, python_callable, error)
+ if python_callable is None:
+ return callback_decorator_wrap # decorator mode
+ else:
+ return callback_decorator_wrap(python_callable) # direct mode
def getctype(self, cdecl, replace_with=''):
"""Return a string giving the C type 'cdecl', which may be itself
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -901,6 +901,13 @@
>>> ffi.callback("int(*)(int, int)", myfunc)
<cdata 'int(*)(int, int)' calling <function myfunc at 0xf757bbc4>>
+.. versionadded:: 0.4
+ Or equivalently as a decorator:
+
+ >>> @ffi.callback("int(*)(int, int)")
+ ... def myfunc(x, y):
+ ... return x + y
+
Warning: like ffi.new(), ffi.callback() returns a cdata that has
ownership of its C data. (In this case, the necessary C data contains
the libffi data structures to do a callback.) This means that the
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -663,7 +663,6 @@
def test_functionptr_simple(self):
ffi = FFI(backend=self.Backend())
- py.test.raises(TypeError, ffi.callback, "int(*)(int)")
py.test.raises(TypeError, ffi.callback, "int(*)(int)", 0)
def cb(n):
return n + 1
@@ -1259,6 +1258,16 @@
res = f(10, ffi.cast("int", 100), ffi.cast("long long", 1000))
assert res == 20 + 300 + 5000
+ def test_callback_decorator(self):
+ ffi = FFI(backend=self.Backend())
+ #
+ @ffi.callback("long(long, long)", error=42)
+ def cb(a, b):
+ return a - b
+ #
+ assert cb(-100, -10) == -90
+ assert cb(sys.maxint, -10) == 42
+
def test_unique_types(self):
ffi1 = FFI(backend=self.Backend())
ffi2 = FFI(backend=self.Backend())
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit