I need to call a pipeline realized as a Python (3.6) function from my C++ project under the Windows platform. Function “function_name” from file "experiment_test.py" takes text string as input parameter and return another text string as the result. I try the code below but it doesn’t work properly – python functions from libraries shutil, codecs, makedirs, etc doesn’t work.
C++ code (reduced):
std::string Text,Result;
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
Py_Initialize();
pName = PyUnicode_FromString("experiment_test");
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, "function_name");
pArgs = PyTuple_New(1);
pValue = PyUnicode_FromString(Text.c_str());
PyTuple_SetItem(pArgs, 0, pValue);
if (PyCallable_Check(pFunc))
{
pValue = PyObject_CallObject(pFunc, pArgs);
if (pValue != NULL)
{
Result = PyUnicode_AsUTF8(pValue);
Py_DECREF(pValue);
}
else return false;
}
// ...
Py_Finalize();
Python code (reduced):
#!/usr/local/bin/python3
import shutil
import codecs
from os import makedirs
from os import path
from os import unlink
from subprocess import call
def function_name():
name = 'working_files/current_text'
if not path.exists('working_files'):
makedirs('working_files')
if path.exists('result.txt'):
unlink('result.txt')
with codecs.open(name + '.txt', 'w', encoding='utf-8') as f:
f.write(text)
# ...
return result
So no new files will be generated by Python. I tried to import Python modules in C++ by calling PyRun_SimpleString("import shutil"); etc after Py_Initialize(); but it doesn’t help.
What do I do wrong?
I tried replicating the problem with the given intel, but it was impossible, so I created a small example (as close as possible to what's described in the question) - Also referred to as [SO]: How to create a Minimal, Reproducible Example (reprex (mcve)) (that should be included in the question BTW)
So, the problem that I'm illustrating here, is:
I am using (on Win 10 x64 (10.0.16299.125)):
The structure consists of:
main.cpp:
Notes:
Build (compile / link) / Run options (obviously, you got past these, since you were able to run your program, but I'm going to list them anyway - for sure there are some shortcuts here, when dealing with more than one such project):
Notes:
This path contains (as expected) a Release version, and this is fine as long as I don't need to get into Python code (and as long as I don't mess around with memory - as (when building my app in Debug mode) I have 2 C runtimes in my .exe - check the links below to see what happens when tampering with MSVC runtimes (UCRTs)):
Compile:
Let VStudio know about the Python include files location:
Link:
Let VSTudio know about the Python lib files location (if only pythonxx*.lib (%PYTHONCORE%) is required, nothing extra needed, since PYTHONCORE is included by default by Python code; otherwise, all the rest should be specified in the [MS.Docs]: .Lib Files as Linker Input:
Run / Debug - let:
experiment_test.py:
Notes:
test_dir\test_file.txt:
Output (VStudio console):