diff --git a/capnp/__init__.py b/capnp/__init__.py index a990f7b..b10d7cf 100644 --- a/capnp/__init__.py +++ b/capnp/__init__.py @@ -52,6 +52,8 @@ from .lib.capnp import ( _write_message_to_fd, _write_packed_message_to_fd, _Promise as Promise, + _init_capnp_api, ) +_init_capnp_api() add_import_hook() # enable import hook by default diff --git a/capnp/helpers/capabilityHelper.cpp b/capnp/helpers/capabilityHelper.cpp new file mode 100644 index 0000000..05350ac --- /dev/null +++ b/capnp/helpers/capabilityHelper.cpp @@ -0,0 +1,159 @@ +#include "capnp/helpers/capabilityHelper.h" +#include "capnp/lib/capnp_api.h" + +::kj::Promise convert_to_pypromise(capnp::RemotePromise & promise) { + return promise.then([](capnp::Response&& response) { return wrap_dynamic_struct_reader(response); } ); +} + +void reraise_kj_exception() { + GILAcquire gil; + try { + if (PyErr_Occurred()) + ; // let the latest Python exn pass through and ignore the current one + else + throw; + } + catch (kj::Exception& exn) { + auto obj = wrap_kj_exception_for_reraise(exn); + PyErr_SetObject((PyObject*)obj->ob_type, obj); + Py_DECREF(obj); + } + catch (const std::exception& exn) { + PyErr_SetString(PyExc_RuntimeError, exn.what()); + } + catch (...) + { + PyErr_SetString(PyExc_RuntimeError, "Unknown exception"); + } +} + +void check_py_error() { + GILAcquire gil; + PyObject * err = PyErr_Occurred(); + if(err) { + PyObject * ptype, *pvalue, *ptraceback; + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + if(ptype == NULL || pvalue == NULL || ptraceback == NULL) + throw kj::Exception(kj::Exception::Type::FAILED, kj::heapString("capabilityHelper.h"), 44, kj::heapString("Unknown error occurred")); + + PyObject * info = get_exception_info(ptype, pvalue, ptraceback); + + PyObject * py_filename = PyTuple_GetItem(info, 0); + kj::String filename(kj::heapString(PyBytes_AsString(py_filename))); + + PyObject * py_line = PyTuple_GetItem(info, 1); + int line = PyLong_AsLong(py_line); + + PyObject * py_description = PyTuple_GetItem(info, 2); + kj::String description(kj::heapString(PyBytes_AsString(py_description))); + + Py_DECREF(ptype); + Py_DECREF(pvalue); + Py_DECREF(ptraceback); + Py_DECREF(info); + PyErr_Clear(); + + throw kj::Exception(kj::Exception::Type::FAILED, kj::mv(filename), line, kj::mv(description)); + } +} + +kj::Promise wrapPyFunc(PyObject * func, PyObject * arg) { + GILAcquire gil; + auto arg_promise = extract_promise(arg); + + if(arg_promise == NULL) { + PyObject * result = PyObject_CallFunctionObjArgs(func, arg, NULL); + Py_DECREF(arg); + + check_py_error(); + + auto promise = extract_promise(result); + if(promise != NULL) + return kj::mv(*promise); // TODO: delete promise, see incref of containing promise in capnp.pyx + auto remote_promise = extract_remote_promise(result); + if(remote_promise != NULL) + return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx + return result; + } + else { + return arg_promise->then([&](PyObject * new_arg){ return wrapPyFunc(func, new_arg); });// TODO: delete arg_promise? + } +} + +kj::Promise wrapPyFuncNoArg(PyObject * func) { + GILAcquire gil; + PyObject * result = PyObject_CallFunctionObjArgs(func, NULL); + + check_py_error(); + + auto promise = extract_promise(result); + if(promise != NULL) + return kj::mv(*promise); + auto remote_promise = extract_remote_promise(result); + if(remote_promise != NULL) + return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx + return result; +} + +kj::Promise wrapRemoteCall(PyObject * func, capnp::Response & arg) { + GILAcquire gil; + PyObject * ret = wrap_remote_call(func, arg); + + check_py_error(); + + auto promise = extract_promise(ret); + if(promise != NULL) + return kj::mv(*promise); + auto remote_promise = extract_remote_promise(ret); + if(remote_promise != NULL) + return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx + return ret; +} + +::kj::Promise then(kj::Promise & promise, PyObject * func, PyObject * error_func) { + if(error_func == Py_None) + return promise.then([func](PyObject * arg) { return wrapPyFunc(func, arg); } ); + else + return promise.then([func](PyObject * arg) { return wrapPyFunc(func, arg); } + , [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } ); +} + +::kj::Promise then(::capnp::RemotePromise< ::capnp::DynamicStruct> & promise, PyObject * func, PyObject * error_func) { + if(error_func == Py_None) + return promise.then([func](capnp::Response&& arg) { return wrapRemoteCall(func, arg); } ); + else + return promise.then([func](capnp::Response&& arg) { return wrapRemoteCall(func, arg); } + , [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } ); +} + +::kj::Promise then(kj::Promise & promise, PyObject * func, PyObject * error_func) { + if(error_func == Py_None) + return promise.then([func]() { return wrapPyFuncNoArg(func); } ); + else + return promise.then([func]() { return wrapPyFuncNoArg(func); } + , [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } ); +} + +::kj::Promise then(kj::Promise > && promise) { + return promise.then([](kj::Array&& arg) { return convert_array_pyobject(arg); } ); +} + +kj::Promise PythonInterfaceDynamicImpl::call(capnp::InterfaceSchema::Method method, + capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> context) { + auto methodName = method.getProto().getName(); + + kj::Promise * promise = call_server_method(py_server, const_cast(methodName.cStr()), context); + + check_py_error(); + + if(promise == nullptr) + return kj::READY_NOW; + + kj::Promise ret(kj::mv(*promise)); + delete promise; + return ret; +}; + +void init_capnp_api() { + import_capnp__lib__capnp(); +} diff --git a/capnp/helpers/capabilityHelper.h b/capnp/helpers/capabilityHelper.h index d6f7ff0..d45c511 100644 --- a/capnp/helpers/capabilityHelper.h +++ b/capnp/helpers/capabilityHelper.h @@ -4,18 +4,6 @@ #include #include "Python.h" -extern "C" { - PyObject * wrap_remote_call(PyObject * func, capnp::Response &); - PyObject * wrap_dynamic_struct_reader(capnp::Response &); - ::kj::Promise * call_server_method(PyObject * py_server, char * name, capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> & context); - PyObject * wrap_kj_exception(kj::Exception &); - PyObject * wrap_kj_exception_for_reraise(kj::Exception &); - PyObject * get_exception_info(PyObject *, PyObject *, PyObject *); - PyObject * convert_array_pyobject(kj::Array&); - ::kj::Promise * extract_promise(PyObject *); - ::capnp::RemotePromise< ::capnp::DynamicStruct> * extract_remote_promise(PyObject *); - } - class GILAcquire { public: GILAcquire() : gstate(PyGILState_Ensure()) {} @@ -38,11 +26,9 @@ public: PyThreadState *_save; // The macros above read/write from this variable }; -::kj::Promise convert_to_pypromise(capnp::RemotePromise & promise) { - return promise.then([](capnp::Response&& response) { return wrap_dynamic_struct_reader(response); } ); -} +::kj::Promise convert_to_pypromise(capnp::RemotePromise & promise); -::kj::Promise convert_to_pypromise(kj::Promise & promise) { +inline ::kj::Promise convert_to_pypromise(kj::Promise & promise) { return promise.then([]() { GILAcquire gil; Py_INCREF( Py_None ); @@ -55,138 +41,22 @@ template return promise.then([](T) { } ); } -void reraise_kj_exception() { - GILAcquire gil; - try { - if (PyErr_Occurred()) - ; // let the latest Python exn pass through and ignore the current one - else - throw; - } - catch (kj::Exception& exn) { - auto obj = wrap_kj_exception_for_reraise(exn); - PyErr_SetObject((PyObject*)obj->ob_type, obj); - Py_DECREF(obj); - } - catch (const std::exception& exn) { - PyErr_SetString(PyExc_RuntimeError, exn.what()); - } - catch (...) - { - PyErr_SetString(PyExc_RuntimeError, "Unknown exception"); - } -} +void reraise_kj_exception(); -void check_py_error() { - GILAcquire gil; - PyObject * err = PyErr_Occurred(); - if(err) { - PyObject * ptype, *pvalue, *ptraceback; - PyErr_Fetch(&ptype, &pvalue, &ptraceback); - if(ptype == NULL || pvalue == NULL || ptraceback == NULL) - throw kj::Exception(kj::Exception::Type::FAILED, kj::heapString("capabilityHelper.h"), 44, kj::heapString("Unknown error occurred")); +void check_py_error(); - PyObject * info = get_exception_info(ptype, pvalue, ptraceback); +kj::Promise wrapPyFunc(PyObject * func, PyObject * arg); - PyObject * py_filename = PyTuple_GetItem(info, 0); - kj::String filename(kj::heapString(PyBytes_AsString(py_filename))); +kj::Promise wrapPyFuncNoArg(PyObject * func); - PyObject * py_line = PyTuple_GetItem(info, 1); - int line = PyInt_AsLong(py_line); +kj::Promise wrapRemoteCall(PyObject * func, capnp::Response & arg); - PyObject * py_description = PyTuple_GetItem(info, 2); - kj::String description(kj::heapString(PyBytes_AsString(py_description))); +::kj::Promise then(kj::Promise & promise, PyObject * func, PyObject * error_func); +::kj::Promise then(::capnp::RemotePromise< ::capnp::DynamicStruct> & promise, PyObject * func, PyObject * error_func); - Py_DECREF(ptype); - Py_DECREF(pvalue); - Py_DECREF(ptraceback); - Py_DECREF(info); - PyErr_Clear(); +::kj::Promise then(kj::Promise & promise, PyObject * func, PyObject * error_func); - throw kj::Exception(kj::Exception::Type::FAILED, kj::mv(filename), line, kj::mv(description)); - } -} - -kj::Promise wrapPyFunc(PyObject * func, PyObject * arg) { - GILAcquire gil; - auto arg_promise = extract_promise(arg); - - if(arg_promise == NULL) { - PyObject * result = PyObject_CallFunctionObjArgs(func, arg, NULL); - Py_DECREF(arg); - - check_py_error(); - - auto promise = extract_promise(result); - if(promise != NULL) - return kj::mv(*promise); // TODO: delete promise, see incref of containing promise in capnp.pyx - auto remote_promise = extract_remote_promise(result); - if(remote_promise != NULL) - return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx - return result; - } - else { - return arg_promise->then([&](PyObject * new_arg){ return wrapPyFunc(func, new_arg); });// TODO: delete arg_promise? - } -} - -kj::Promise wrapPyFuncNoArg(PyObject * func) { - GILAcquire gil; - PyObject * result = PyObject_CallFunctionObjArgs(func, NULL); - - check_py_error(); - - auto promise = extract_promise(result); - if(promise != NULL) - return kj::mv(*promise); - auto remote_promise = extract_remote_promise(result); - if(remote_promise != NULL) - return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx - return result; -} - -kj::Promise wrapRemoteCall(PyObject * func, capnp::Response & arg) { - GILAcquire gil; - PyObject * ret = wrap_remote_call(func, arg); - - check_py_error(); - - auto promise = extract_promise(ret); - if(promise != NULL) - return kj::mv(*promise); - auto remote_promise = extract_remote_promise(ret); - if(remote_promise != NULL) - return convert_to_pypromise(*remote_promise); // TODO: delete promise, see incref of containing promise in capnp.pyx - return ret; -} - -::kj::Promise then(kj::Promise & promise, PyObject * func, PyObject * error_func) { - if(error_func == Py_None) - return promise.then([func](PyObject * arg) { return wrapPyFunc(func, arg); } ); - else - return promise.then([func](PyObject * arg) { return wrapPyFunc(func, arg); } - , [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } ); -} - -::kj::Promise then(::capnp::RemotePromise< ::capnp::DynamicStruct> & promise, PyObject * func, PyObject * error_func) { - if(error_func == Py_None) - return promise.then([func](capnp::Response&& arg) { return wrapRemoteCall(func, arg); } ); - else - return promise.then([func](capnp::Response&& arg) { return wrapRemoteCall(func, arg); } - , [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } ); -} - -::kj::Promise then(kj::Promise & promise, PyObject * func, PyObject * error_func) { - if(error_func == Py_None) - return promise.then([func]() { return wrapPyFuncNoArg(func); } ); - else - return promise.then([func]() { return wrapPyFuncNoArg(func); } - , [error_func](kj::Exception arg) { return wrapPyFunc(error_func, wrap_kj_exception(arg)); } ); -} - -::kj::Promise then(kj::Promise > && promise) { - return promise.then([](kj::Array&& arg) { return convert_array_pyobject(arg); } ); -} +::kj::Promise then(kj::Promise > && promise); class PythonInterfaceDynamicImpl final: public capnp::DynamicCapability::Server { public: @@ -204,20 +74,7 @@ public: } kj::Promise call(capnp::InterfaceSchema::Method method, - capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> context) { - auto methodName = method.getProto().getName(); - - kj::Promise * promise = call_server_method(py_server, const_cast(methodName.cStr()), context); - - check_py_error(); - - if(promise == nullptr) - return kj::READY_NOW; - - kj::Promise ret(kj::mv(*promise)); - delete promise; - return ret; - } + capnp::CallContext< capnp::DynamicStruct, capnp::DynamicStruct> context); }; class PyRefCounter { @@ -240,13 +97,15 @@ public: } }; -capnp::DynamicCapability::Client new_client(capnp::InterfaceSchema & schema, PyObject * server) { +inline capnp::DynamicCapability::Client new_client(capnp::InterfaceSchema & schema, PyObject * server) { return capnp::DynamicCapability::Client(kj::heap(schema, server)); } -capnp::DynamicValue::Reader new_server(capnp::InterfaceSchema & schema, PyObject * server) { +inline capnp::DynamicValue::Reader new_server(capnp::InterfaceSchema & schema, PyObject * server) { return capnp::DynamicValue::Reader(kj::heap(schema, server)); } -capnp::Capability::Client server_to_client(capnp::InterfaceSchema & schema, PyObject * server) { +inline capnp::Capability::Client server_to_client(capnp::InterfaceSchema & schema, PyObject * server) { return kj::heap(schema, server); } + +void init_capnp_api(); diff --git a/capnp/helpers/helpers.pxd b/capnp/helpers/helpers.pxd index cde9bab..5304d5d 100644 --- a/capnp/helpers/helpers.pxd +++ b/capnp/helpers/helpers.pxd @@ -25,6 +25,7 @@ cdef extern from "capnp/helpers/capabilityHelper.h": PyPromise convert_to_pypromise(RemotePromise&) PyPromise convert_to_pypromise(VoidPromise&) VoidPromise convert_to_voidpromise(PyPromise&) + void init_capnp_api() cdef extern from "capnp/helpers/rpcHelper.h": Capability.Client bootstrapHelper(RpcSystem&) diff --git a/capnp/lib/capnp.pxd b/capnp/lib/capnp.pxd index 21c8950..55c8531 100644 --- a/capnp/lib/capnp.pxd +++ b/capnp/lib/capnp.pxd @@ -2,7 +2,7 @@ from capnp.includes cimport capnp_cpp as capnp from capnp.includes cimport schema_cpp -from capnp.includes.capnp_cpp cimport Schema as C_Schema, StructSchema as C_StructSchema, InterfaceSchema as C_InterfaceSchema, EnumSchema as C_EnumSchema, ListSchema as C_ListSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue, Type as C_Type, DynamicList as C_DynamicList, SchemaParser as C_SchemaParser, ParsedSchema as C_ParsedSchema, VOID, ArrayPtr, StringPtr, String, StringTree, DynamicOrphan as C_DynamicOrphan, AnyPointer as C_DynamicObject, DynamicCapability as C_DynamicCapability, Request, Response, RemotePromise, PyPromise, VoidPromise, CallContext, RpcSystem, makeRpcServerBootstrap, makeRpcClient, Capability as C_Capability, TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, PromiseFulfillerPair as C_PromiseFulfillerPair, copyPromiseFulfillerPair, newPromiseAndFulfiller, PyArray, DynamicStruct_Builder, TwoWayPipe +from capnp.includes.capnp_cpp cimport Schema as C_Schema, StructSchema as C_StructSchema, InterfaceSchema as C_InterfaceSchema, EnumSchema as C_EnumSchema, ListSchema as C_ListSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue, Type as C_Type, DynamicList as C_DynamicList, SchemaParser as C_SchemaParser, ParsedSchema as C_ParsedSchema, VOID, ArrayPtr, StringPtr, String, StringTree, DynamicOrphan as C_DynamicOrphan, AnyPointer as C_DynamicObject, DynamicCapability as C_DynamicCapability, Request, Response, RemotePromise, Promise, CallContext, RpcSystem, makeRpcServerBootstrap, makeRpcClient, Capability as C_Capability, TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, PromiseFulfillerPair as C_PromiseFulfillerPair, copyPromiseFulfillerPair, newPromiseAndFulfiller, PyArray, DynamicStruct_Builder, TwoWayPipe from capnp.includes.schema_cpp cimport Node as C_Node, EnumNode as C_EnumNode from capnp.includes.types cimport * from capnp.helpers.non_circular cimport reraise_kj_exception @@ -130,6 +130,15 @@ cdef class _DynamicListBuilder: cpdef init(self, index, size) +cdef class _MessageBuilder: + cdef schema_cpp.MessageBuilder * thisptr + cpdef init_root(self, schema) + cpdef get_root(self, schema) except +reraise_kj_exception + cpdef get_root_as_any(self) except +reraise_kj_exception + cpdef set_root(self, value) except +reraise_kj_exception + cpdef get_segments_for_output(self) except +reraise_kj_exception + cpdef new_orphan(self, schema) except +reraise_kj_exception + cdef to_python_reader(C_DynamicValue.Reader self, object parent) cdef to_python_builder(C_DynamicValue.Builder self, object parent) cdef _to_dict(msg, bint verbose, bint ordered) @@ -137,3 +146,13 @@ cdef _from_list(_DynamicListBuilder msg, list d) cdef _from_tuple(_DynamicListBuilder msg, tuple d) cdef _setDynamicFieldWithField(DynamicStruct_Builder thisptr, _StructSchemaField field, value, parent) cdef _setDynamicFieldStatic(DynamicStruct_Builder thisptr, field, value, parent) + +cdef api object wrap_dynamic_struct_reader(Response & r) with gil +cdef api PyObject * wrap_remote_call(PyObject * func, Response & r) except * with gil +cdef api Promise[void] * call_server_method(PyObject * _server, char * _method_name, CallContext & _context) except * with gil +cdef api convert_array_pyobject(PyArray & arr) with gil +cdef api Promise[PyObject*] * extract_promise(object obj) with gil +cdef api RemotePromise * extract_remote_promise(object obj) with gil +cdef api object wrap_kj_exception(capnp.Exception & exception) with gil +cdef api object wrap_kj_exception_for_reraise(capnp.Exception & exception) with gil +cdef api object get_exception_info(object exc_type, object exc_obj, object exc_tb) with gil diff --git a/capnp/lib/capnp.pyx b/capnp/lib/capnp.pyx index 9cf03fd..b0d62a7 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -9,8 +9,8 @@ cimport cython -from capnp.helpers.helpers cimport AsyncIoStreamReadHelper -from capnp.includes.capnp_cpp cimport AsyncIoStream, WaitScope +from capnp.helpers.helpers cimport AsyncIoStreamReadHelper, init_capnp_api +from capnp.includes.capnp_cpp cimport AsyncIoStream, WaitScope, PyPromise, VoidPromise from libc.stdlib cimport malloc, free from libc.string cimport memcpy @@ -48,10 +48,10 @@ def deregister_all_types(): _type_registry = {} # By making it public, we'll be able to call it from capabilityHelper.h -cdef public object wrap_dynamic_struct_reader(Response & r) with gil: +cdef api object wrap_dynamic_struct_reader(Response & r) with gil: return _Response()._init_childptr(new Response(moveResponse(r)), None) -cdef public PyObject * wrap_remote_call(PyObject * func, Response & r) except * with gil: +cdef api PyObject * wrap_remote_call(PyObject * func, Response & r) except * with gil: response = _Response()._init_childptr(new Response(moveResponse(r)), None) func_obj = func @@ -62,7 +62,7 @@ cdef public PyObject * wrap_remote_call(PyObject * func, Response & r) except * cdef _find_field_order(struct_node): return [f.name for f in sorted(struct_node.fields, key=_attrgetter('codeOrder'))] -cdef public VoidPromise * call_server_method(PyObject * _server, char * _method_name, CallContext & _context) except * with gil: +cdef api VoidPromise * call_server_method(PyObject * _server, char * _method_name, CallContext & _context) except * with gil: server = _server method_name = _method_name @@ -117,10 +117,10 @@ cdef public VoidPromise * call_server_method(PyObject * _server, char * _method_ return NULL -cdef public convert_array_pyobject(PyArray & arr) with gil: +cdef api convert_array_pyobject(PyArray & arr) with gil: return [arr[i] for i in range(arr.size())] -cdef public PyPromise * extract_promise(object obj) with gil: +cdef api PyPromise * extract_promise(object obj) with gil: if type(obj) is _Promise: promise = <_Promise>obj @@ -131,7 +131,7 @@ cdef public PyPromise * extract_promise(object obj) with gil: return NULL -cdef public RemotePromise * extract_remote_promise(object obj) with gil: +cdef api RemotePromise * extract_remote_promise(object obj) with gil: if type(obj) is _RemotePromise: promise = <_RemotePromise>obj promise.is_consumed = True @@ -235,20 +235,20 @@ class KjException(Exception): return AttributeError(message) return self -cdef public object wrap_kj_exception(capnp.Exception & exception) with gil: +cdef api object wrap_kj_exception(capnp.Exception & exception) with gil: PyErr_Clear() wrapper = _KjExceptionWrapper()._init(exception) ret = KjException(wrapper=wrapper) return ret -cdef public object wrap_kj_exception_for_reraise(capnp.Exception & exception) with gil: +cdef api object wrap_kj_exception_for_reraise(capnp.Exception & exception) with gil: wrapper = _KjExceptionWrapper()._init(exception) ret = KjException(wrapper=wrapper) return ret -cdef public object get_exception_info(object exc_type, object exc_obj, object exc_tb) with gil: +cdef api object get_exception_info(object exc_type, object exc_obj, object exc_tb) with gil: try: return (exc_tb.tb_frame.f_code.co_filename.encode(), exc_tb.tb_lineno, (repr(exc_type) + ':' + str(exc_obj)).encode()) except: @@ -3250,7 +3250,6 @@ cdef class _MessageBuilder: .. warning:: Don't ever instantiate this class directly. It is only used for inheritance. """ - cdef schema_cpp.MessageBuilder * thisptr def __dealloc__(self): del self.thisptr @@ -4080,3 +4079,7 @@ def remove_import_hook(): if _importer is not None: _sys.meta_path.remove(_importer) _importer = None + +def _init_capnp_api(): + """ Initialize static function pointers for cdef api functions. """ + init_capnp_api() diff --git a/setup.py b/setup.py index 2c86de8..a6976de 100644 --- a/setup.py +++ b/setup.py @@ -168,7 +168,7 @@ if os.name == 'nt': import Cython.Build import Cython # noqa: F401 extensions = [Extension( - '*', ['capnp/lib/*.pyx'], + '*', ['capnp/helpers/capabilityHelper.cpp', 'capnp/lib/*.pyx'], extra_compile_args=extra_compile_args, extra_link_args=extra_link_args, language='c++',