0

I am having a problem with calling a simple python script from C++. I have a simple testcase to illustrate the problem; In the python script - func fb should call fa which has previously defined.

However I get an error:

Called fb

Traceback (most recent call last):
    File "<string>", line 1, in <module>
    File "<string>", line 13, in <module>
    File "<string>", line 10, in fb
NameError: name 'fa' is not defined

The file test.py:

def fa() :
       print('Called fa')
       return 3
def fb() :
       print('Called fb')
       return fa() * 2
fb()
print('Finished test.py')

The C++ code:

#ifdef _DEBUG
#undef _DEBUG
#include <Python.h>
#define _DEBUG
#else
#include <Python.h>
#endif
#include <string>
int main() {

    // Initialize the python interpreter, setting path
    const char * app_path = "C:\\Python383-x64\\";
    size_t convertedChars = 0;
    size_t newsize = strlen(app_path);
    wchar_t* wcstring = new wchar_t[newsize];
    mbstowcs_s(&convertedChars, wcstring, newsize, app_path, _TRUNCATE);
    Py_SetPythonHome(wcstring);
    Py_Initialize();

    // Create dicts for globals and locals
    PyObject* globals = PyDict_New();
    PyObject* locals = PyDict_New();

    // Set the builtins
    PyDict_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());

    // Evaluate python code and get the result
    PyObject* string_result = PyRun_String("exec(open(\"test.py\").read())",     Py_single_input, globals, locals);

    // check whether the python code caused any Exception
    if (PyErr_Occurred()) {
        PyErr_Print(); PyErr_Clear(); return 1;
    }
    else {
        // print the result
        PyObject_Print(string_result, stdout, Py_PRINT_RAW);
    }
    return 0;
}
5
  • It compiles and runs for me, on VC 2026. Commented Feb 25 at 10:44
  • It was missing a closing bracket during cut&paste, sorry. That should have been obvious. Why the '#undef _DEBUG', it's because otherwise its looking for the debug version of python which wasn't present in the python library. Commented Feb 25 at 11:09
  • 1
    I'd also point out that using PyRun_SimpleString("exec(open(\"test.py\").read())") works, i.e. prints 'Called fb' then 'Called fa'. So I'm guessing its something to do with setting globals/locals. Commented Feb 25 at 11:19
  • 2
    Look at PyRun_SimpleString source code, you will see that it is setting globals/locals differently. Commented Feb 25 at 11:30
  • Thanks! Yes adding: PyObject* main_module = PyImport_AddModule("main"); PyObject* dict = PyModule_GetDict(main_module); and using dict for globals/locals works. Commented Feb 25 at 11:38

1 Answer 1

2

So the answer was to add __main__ to the dicts.

#ifdef _DEBUG
#undef _DEBUG
#include <Python.h>
#define _DEBUG
#else
#include <Python.h>
#endif
#include <string>
int main() {

    // Initialize the python interpreter, setting path
    const char * app_path = "C:\\Python383-x64\\";
    size_t convertedChars = 0;
    size_t newsize = strlen(app_path);
    wchar_t* wcstring = new wchar_t[newsize];
    mbstowcs_s(&convertedChars, wcstring, newsize, app_path, _TRUNCATE);
    Py_SetPythonHome(wcstring);
    Py_Initialize();

    // Create dicts for globals and locals
    PyObject* main_module = PyImport_AddModule("__main__");
    PyObject* locals = PyModule_GetDict(main_module);
    PyObject* globals = PyModule_GetDict(main_module);
    PyDict_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());

    // Evaluate python code and get the result
    PyObject* string_result = PyRun_String("exec(open(\"test.py\").read())", Py_file_input, globals, locals);

    // check whether the python code caused any Exception
    if (PyErr_Occurred()) {
        PyErr_Print(); PyErr_Clear(); return 1;
    }
    return 0;
}
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.