I'm back to programming in a project and i'm getting no return from the python script for some long hours now.
Funny thing is, a couple of months ago i managed to get this working, now i don't know what's wrong
Where's the C++ code:
int CPythonPlugIn::py_embed(int argc, char *argv[]){
ofstream textfile3;
textfile3.open("FP_python_embed.txt");
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
if(argc<3){
printf("Usage: exe_name python_source function_name\n");
return 1;
}
//To inform the interpreter about paths to Python run-time libraries
Py_SetProgramName(argv[0]);
// Initialize the Python Interpreter
Py_Initialize();
if( !Py_IsInitialized() ){
cout<<"Can't initialize"<<endl;
return -1;
}
// Build the name object
pName = PyString_FromString(argv[1]);
if( !pName ){
cout<<"Can't build the object "<<endl;
return -1;
}
// Load the module object
pModule = PyImport_Import(pName);
if( !pModule ){
cout<<"Can't import the module "<<endl;
return -1;
}
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
if( !pDict ){
cout<<"Can't get the dict"<<endl;
return -1;
}
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, argv[2]);
if( !pFunc || !PyCallable_Check(pFunc) ){
cout<<"can't get the function"<<endl;
return -1;
}
if (PyCallable_Check(pFunc))
{
// Prepare the argument list for the call
if( argc > 3 )
{
pArgs = PyTuple_New(argc - 3);
for (int i = 0; i < argc - 3; i++)
{
pValue = PyInt_FromLong(atoi(argv[i + 3]));
if (!pValue)
{
PyErr_Print();
return 1;
}
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
textfile3<<PyInt_AsLong(pValue)<<endl<<" worked1";
if (pArgs != NULL)
{
Py_DECREF(pArgs);
}
}
else
{
pValue = PyObject_CallObject(pFunc, NULL);
}
if (pValue != NULL)
{
printf("Return of call : %d\n", PyInt_AsLong(pValue));
textfile3<<PyInt_AsLong(pValue)<<endl<<" worked2";
Py_DECREF(pValue);
}
else
{
PyErr_Print();
}
textfile3.close();
}
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
};
and this is how i call this function:
char *arg[4]={"PythonPlugIn2","bridge","test_callsign","MAH545"};
py_embed(4,arg);
the simple python script:
def test_callsign(b):
fp_txt=open('allomate.txt','w+')
fp_txt.write('WHAT')
fp_txt.write(b)
if b=='MAH545':
fp_txt.write('MAHHH')
fp_txt.close()
return 1
elif b=='MAH544':
fp_txt.close()
return 2
elif b=='AFR545':
fp_txt.close()
return 3
else:
fp_txt.write('MAHHH22')
print 'No such airplane'
fp_txt.close()
return 10
The allomate.txt is created and it has only "WHAT" written on it. The FP_python_embed.txt also is created and has "-1, worked1" so the problem needs to be on pValue which is giving NULL for some reason
Thank you in advance for the help
I finally found the solution. I was parsing the pValue not as a string but as an int.
So, where i had:
pValue = PyInt_FromLong(atoi(argv[i + 3]));
it really should be:
pValue = PyString_FromString(argv[i+3]);
Related
So, I'm trying to use Python with C++ in order to read a text file and search that text file for the specific input received from C++ (a string value) It should then return a numeric value of the string frequency in that text file back to the C++ code. As the code is, it only returns "1" on the display of my program. Any tips?
def ItemFreq(v):
#Opening and reading the input item list file
file = open("ItemList.txt", "r")
text = file.read()
#Output our list in a new line format
word_list = text.split('\n')
#Declare an empty dictionary
word_freq = {}
for word in word_list:
word_freq[word] = word_freq.get(word, 0) + 1
if v in word_freq:
return word_freq[v]
else:
return 0
CPP portion with the user input prompt
// Option 2 for our specific item purchase information
else if (a == 2) {
int v;
cout << "Please enter the name of an item to begin search: ";
cin >> v;
// Print our returned input from Python
cout << callIntFunc("ItemFreq", v) << endl;
system("pause");
}
And the Python integration in my CPP file
int callIntFunc(string proc, string param)
{
char *procname = new char[proc.length() + 1];
std::strcpy(procname, proc.c_str());
char *paramval = new char[param.length() + 1];
std::strcpy(paramval, param.c_str());
PyObject *pName, *pModule, *pDict, *pFunc, *pValue = nullptr, *presult = nullptr;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyUnicode_FromString((char*)"PythonCode");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, procname);
if (PyCallable_Check(pFunc))
{
pValue = Py_BuildValue("(z)", paramval);
PyErr_Print();
presult = PyObject_CallObject(pFunc, pValue);
PyErr_Print();
}
else
{
PyErr_Print();
}
//printf("Result is %d\n", _PyLong_AsInt(presult));
Py_DECREF(pValue);
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
// clean
delete[] procname;
delete[] paramval;
return _PyLong_AsInt(presult);
}
int callIntFunc(string proc, int param)
{
char *procname = new char[proc.length() + 1];
std::strcpy(procname, proc.c_str());
PyObject *pName, *pModule, *pDict, *pFunc, *pValue = nullptr, *presult = nullptr;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyUnicode_FromString((char*)"PythonCode");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, procname);
if (PyCallable_Check(pFunc))
{
pValue = Py_BuildValue("(i)", param);
PyErr_Print();
presult = PyObject_CallObject(pFunc, pValue);
PyErr_Print();
}
else
{
PyErr_Print();
}
//printf("Result is %d\n", _PyLong_AsInt(presult));
Py_DECREF(pValue);
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
// clean
delete[] procname;
return _PyLong_AsInt(presult);
}
I used the code in this answer to create the following file
callpython.c
#include </usr/include/python2.7/Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
pName = PyString_FromString(argv[1]);
/* Error checking of pName left out */
//fprintf(stderr,"pName is %s\n", pName);
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\".\")");
//PySys_SetArgv(argc, argv);
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
pValue = PyInt_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* iValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
//PyTuple_SetItem(pArgs, i, argv[i + 3]);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
Py_Finalize();
return 0;
}
I created another file in the same directory as helloWorld.py. The contents of this python script are
def helloworldFunc(a):
print 'Hello '+str(a)
I compile and run callpython.c as below
g++ -o callpython callpython.c -lpython2.7 -lm -L/usr/lib/python2.7/config && ./callpython helloworld helloworldFunc world
Rather than printing "Hello world", it prints "Hello 0"
Why does it not parse the python function argument as string?
The sample code is parsing the arguments as integers, buy you've passed a string. atoi("world") returns 0, so that's the integer you get:
/* Create tuple of the correct length for the arguments. */
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
/* Convert each C argv to a C integer, then to a Python integer. */
pValue = PyInt_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* iValue reference stolen here: */
/* Store the Python integer in the tuple at the correct offset (i) */
PyTuple_SetItem(pArgs, i, pValue);
}
Change the conversion line to the following to handle any string:
pValue = PyString_FromString(argv[i + 3]);
Solved the issue. The culprit was this line
pValue = PyInt_FromLong(atoi(argv[i + 3]));
It was parsing each argument to python script as an integer.
When replaced with the following line, it parses each argument as a string
pValue = PyString_FromString(argv[i+3]);
I haven't really understood how pValue works, but this solves the problem for now.
I'm using embedded python interpreter in my app (iOS to be detailed).
Sometimes sys.exit(1) is invoked in interpreted script and it finishes the whole app process instead of stopping PyObject_callObject() invocation. I've tried to check errors using PyErr_Occured but it did not help.
How to prevent sys.exit(N) to finish the whole process in embedded python?
NSString *outputFile = nil;
for (int i=0; i<args.count; i++) {
if ([#"-o" isEqualToString:args[i]]) {
outputFile = args[i + 1];
break;
}
}
PyEval_AcquireLock();
PyThreadState *subState = Py_NewInterpreter();
PyObject *pModuleName, *pModule, *pFunc;
// init python
NSString *pythonHome = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:#"/"];
Py_SetProgramName("python");
char *cPythonHome = (char*)[pythonHome UTF8String];
setenv("PYTHONPATH", cPythonHome, 1); // VERY IMPORTANT !!!
Py_SetPythonHome(cPythonHome);
NSString *libsPath = [pythonHome stringByAppendingString:#"lib/python2.7"];
if (!Py_IsInitialized())
Py_Initialize();
// invoke
int result = 0;
NSString *scriptFilename = args[1];
NSString *moduleName = [[scriptFilename lastPathComponent] stringByDeletingPathExtension];
pModuleName = PyString_FromString([moduleName UTF8String]); // module (script) name
pModule = PyImport_Import(pModuleName);
if (PyErr_Occurred())
PyErr_Print();
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, "main__"); // module must have "def main__(args)"
if (pFunc != NULL && PyCallable_Check(pFunc)) {
// prepare args
PyObject *pArgs = PyList_New(args.count-1);
for (int i=0; i<args.count-1; i++) {
NSString *arg_i = args[i + 1]; // skip first argument (it's program name)
PyObject *pEachArg = PyString_FromString([arg_i UTF8String]);
PyList_SetItem(pArgs, i, pEachArg);
// WARNING: don't Py_DECREF for each argument
}
// for some reason arguments should be passed as s Tuple
PyObject *pTuple = PyTuple_New(1);
PyTuple_SetItem(pTuple, 0, pArgs);
// call func
NSLog(#"Invoke %# via main__(args)", scriptFilename);
PyObject *pyResult = PyObject_CallObject(pFunc, pTuple); // process killed here !
if (pyResult == NULL || PyErr_Occurred()) {
// print error
PyErr_Print();
// fix error
PyErr_Clear();
if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
result = 3; // error: system.exit() called
} else
result = 4; // error: unknown exception
}
if (pyResult != NULL)
Py_DECREF(pyResult);
Py_DECREF(pTuple);
Py_DECREF(pArgs);
} else
result = 2; // error: can't find "def main__()" in module
if (pFunc != NULL)
Py_XDECREF(pFunc);
} else
result = 1; // error: can't import module
if (pModule != NULL)
Py_DECREF(pModule);
Py_DECREF(pModuleName);
// restore parent interpreter
Py_EndInterpreter(subState);
PyEval_ReleaseLock();
I had to hack Python sources and create my own function:
int MyPyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags)
{
PyObject *m, *d, *v;
const char *ext;
int set_file_name = 0, ret, len;
m = PyImport_AddModule("__main__");
if (m == NULL)
return -1;
d = PyModule_GetDict(m);
if (PyDict_GetItemString(d, "__file__") == NULL) {
PyObject *f = PyString_FromString(filename);
if (f == NULL)
return -1;
if (PyDict_SetItemString(d, "__file__", f) < 0) {
Py_DECREF(f);
return -1;
}
set_file_name = 1;
Py_DECREF(f);
}
len = strlen(filename);
ext = filename + len - (len > 4 ? 4 : 0);
/*
if (maybe_pyc_file(fp, filename, ext, closeit)) {
// Try to run a pyc file. First, re-open in binary
if (closeit)
fclose(fp);
if ((fp = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "python: Can't reopen .pyc file\n");
ret = -1;
goto done;
}
// Turn on optimization if a .pyo file is given
if (strcmp(ext, ".pyo") == 0)
Py_OptimizeFlag = 1;
v = run_pyc_file(fp, filename, d, d, flags);
} else { */
v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d,
closeit, flags);
//}
if (v == NULL) {
//PyErr_Print(); // crashed here!
ret = -1;
goto done;
}
Py_DECREF(v);
if (Py_FlushLine())
PyErr_Clear();
ret = 0;
done:
if (set_file_name && PyDict_DelItemString(d, "__file__"))
PyErr_Clear();
return ret;
}
I had to use _SimpleFile instead of _SimpleString but i believe you can change _SimpleString in similar way.
The reason was PyErr_Print which caused app crash. The one drawback is that i had to comment pyc file checking and usage as maybe_pyc_file is not exported and is unavailable.
One more note: if SystemExit was raised (by sys.exit(1) f.e.) don't use PyErr_Print. Use the next checking:
if (PyErr_Occurred()) {
pythonSuccess = NO;
if (PyErr_ExceptionMatches(PyExc_SystemExit)) {
NSLog(#"sys.exit() in python");
} else {
// print error
PyErr_Print();
}
// fix error
PyErr_Clear();
}
If you have better solution, let us know.
I'm following this tutorial on Embedding Python on C, but their Pure Embedding example is not working for me.
I have on the same folder (taken from the example):
call.c
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
pName = PyString_FromString(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
pValue = PyInt_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
Py_Finalize();
return 0;
}
multiply.py
def multiply(a,b):
print "Will compute", a, "times", b
c = 0
for i in range(0, a):
c = c + b
return c
And I compile and run like this:
$ gcc $(python-config --cflags) call.c $(python-config --ldflags) -o call
call.c: In function ‘main’:
call.c:6:33: warning: unused variable ‘pDict’ [-Wunused-variable]
PyObject *pName, *pModule, *pDict, *pFunc;
^
# This seems OK because it's true that pDict is not used
$ ./call multiply multiply 3 2
ImportError: No module named multiply
Failed to load "multiply"
Why can't it load multiply module?
Example doesn't show filenames nor paths. Can it be a path problem?
Thanks a lot.
Try setting PYTHONPATH:
export PYTHONPATH=`pwd`
Really, the example should have PySys_SetPath("."); after initialization.
I have a solution in VisualStudio that contains two projects. The first project is a C++ console application with Pure Embedding as follows:
#include <Python.h>
int main(int argc, char *argv[]){
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
pName = PyUnicode_FromString(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
pValue = PyLong_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyLong_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
Py_Finalize();
return 0;}
When running a python file any works perfectly.
The second project contains some C++ classes compiled with SWIG. This project works perfectly using the Python script as below.
import example
x = 42
y = 105
example.gcd = g (x, y)
My problem is when the console application needs to run a python script that imports classes from the SWIG. If I use the python lib python32.lib works commenting on some parts of the code as "Py_DECREF (pArgs)" but I can only run once the python script, the second attempt, an error occurs the read access of memory. If I use python32_d.lib the construction of the modules do not work if the file import python SWIG:
pName = PyUnicode_FromString(argv[1]);
pModule = PyImport_Import(pName);
NOTE: I need to compile in DEBUG mode and not in RELEASE mode.