Search code examples
pythoncpython-3.ximportembedding

Embedding Python into C - can't import method from python module


I'm building C application which will be using Python plugins. When trying to call the method from another Python module, the function PyImport_ImportModule() seems to imports the module properly, then i try to get the function from this module using PyObject_GetAttrString() and all that I get is null.

I already tried using PyModule_GetDict() and PyDict_GetItemString() to get the method from the module, but the effect was the same.

main.c:

#include <stdio.h>
#include <python3.6/Python.h>

int main()
{
    PyObject *arg, *pModule, *ret, *pFunc, *pValue, *pMethod, *pDict;
    Py_Initialize();
    PyObject *sys = PyImport_ImportModule("sys");
    PyObject *path = PyObject_GetAttrString(sys, "path");
    PyList_Append(path, PyUnicode_FromString("."));

    pModule = PyImport_ImportModule("test");
    if(pModule == NULL)
    {
        perror("Can't open module");
    }
    pMethod = PyObject_GetAttrString(pModule, "myfun");
    if(pMethod == NULL)
    {
        perror("Can't find method");
    }

    ret = PyEval_CallObject(pMethod, NULL);
    if(ret == NULL)
    {
        perror("Couldn't call method");
    }

    PyArg_Parse(ret, "&d", pValue);
    printf("&d \n", pValue);

    Py_Finalize();
    return 0;
}

test.py:

def myfun():
  c = 123 + 123
  print('the result is: ', c)

myfun()

The result i got is:

Can't find method: Success
Segmentation fault (core dumped)

When I used the gdb debugger the output was:

pModule = (PyObject *) 0x7ffff5a96f48
pMethod = (PyObject *) 0x0

Solution

  • Your program is not wroking because the module being imported is the test built-in module, rather than your test.py script. This is because you are appending the current directory to sys.path, so it is checked after every other already existing path in the list. You should insert it at the beginning of the list instead, so that it is checked first.

    This will work:

    PyObject *sys = PyImport_ImportModule("sys");                                                                                                                                                                     
    PyObject *path = PyObject_GetAttrString(sys, "path");                                                                                                                                                     
    PyList_Insert(path, 0, PyUnicode_FromString("."));
    

    By the way, you should #include the Python header before anything else, as stated in the documentation:

    Note: Since Python may define some pre-processor definitions which affect the standard headers on some systems, you must include Python.h before any standard headers are included.