[C++-sig] Passing opaque data to C++ callback from Python

Stefan Seefeld stefan at seefeld.name
Thu Dec 18 18:16:39 CET 2014


On 16/12/14 11:13 PM, Peter LaDow wrote:
> I'm embedding Python (using boost::python) into an application plugin
> that uses callbacks. Essentially, I want to do something like:
>
> In Python (say test.py):
>
> def do_something():
>   ...
>
> register_callback(do_something)
>
> And on the C++ side I register the register_callback() function:
>
> void register_callback(boost::python::object& o)
> {
>     // Access some persistent state information
> }

You defined 'do_something' as a callback, and registered it so it could
be called from C++, yes ? Then, in your implementation of
'register_callback', 'o' is actually a reference to your callback
function. Do you want to access the persistent state while registering
the callback, or from within the callback ? Or am I misreading the code
above ?

        Stefan

> BOOST_PYTHON_MODULE(foo)
> {
>   boost::python::def("register_callback", register_callback);
> }
>
> void library_entry()
> {
>   PyImport_AppendInittab("foo", initfoo);
>
>   PyInitialize();
>
>   // Create some persistent state information
>
>   boost::python::exec_file("test.py", ...);
> }
>
> The issue here is that I need to create the Python context and store
> things away in an opaque pointer I return to the application. And when
> Python calls back into the C++, I need to recover that opaque value.
> For example:
>
> Application -- (calls) --> my C++ library -- (runs) --> Python script
> -- (calls) --> my C++ library
>
> For that last step, I need to recover some opaque data. Further, I
> need that opaque data to be persistent. The calls into my C++ library
> are callbacks from the application. The issue I'm having is trying to
> figure out how to pass that state information to the C++
> register_callback() function. I've tried something like:
>
> namespace bp = boost::python;
>
> class state_info_t
> {
> };
>
> void register_callback(std::shared_ptr<state_info_t>& state, bp::object& o);
> {
>   // Access some persistent state information
> }
>
> // Create some persistent state information
> std::shared_ptr<state_info_t> state = std::make_shared<state_info_t>();
>
> PyImport_AppendInittab("foo", initfoo);
>
> Py_Initialize();
>
> std::shared_ptr<bp::object> main_module =
> std::make_shared<bp::object>(bp::handle<>(bp::borrowed(PyImport_AddModule("__main__"))));
> bp::object main_namespace = main_module->attr("__dict__");
> std::shared_ptr<bp::object> foo_module =
> std::make_shared<bp::object>(bp::handle<>(PyImport_ImportModule("foo")));
>
> main_namespace["foo"] = *foo_module;
>
> bp::scope foo_scope(*foo_module);
>
> // Both of these fail with _a lot_ of errors, most related to "no
> matching function call to 'get_signature'
> bp::def("register_callback",
>         [&](bp::object& o) { register_callback(state, o); },
>         bp::arg("func"));
>
> bp::def("register_callback",
>         std::bind(register_callback, state, std::placeholders::_1),
>         bp::arg("func"));
>
> The other thought I had was to store the persistent data in the
> module's dictionary. But I don't know how to recover it in the
> callback. For example:
>
> // Create some persistent state information
> std::shared_ptr<state_info_t> state = std::make_shared<state_info_t>();
>
> PyImport_AppendInittab("foo", initfoo);
>
> Py_Initialize();
>
> std::shared_ptr<bp::object> main_module =
> std::make_shared<bp::object>(bp::handle<>(bp::borrowed(PyImport_AddModule("__main__"))));
> bp::object main_namespace = main_module->attr("__dict__");
> std::shared_ptr<bp::object> foo_module =
> std::make_shared<bp::object>(bp::handle<>(PyImport_ImportModule("foo")));
> bp::object foo_namespace = main_module->attr("__dict__");
>
> main_namespace["foo"] = *foo_module;
> foo_namespace["state"] = bp::handle<>(state); // Whatever the
> appropriate wrapper is
>
> Then in C++ side of register_callback:
>
> void register_callback(bp::object& o)
> {
>   // How do I extract "state" from the context?
> }
>
> I'm not keen on this last one, since it exposes the state information
> to the script.
>
> I don't want to make the state information global since there may be
> multiple running Python instances. And regardless, with multiple
> Python instances I still need a way to determine which Python instance
> is running to select the appropriate state information.
>
> Any suggestions?
> _______________________________________________
> Cplusplus-sig mailing list
> Cplusplus-sig at python.org
> https://mail.python.org/mailman/listinfo/cplusplus-sig


-- 

      ...ich hab' noch einen Koffer in Berlin...



More information about the Cplusplus-sig mailing list