diff --git a/python/src/deltachat/__init__.py b/python/src/deltachat/__init__.py new file mode 100644 index 00000000..6ae6926a --- /dev/null +++ b/python/src/deltachat/__init__.py @@ -0,0 +1,14 @@ +from deltachat import capi + + +_DC_CALLBACK_MAP = {} + + +@capi.ffi.def_extern() +def py_dc_callback(ctx, evt, data1, data2): + """The global event handler. + + CFFI only allows us to set one global event handler, so this one + looks up the correct event handler for the given context. + """ + return _DC_CALLBACK_MAP.get(ctx, lambda *a: 0) diff --git a/python/src/deltachat/_build.py b/python/src/deltachat/_build.py index 95969699..16fd9742 100644 --- a/python/src/deltachat/_build.py +++ b/python/src/deltachat/_build.py @@ -28,6 +28,13 @@ def ffibuilder(): output_file=dst_fp.name, macros=[('PY_CFFI', '1')]) builder.cdef(dst_fp.read()) + builder.cdef(""" + extern "Python" uintptr_t py_dc_callback( + dc_context_t* context, + int event, + uintptr_t data1, + uintptr_t data2); + """) return builder diff --git a/python/tests/conftest.py b/python/tests/conftest.py new file mode 100644 index 00000000..ce909e71 --- /dev/null +++ b/python/tests/conftest.py @@ -0,0 +1,15 @@ +import pytest + +import deltachat + + +@pytest.fixture +def register_dc_callback(monkeypatch): + """Register a callback for a given context. + + This is a function-scoped fixture and the function will be + unregisterd automatically on fixture teardown. + """ + def register_dc_callback(ctx, func): + monkeypatch.setitem(deltachat._DC_CALLBACK_MAP, ctx, func) + return register_dc_callback diff --git a/python/tests/test_mrmailbox.py b/python/tests/test_mrmailbox.py index b7fa398e..5fddce47 100644 --- a/python/tests/test_mrmailbox.py +++ b/python/tests/test_mrmailbox.py @@ -1,10 +1,17 @@ -import pathlib - -import pytest - +import deltachat from deltachat import capi def test_empty_context(): ctx = capi.lib.dc_context_new(capi.ffi.NULL, capi.ffi.NULL, capi.ffi.NULL) capi.lib.dc_close(ctx) + + +def test_cb(register_dc_callback): + def cb(ctx, evt, data1, data2): + return 0 + ctx = capi.lib.dc_context_new(capi.lib.py_dc_callback, + capi.ffi.NULL, capi.ffi.NULL) + register_dc_callback(ctx, cb) + capi.lib.dc_close(ctx) + assert deltachat._DC_CALLBACK_MAP[ctx] is cb