I am embedding Python into a C++ application.
When I run the following piece of C++ code, which returns me the timestamp, it works fine.
Py_Initialize();
std::string strModule = "time"; // module to be loaded
pName = PyString_FromString(strModule.c_str());
pModule = PyImport_Import(pName); // import the module
pDict = PyModule_GetDict(pModule); // get all the symbols in the module
pFunc = PyDict_GetItemString(pDict, "time"); // get the function we want to call
// Call the function and get the return in the pValue
pValue = PyObject_CallObject(pFunc, NULL);
if (pValue == NULL){
printf('Something is wrong !');
return 0;
}
printf("Return of python call : %d\n", PyInt_AsLong(pValue)); // I get the correct timestamp
Py_Finalize();
Now I want to get the sys.path. But the similar code throws me error:
Py_Initialize();
std::string strModule = "sys"; // module to be loaded
pName = PyString_FromString(strModule.c_str());
pModule = PyImport_Import(pName); // import the module
pDict = PyModule_GetDict(pModule); // get all the symbols in the module
pFunc = PyDict_GetItemString(pDict, "path"); // get the function we want to call
// Call the function and get the return in the pValue
pValue = PyObject_CallObject(pFunc, NULL);
if (pValue == NULL){
printf('Something is wrong !'); // I end up here, why pValue is NULL?
return 0;
}
printf("Return of python call : %d\n", PyInt_AsLong(pValue));
Py_Finalize();
I guess the problem is that time.time() is a function call whereas sys.path is a variable. If that is the case:
How to get the result of a variable?
How to properly translate the result (in this case a list) to something meaningful in C++ for e.g. an array of strings?
If not, how to proceed? I am using Python 2.7.6
Thanks.
Your problem is that PyDict_GetItemString(pDict, "path") will return python list and it is not callable. And when you execute PyObject_CallObject(pFunc, NULL); you will execute it. This is equal to sys.path().
This should work:
PyObject *pName, *pModule, *pDict, *list, *pValue, *item;
int n, i;
char *name;
Py_Initialize();
std::string strModule = "sys"; // module to be loaded
pName = PyString_FromString(strModule.c_str());
pModule = PyImport_Import(pName); // import the module
pDict = PyModule_GetDict(pModule); // get all the symbols in the module
list = PyDict_GetItemString(pDict, "path"); // get python list
n = PyList_Size(list);
if (n < 0)
return -1; /* Not a list */
for (i = 0; i < n; i++) { // iterate over list
item = PyList_GetItem(list, i); /* Can't fail */
if (!PyString_Check(item)) continue; /* Skip non-string */
name = PyString_AsString(item);
std::puts(name);
}
Py_Finalize();
return 0;
Full code here.
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 am trying to pass a list to python from cpp and taking it back. Initially I tried to pass a single value and get back one value. It worked. Now I am trying to pass the complete array/list Below is my cpp code:
#include <iostream>
#include <Python.h>
#include <numpy/arrayobject.h>
#include <typeinfo>
using namespace std;
int main()
{
Py_Initialize();
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyString_FromString("."));
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
// Build the name object
pName = PyString_FromString("mytest");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyObject_GetAttrString(pModule, "stuff");
if (!PyCallable_Check(pFunc))
PyErr_Print();
PyObject *list = PyList_New (5);
Py_ssize_t size = PyList_GET_SIZE(list);
for(Py_ssize_t s = 0; s < size; s++ )
{
PyList_SetItem(list, s, Py_BuildValue("d", 2.5));
}
PyObject* result = PyObject_CallObject(pFunc, list);
if(result==NULL)
{cout << "FAILED ..!!" << endl;}
cout << result << endl;;
return 0;
}
I am always getting "FAILED..!!".
Here is my mytest.py
def stuff(a):
x=a
return x
Any suggestions where I might be going wrong?
From the documentation:
PyObject* PyObject_CallObject(PyObject *callable, PyObject *args)
This is the equivalent of the Python expression: callable(*args).
Whereas PyObject_CallFunctionObjArgs is documented as:
PyObject* PyObject_CallFunctionObjArgs(PyObject *callable, ..., NULL)
This is the equivalent of the Python expression: callable(arg1, arg2, ...).
So change your call to the following:
PyObject* result = PyObject_CallFunctionObjArgs(pFunc, list, NULL);
(or you could wrap your list inside another list and keep on using CallObject, but this is by far the easier solution)
I want to call the Python function in C++ using python.h but there are some problems.
Here is my Python function sample
def function1(tuple1, tuple2, string1, string2 ,string3, double1, string4 = ""):
...
and the C++ sample
double function_adapter(const vector<double> &vec1, const vector<double> &vec2, const string &string1, const string &string2, const string &string3, const double double1, const string &string4)
{
Py_Initial();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\"./\")");
PyObject *pModule, *pFunc, *pRes;
pModule = PyImport_Import(PyString_FromString("PythonFile"));
pFunc = PyObject_GetAttrString(pModule, "function1");
PyObject *pArgs = PyTuple_New(7);
PyObject *pVec1 = PyTuple_New(vec1.size());
for(size_t i = 0; i < vec1.size(); ++i) {
PyTuple_SetItem(pVec1, i, Py_BuildValue("f", vec1[i]));
}
PyObject *pVec2 = PyTuple_New(vec2.size());
for(size_t i = 0; i < vec2.size(); ++i) {
PyTuple_SetItem(pVec2, i, Py_BuildValue("f", vec2[i]));
}
PyObject *pString1 = Py_BuildValue("s", string1);
PyObject *pString2 = Py_BuildValue("s", string2);
PyObject *pString3 = Py_BuildValue("s", string3);
PyObject *pDouble1 = Py_BuildValue("f", double1);
PyObject *pString4 = Py_BuildValue("s", string4);
PyTuple_SetItem(pArgs, 0, pVec1);
PyTuple_SetItem(pArgs, 1, pVec2);
PyTuple_SetItem(pArgs, 2, pString1);
PyTuple_SetItem(pArgs, 3, pString2);
PyTuple_SetItem(pArgs, 4, pString3);
PyTuple_SetItem(pArgs, 5, pDouble1);
PyTuple_SetItem(pArgs, 6, pString4);
pRes = PyObject_CallObject(pFunc, pArgs);
if(pRes == NULL) {
return -2;
}
int res = PyLong_AsLong(pRes);
Py_DecRef(pModule);
.
.
.
Py_Finalize();
return res;
}
But the pRes returns NULL. And the PyObject_CallObject is just like a blackbox, I can't step in to look how it works.
So I want to ask that is there anything wrong in my code?
And the arguments preparation is right or not? (There are few examples in this case on the internet.)
A CPython API function that returns NULL means that an error has occurred. You can use the PyErr_* set of API functions to query this exception.
For debugging, the most useful is probably PyErr_Print(), which will just print the exception and stack trace (if any) to stderr.
Make sure to double check that pModule and pFunc are not NULL. The exception may have occurred when trying to import the module or get the function from the module. CPython does not raise exceptions, it just returns NULL on an error. So checking the return value of C-API functions is important.
I had an image processing function (IMP) written in Python using OpenCV lib.
Now I would like to call IMP from C code:
#include "/usr/include/python2.7/Python.h"
int main()
{
PyObject *pName, *pModule, *pDict, *pFun, *pValue, main_module;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyString_FromString("test");
if(pName)printf("OK\n");
// Load the module object
pModule = PyImport_Import(pName);
// pFunc is also a borrowed reference
pFun = PyObject_GetAttrString(pModule, "IMP");
if (PyCallable_Check(pFun))
{
//PyObject_CallObject(pFun, NULL);
PyObject_CallFunction(pFun,"o",framebuffer);
}
else
{
PyErr_Print();
}
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
Py_DECREF(pFun);
// Finish the Python Interpreter
Py_Finalize();
getchar();
return 0;
}
How do I prepare "framebuffer" to pass into my IMP python function?
could anyone help to show me an example image packaged in an object understood by CV2 and pass it to IMP using the above example C code? Thanks a lot for your help.
I think I found what I need: just create a template "framebuffer" in my test.py:
import numpy as np
import cv2
framebuffer = cv2.imread('pic.jpg',cv2.IMREAD_COLOR)
def IMP(p):
print "I am here!"
print "image.shape h,w,d=",p.shape
cv2.imshow("picture",p)
cv2.waitKey(0)
cv2.destroyAllWindows()
and then in my test.c, I grep the "framebuffer" from pDict for further manipulation then call IMP:
#include "/usr/include/python2.7/Python.h"
#include <numpy/arrayobject.h>
int main()
{
PyObject *pName, *pModule, *pDict, *pFun, *pValue, *pArgs, *pFB;
int i,j;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyString_FromString("test");
if(pName)printf("OK\n");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFun = PyDict_GetItemString(pDict, "IMP");
pFB = PyDict_GetItemString(pDict, "framebuffer");
if (pFB != NULL)
printf("got the framebuffer as pFB!\n");
//copy a new framebuffer into pFB here!!!
uint8_t *ptr;
ptr = PyArray_DATA(pFB);
int col,row,color;
int NCOL = 0, NROW = 0, NCLR = 0;
int ndim=0;
ndim = PyArray_NDIM(pFB);
NROW = PyArray_DIM(pFB,0);
NCOL = PyArray_DIM(pFB,1);
NCLR = PyArray_DIM(pFB,2);
for (row=0;row<NROW;row++)
for (col=0;col<NCOL;col++)
for (color=0;color<NCLR;color++)
{
*ptr = pixel_value; //copy your framebuffer pixel value to pFB!!!
ptr++;
}
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs,0,pFB);
if (PyCallable_Check(pFun))
{
PyObject_CallObject(pFun, pArgs); //call python IMP with updated framebuffer!!!
}
else
{
PyErr_Print();
}
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
//Py_DECREF(pDict); //do not decref on pDict because it is borrowed ref, otherwise it will crash Py_Finalize()!!!
//Py_DECREF(pArgs);
//Py_DECREF(pFun);
//Py_DECREF(pFB);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
That's it!
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]);