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
}

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@python.org
https://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to