brita_
brita_

Reputation: 485

How to add a built-in module to a C-Python API after Py_Initialize?

I have a module defined in my C code like so:

static struct PyModuleDef module_def = {
    PyModuleDef_HEAD_INIT,
    "the_module_name",  /* m_name */
    module_documentation,  /* m_doc */
    //....
};

and a function to initialize it:

PyMODINIT_FUNC init_the_module(void)
{
    PyObject *mod, *submodule;
    PyObject *sys_modules = PyThreadState_GET()->interp->modules;

    mod = PyModule_Create(&module_def);

    PyModule_AddObject(mod, "some_submodule", (submodule = init_the_submodule()));
    PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
    Py_INCREF(submodule);

    // more submodules..

    return mod;
}

The application that I am embedding python into is quite big and I can not change the workflow much. At this point Py_Initialize has already been called, so I can not call PyImport_ExtendInittabor PyImport_AppendInittab . How can I create and add the module to the system modules? Maybe I can manipulate the modules dictionary directly? Like so:

PyObject *modules, *the_module;
modules = PyImport_GetModuleDict();

PyDict_SetItemString(modules, "the_module_name", init_the_module());

the_module = PyDict_GetItemString(modules, "the_module_name"); //this is getting something back
std::cout << PyDict_Size(the_module) << std::endl; // this prints -1

Upvotes: 2

Views: 1001

Answers (1)

The easiest way to handle this is to statically initialize your statically-linked modules by directly calling initspam() after the call to Py_Initialize() or PyMac_Initialize():

int main(int argc, char **argv)
{
    /* Pass argv[0] to the Python interpreter */
    Py_SetProgramName(argv[0]);

    /* Initialize the Python interpreter.  Required. */
    Py_Initialize();

    /* Add a static module */
    initspam();

An example may be found in the file Demo/embed/demo.c in the Python source distribution.

Upvotes: 1

Related Questions