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

Reply via email to