Author: Armin Rigo <[email protected]>
Branch: static-callback
Changeset: r2420:63e802144a16
Date: 2015-11-20 15:57 +0100
http://bitbucket.org/cffi/cffi/changeset/63e802144a16/

Log:    Change the @ffi.def_extern() decorator to not automatically replace
        the function with the cdata. You need to get the cdata from the lib
        explicitly. This should make it clearer that there is only one
        cdata, even if you apply the decorator again.

diff --git a/c/call_python.c b/c/call_python.c
--- a/c/call_python.c
+++ b/c/call_python.c
@@ -43,10 +43,9 @@
         return NULL;
 
     infotuple = prepare_callback_info_tuple(ct, fn, error, onerror, 0);
-    if (infotuple == NULL) {
-        Py_DECREF(ct);
+    Py_DECREF(ct);
+    if (infotuple == NULL)
         return NULL;
-    }
 
     /* attach infotuple to reserved1, where it will stay forever
        unless a new version is attached later */
@@ -55,11 +54,9 @@
     externpy->reserved1 = (void *)infotuple;
     Py_XDECREF(x);
 
-    /* return a cdata of type function-pointer, equal to the one
-       obtained by reading 'lib.bar' (see lib_obj.c) */
-    x = convert_to_object((char *)&g->size_or_direct_fn, ct);
-    Py_DECREF(ct);
-    return x;
+    /* return the function object unmodified */
+    Py_INCREF(fn);
+    return fn;
 
  not_found:
     PyErr_Format(FFIError, "ffi.def_extern('%s'): no 'extern \"Python\"' "
diff --git a/doc/source/using.rst b/doc/source/using.rst
--- a/doc/source/using.rst
+++ b/doc/source/using.rst
@@ -461,11 +461,12 @@
     def my_callback(fooptr, value):
         return 42
 
-You can get a ``<cdata>`` pointer-to-function object from either
-reading ``lib.my_callback``, or directly from the decorated
-``my_callback`` above.  This ``<cdata>`` can be passed to C code and
+You can get a ``<cdata>`` pointer-to-function object from
+``lib.my_callback``.  This ``<cdata>`` can be passed to C code and
 then works like a callback: when the C code calls this function
-pointer, the Python function ``my_callback`` is called.
+pointer, the Python function ``my_callback`` is called.  (You need
+to pass ``lib.my_callback`` to C code, and not ``my_callback``: the
+latter is just a plain Python function that cannot be passed to C.)
 
 CFFI implements this by defining ``my_callback`` as a static C
 function, written after the ``set_source()`` code.  The ``<cdata>``
@@ -474,10 +475,13 @@
 ``@ffi.def_extern()``.
 
 Each function from the cdef with ``extern "Python"`` turns into only
-one C function.  You can redefine the attached Python function by
-calling ``@ffi.def_extern()`` again, but it changes the C logic to
-call the new Python function; the old Python function is not callable
-any more and the C function pointer itself is always the same.
+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!  Better write the Python function
+more flexibly in the first place.  Calling ``@ffi.def_extern()`` again
+changes the C logic to call the new Python function; the old Python
+function is not callable any more and the C function pointer you get
+from ``lib.my_function`` is always the same.
 
 Extern "Python" and "void *" arguments
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -517,7 +521,7 @@
         def __init__(self):
             userdata = ffi.new_handle(self)
             self._userdata = userdata     # must keep this alive!
-            lib.event_cb_register(my_event_callback, userdata)
+            lib.event_cb_register(lib.my_event_callback, userdata)
 
         def process_event(self, evt):
             ...
@@ -546,7 +550,7 @@
             userdata = ffi.new_handle(self)
             self._userdata = userdata        # must still keep this alive!
             ll_widget.userdata = userdata    # this makes a copy of the "void 
*"
-            lib.event_cb_register(ll_widget, my_event_callback)
+            lib.event_cb_register(ll_widget, lib.my_event_callback)
 
         def process_event(self, evt):
             ...
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -1509,36 +1509,38 @@
     def my_bar(x, y):
         seen.append(("Bar", x, y))
         return x * y
-    assert my_bar == lib.bar
+    assert my_bar != lib.bar
     seen = []
     res = lib.bar(6, 7)
     assert seen == [("Bar", 6, 7)]
     assert res == 42
 
-    @ffi.def_extern()
     def baz(x, y):
         seen.append(("Baz", x, y))
+    baz1 = ffi.def_extern()(baz)
+    assert baz1 is baz
     seen = []
-    res = baz(50L, 8L)
+    baz(40L, 4L)
+    res = lib.baz(50L, 8L)
     assert res is None
-    assert seen == [("Baz", 50, 8)]
-    assert type(seen[0][1]) is type(seen[0][2]) is int
-    assert baz == lib.baz
+    assert seen == [("Baz", 40L, 4L), ("Baz", 50, 8)]
+    assert type(seen[0][1]) is type(seen[0][2]) is long
+    assert type(seen[1][1]) is type(seen[1][2]) is int
 
     @ffi.def_extern(name="bok")
     def bokk():
         seen.append("Bok")
         return 42
     seen = []
-    assert lib.bok() == bokk() == 42
-    assert seen == ["Bok", "Bok"]
+    assert lib.bok() == 42
+    assert seen == ["Bok"]
 
     @ffi.def_extern()
     def boz():
         seen.append("Boz")
     seen = []
-    assert lib.boz() is boz() is None
-    assert seen == ["Boz", "Boz"]
+    assert lib.boz() is None
+    assert seen == ["Boz"]
 
 def test_extern_python_bogus_name():
     ffi = FFI()
@@ -1569,11 +1571,11 @@
     ffi.cdef("""extern "Python" void bar(int);""")
     lib = verify(ffi, 'test_extern_python_bogus_result_type', "")
     #
+    @ffi.def_extern()
     def bar(n):
         return n * 10
-    bar1 = ffi.def_extern()(bar)
     with StdErrCapture() as f:
-        res = bar1(321)
+        res = lib.bar(321)
     assert res is None
     assert f.getvalue() == (
         "From cffi callback %r:\n" % (bar,) +
@@ -1677,12 +1679,12 @@
     @ffi.def_extern(onerror=oops)
     def bar(x):
         return x + ""
-    assert bar(10) == 0
+    assert lib.bar(10) == 0
 
     @ffi.def_extern(name="bar", onerror=oops, error=-66)
     def bar2(x):
         return x + ""
-    assert bar(10) == -66
+    assert lib.bar(10) == -66
 
     assert len(seen) == 2
     exc, val, tb = seen[0]
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to