summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--c/call_python.c13
-rw-r--r--doc/source/using.rst24
-rw-r--r--testing/cffi1/test_recompiler.py30
3 files changed, 35 insertions, 32 deletions
diff --git a/c/call_python.c b/c/call_python.c
index f456d8e..a2da772 100644
--- a/c/call_python.c
+++ b/c/call_python.c
@@ -43,10 +43,9 @@ static PyObject *_ffi_def_extern_decorator(PyObject *outer_args, PyObject *fn)
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 @@ static PyObject *_ffi_def_extern_decorator(PyObject *outer_args, PyObject *fn)
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
index 0ac3da1..868adc6 100644
--- a/doc/source/using.rst
+++ b/doc/source/using.rst
@@ -461,11 +461,12 @@ your application's code::
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 @@ Python function object that was dynamically attached by
``@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 @@ and in your main application you register events like this::
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 @@ Then you can use the ``void *`` field in the low-level
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
index 81c43ef..f9d45eb 100644
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -1509,36 +1509,38 @@ def test_extern_python_1():
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 @@ def test_extern_python_bogus_result_type():
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 @@ def test_extern_python_errors():
@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]