Garrett
Garrett

Reputation: 125

How can embedded python call a C++ class's function?

So, StackOverflow, I'm stumped.

The code as I have it is a C++ function with embedded Python. I generate a message on the C++ side, send it to the python, get a different message back. I got it to work, I got it tested, so far, so good.

The next step is that I need Python to generate messages on their own and send them into C++. This is where I'm starting to get stuck. After spending a few hours puzzling over the documentation, it seemed like the best way would be to define a module to hold my functions. So I wrote up the following stub:

static PyMethodDef mailbox_methods[] = {
    { "send_external_message", 
      [](PyObject *caller, PyObject *args) -> PyObject *
      {
         classname *interface = (classname *) 
             PyCapsule_GetPointer(PyTuple_GetItem(args, 0), "turkey");
         class_field_type toReturn;
         toReturn = class_field_type.python2cpp(PyTuple_GetItem(args, 1));
         interface ->send_message(toReturn);
         Py_INCREF(Py_None);
         return Py_None;
     },
     METH_VARARGS, 
     "documentation" },
     { NULL, NULL, 0, NULL }
};

static struct PyModuleDef moduledef = {
    PyModuleDef_HEAD_INIT,
    "turkey",
    "documentation",
    -1,
    mailbox_methods
};

//defined in header file, just noting its existence here
PyObject *Module;

PyMODINIT_FUNC PyInit_turkey()
{
    Module = PyModule_Create(&moduledef);
    return Module;
}

And on the Python side, I had the following receiver code:

import turkey

I get the following response:

ImportError: No module named 'turkey'

Now, here's the part where I get really confused. Here's the code in my initialization function:

PyInit_turkey();
PyObject *interface = PyCapsule_New(this, "instance", NULL);
char *repr = PyUnicode_AsUTF8(PyObject_Repr(Module));
cout << "REPR: " << repr << "\n";
if (PyErr_Occurred())
    PyErr_Print();

It prints out

REPR: <module 'turkey'>
Traceback (most recent call last):
    <snipped>
    import turkey
ImportError: No module named 'turkey'

So the module exists, but it's not ever being passed to Python anywhere. I can't find documentation on how to pass it in and get it initialized on the Python side. I realize that I'm probably just missing a trivial step, but I can't for the life off me figure out what it is. Can anyone help?

Upvotes: 2

Views: 892

Answers (1)

Garrett
Garrett

Reputation: 125

The answer was, in the end, a single function that I was missing. Included at the start of my initialization function, before I call Py_Initialize:

PyImport_AppendInittab("facade", initfunc);
Py_Initialize();
PyEval_InitThreads();

The Python documentation does not mention PyImport_AppendInittab except in passing, and this is why I was having such a difficult time making the jump.

To anyone else who finds this in the future: You do not need to create a DLL to extend python or use a pre-built library to bring a module into Python. It can be far easier than that.

Upvotes: 1

Related Questions