diff options
| -rw-r--r-- | c/call_python.c | 13 | ||||
| -rw-r--r-- | doc/source/using.rst | 24 | ||||
| -rw-r--r-- | testing/cffi1/test_recompiler.py | 30 |
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] |
