Author: Armin Rigo <[email protected]>
Branch: cffi-callback-onerror
Changeset: r78195:bc928ced3d92
Date: 2015-06-19 00:02 +0200
http://bitbucket.org/pypy/pypy/changeset/bc928ced3d92/
Log: add the "onerror" argument to ffi.callback(), at least the out-of-
line one
diff --git a/pypy/module/_cffi_backend/ccallback.py
b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -22,8 +22,9 @@
class W_CDataCallback(W_CData):
#_immutable_fields_ = ...
ll_error = lltype.nullptr(rffi.CCHARP.TO)
+ w_onerror = None
- def __init__(self, space, ctype, w_callable, w_error):
+ def __init__(self, space, ctype, w_callable, w_error, w_onerror):
raw_closure = rffi.cast(rffi.CCHARP, clibffi.closureHeap.alloc())
W_CData.__init__(self, space, raw_closure, ctype)
#
@@ -31,6 +32,12 @@
raise oefmt(space.w_TypeError,
"expected a callable object, not %T", w_callable)
self.w_callable = w_callable
+ if not space.is_none(w_onerror):
+ if not space.is_true(space.callable(w_onerror)):
+ raise oefmt(space.w_TypeError,
+ "expected a callable object for 'onerror', not %T",
+ w_onerror)
+ self.w_onerror = w_onerror
#
fresult = self.getfunctype().ctitem
size = fresult.size
@@ -196,6 +203,15 @@
callback.convert_result(ll_res, w_res)
except OperationError, e:
# got an app-level exception
+ if callback.w_onerror is not None:
+ try:
+ e.normalize_exception(space)
+ w_t = e.w_type
+ w_v = e.get_w_value(space)
+ w_tb = space.wrap(e.get_traceback())
+ space.call_function(callback.w_onerror, w_t, w_v, w_tb)
+ except OperationError, e2:
+ e = e2
callback.print_error(e, extra_line)
callback.write_error_return_value(ll_res)
#
diff --git a/pypy/module/_cffi_backend/ffi_obj.py
b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -276,8 +276,9 @@
@unwrap_spec(w_python_callable=WrappedDefault(None),
- w_error=WrappedDefault(None))
- def descr_callback(self, w_cdecl, w_python_callable, w_error):
+ w_error=WrappedDefault(None),
+ w_onerror=WrappedDefault(None))
+ def descr_callback(self, w_cdecl, w_python_callable, w_error, w_onerror):
"""\
Return a callback object or a decorator making such a callback object.
'cdecl' must name a C function pointer type. The callback invokes the
@@ -290,14 +291,16 @@
space = self.space
if not space.is_none(w_python_callable):
return ccallback.W_CDataCallback(space, w_ctype,
- w_python_callable, w_error)
+ w_python_callable, w_error,
+ w_onerror)
else:
# decorator mode: returns a single-argument function
- return space.appexec([w_ctype, w_error],
- """(ctype, error):
+ return space.appexec([w_ctype, w_error, w_onerror],
+ """(ctype, error, onerror):
import _cffi_backend
return lambda python_callable: (
- _cffi_backend.callback(ctype, python_callable, error))""")
+ _cffi_backend.callback(ctype, python_callable,
+ error, onerror))""")
def descr_cast(self, w_arg, w_ob):
diff --git a/pypy/module/_cffi_backend/func.py
b/pypy/module/_cffi_backend/func.py
--- a/pypy/module/_cffi_backend/func.py
+++ b/pypy/module/_cffi_backend/func.py
@@ -18,9 +18,9 @@
# ____________________________________________________________
@unwrap_spec(w_ctype=ctypeobj.W_CType)
-def callback(space, w_ctype, w_callable, w_error=None):
+def callback(space, w_ctype, w_callable, w_error=None, w_onerror=None):
from pypy.module._cffi_backend.ccallback import W_CDataCallback
- return W_CDataCallback(space, w_ctype, w_callable, w_error)
+ return W_CDataCallback(space, w_ctype, w_callable, w_error, w_onerror)
# ____________________________________________________________
diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py
b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -114,6 +114,18 @@
assert ffi.callback("int(int)", lambda x: x + "", -66)(10) == -66
assert ffi.callback("int(int)", lambda x: x + "", error=-66)(10) == -66
+ def test_ffi_callback_onerror(self):
+ import _cffi_backend as _cffi1_backend
+ ffi = _cffi1_backend.FFI()
+ seen = []
+ def myerror(exc, val, tb):
+ seen.append(exc)
+ cb = ffi.callback("int(int)", lambda x: x + "", onerror=myerror)
+ assert cb(10) == 0
+ cb = ffi.callback("int(int)", lambda x:int(1E100), -66,
onerror=myerror)
+ assert cb(10) == -66
+ assert seen == [TypeError, OverflowError]
+
def test_ffi_callback_decorator(self):
import _cffi_backend as _cffi1_backend
ffi = _cffi1_backend.FFI()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit