2

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?

11
  • Are you actually asking anything about how to call a C++ class function here, or is this just about how to import C extension modules from an embedded Python? If the latter, please remove all the irrelevant stuff and rename the question, because it's pretty misleading as it stands. Commented Mar 8, 2018 at 21:46
  • Also, if you're using C++ rather than C, have you considered using PyCXX, boost::python, etc. instead of the raw C API? Because there's a lot of tricky stuff to get right—including the module definitions—that the various C++ wrappers help you with. Commented Mar 8, 2018 at 21:48
  • Use pybind11. Commented Mar 8, 2018 at 21:49
  • Finally, the easiest way to debug an extension module in embedded Python is to pull it out and build it as a stanxdalone extension module (commenting out any bits that depend on the embedding environment). And that has the added bonus of giving you an mcve that people on StackOverflow can actually help you debug. Commented Mar 8, 2018 at 21:51
  • Oh, one more thing: You can create the module from the C side, but can you import it from the C side? Start at PyImport_ImportModule and move down through the lower-level functions until you find one that goes the opposite direction. Commented Mar 8, 2018 at 21:56

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.