How to call a Python function that uses numpy from C++ code - python

I have the following Python module (actual module I want to use, has many more functions using numpy and tensorflow), but this is a representative example to reproduce the issue
import numpy as np
def get_random():
return np.random.random()
I want to call the function get_random from the following C++ program:
#include <Python.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]){
Py_Initialize();
if( !Py_IsInitialized() ){
printf("Initialize failed\n");
return -1;
}
PyRun_SimpleString("import sys");
//append path of numpy lib
PyRun_SimpleString("sys.path.append('/home/uji300/.pyenv/versions/venv/lib/python3.4/site-packages/numpy/core/include')");
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pRet;
pName = PyUnicode_DecodeFSDefault("numpytester");
pModule = PyImport_Import(pName);
if ( !pModule ){
return -1;
}
pDict = PyModule_GetDict(pModule);
if ( !pDict ){
return -1;
}
pFunc = PyDict_GetItemString(pDict, "get_random");
if ( !pFunc || !PyCallable_Check(pFunc) ){
return -1;
}
for( int i = 0; i < 5; ++i ){
printf(" ===========> START CALL PYTHON SCRIPT %d <===========\n", i + 1);
pRet = PyObject_CallObject(pFunc, NULL); // call the function
printf(" ===========> CALLING FINISHED %d <===========\n", i + 1);
double result = PyFloat_AsDouble(pRet); // get the return value by pRet
printf(" ===========> result = %f <===========\n", result);
}
Py_DECREF(pName);
Py_DECREF(pModule);
Py_DECREF(pArgs);
Py_DECREF(pRet);
Py_DECREF(pDict);
// close Python
Py_Finalize();
return 0;
}
The C++ program is then built with CMake and run. The call to the get_random() does not work. It returns -1 every time.
What is the right way to call a python function that uses numpy or tensorflow functions ?

Related

How do i fix a throw error when integrating Python and C++ Code? Is the issue with the way that I am calling the function from Python to c++?

Ok so I am trying to run a program that uses C++ and Python. The C++ code calls functions from the Python code. The code in C++ that is above main() was already provided and is not supposed to be edited. However, I keep getting the following error: Unhandled exception thrown: write access violation.
pValue was nullptr. When running the code with options 1 & 2. How do I fix this?
C++ Code
#include <Python.h>
#include <iostream>
#include <Windows.h>
#include <cmath>
#include <string>
#include <string.h>
using namespace std;
void CallProcedure(string pName)
{
char* procname = new char[pName.length() + 1];
std::strcpy(procname, pName.c_str());
Py_Initialize();
PyObject* my_module = PyImport_ImportModule("PythonCode");
PyErr_Print();
PyObject* my_function = PyObject_GetAttrString(my_module, procname);
PyObject* my_result = PyObject_CallObject(my_function, NULL);
Py_Finalize();
delete[] procname;
}
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);
}
void main()
{
int clicked = 0;
do {
int n = 0;
cout << "1: Display a Multiplication Table" << endl << "2: Double a Value" << endl << "3:
Exit" << endl;
cin >> clicked;
switch (clicked) {
case 1:
{ cout << "Please enter a numerical value . . ."<< endl;
cin >> n;
cout << callIntFunc("(MultiplicationTable)",n); }
break;
case 2:
{cout << "Please enter a numerical value . . ."<< endl;
cin >> n;
int dValue = callIntFunc("(DoubleValue)",n);
cout << "Doubled Value: " << dValue << endl; }
break;
case 3:
cout << "You are now exiting the program!" << endl;
break;
default:
cout << "Please enter a valid selection . . ."<< endl;
break;
}
} while (clicked != 3);
}
Python code
import re
import string
def printsomething():
print("Hello from python!")
def PrintMe(v):
print("You sent me: " + v)
return 100
def MultiplicationTable(v):
v = int(v)
for i in range(1, 11):
print(v, " x ", i, " = ", (v * i))
def DoubleValue(v):
return v * 2
def SquareValue(v):
return v * v
Just modify the python function to return 0 as follows;
def MultiplicationTable(v):
v = int(v)
for i in range(1, 11):
print(v, " x ", i, " = ", (v * i))
return 0

Using Boost to exchange python and C Numpy Array

I followed the tutorial on boost::python::numpy, found that numpy's ndarray and array could be shared inside C ++ code, and I found that using the Boost python example, I could call a python function in C ++ with arguments and return.
My goal is that boost python and python exchange numpy array values.
First, I tried to pass the numpy array to the python code with boost python. However, I only found a way to set the pylist to PyList_SET_ITEM by creating a pylist instead of a numpy array.
In C++
//https://docs.python.org/2.0/ext/buildValue.html
PyObject *Convert_Big_Array(long arr[], int length) {
PyObject *pylist, *item;
pylist = PyList_New(length);
if (pylist != NULL)
for (int i = 0; i < length; i++) {
item = PyLong_FromLong(arr[i]);
PyList_SET_ITEM(pylist, i, item);
}
return pylist;
}
int main() {
long arr[5] = { 4,3,2,6,10 };
// Python 3.x Version
Py_SetPythonHome(L"C:\\Users\\User\\Anaconda3");
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult;
Py_Initialize();
return 0;
}
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, (char*)"someFunction");
if (PyCallable_Check(pFunc)) {
pValue = Py_BuildValue("(O)", Convert_Big_Array(arr, 5));
PyErr_Print();
presult = PyObject_CallObject(pFunc, pValue);
PyErr_Print();
}
else {
PyErr_Print();
return 0;
}
boost::python::handle<> handle(presult);
std::cout << std::endl << "Python ndarray :" << p::extract<char const *>(p::str(handle)) << std::endl;
Py_DECREF(pValue);
Py_DECREF(pModule);
Py_DECREF(pName);
Py_Finalize();
return 0;
}
In Python
import numpy as np
def someFunction(text):
print(text)
return np.array([1,2,3])
With this code I find it very difficult to pass a very large C int array to Python. Is there a more efficient way?
First, if I can convert a C ++ array to ndarray using np :: from_data and then convert it to PyObject, I think I can pass this object itself to python.
Second, I want to convert PyObject (presult) created with PyObject_CallObject to np :: ndarray format. Now the code is just an example and the output is successful.
In other words, do you know how to convert ndarray (C ++) -> PyObject (C ++), PyObject (numpy c ++) -> ndarray (c ++)?
I got a answer, and post Here for others...
thank you.
//#include <Python.h>
#include <stdlib.h>
#include <boost/python/numpy.hpp>
#include <boost/python.hpp>
#include <iostream>
//
////#define BOOST_PYTHON_STATIC_LIB
//
using namespace boost::python;
namespace np = boost::python::numpy;
//https://stackoverflow.com/questions/10701514/how-to-return-numpy-array-from-boostpython/14232897#14232897
np::ndarray mywrapper() {
std::vector<short> v;
v.push_back(3);
v.push_back(5);
Py_intptr_t shape[1] = { v.size() };
np::ndarray result = np::zeros(1, shape, np::dtype::get_builtin<short>());
std::copy(v.begin(), v.end(), reinterpret_cast<short*>(result.get_data()));
//std::cout <<"C++ Memory Addr : " << std::dec << &result << std::endl;
return result;
}
//https://stackoverflow.com/questions/54904448/boost-python-nullptr-while-extracting-ndarray
int main() {
double t_end = 7;
long arr[5] = { 4,3,2,6,10 };
// Python 3.x Version
Py_SetPythonHome(L"C:\\Users\\YangwooKim\\Anaconda3");
//PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult;
Py_Initialize();
np::initialize();
object module = import("__main__");
object name_space = module.attr("__dict__");
exec_file("arbName.py", name_space, name_space);
object MyFunc = name_space["someFunction"];
object result;
//for(int i=0; i<1000000; i++)
result = MyFunc(mywrapper());
//printf("Result is %d\n", PyLong_AsLong(presult));
//np::ndarray py_array = np::from_object(boost::python::object(handle));
//auto k = extract<np::ndarray>();
//np::ndarray k = np::from_object(object);
//np::ndarray k = p::extract<np::ndarray>(object);
//const np::ndarray& ret = k();
auto result_array = extract<numpy::ndarray>(result);
const numpy::ndarray& ret = result_array();
int input_size = ret.shape(0);
short* input_ptr = reinterpret_cast<short*>(ret.get_data());
//std::cout << std::endl
// << "Python ndarray :" << p::extract<char const *>(p::str(object)) << std::endl;
std::cout << std::endl << "Python ndarray :" << input_size << std::endl;
for (int i = 0; i < input_size; ++i)
std::cout <<" " <<*(input_ptr + i) <<std::endl;
//Py_Finalize();
//Py_Finalize();
return 0;
}

PyModule_GetDict not adding custom functions and globals to the generated dictionary (Python27)

I've followed all of the basic steps trying to get a python module loaded in c++, however it seems that when I try to get the dictionary of items in the script, it ignores my functions and globals that I wanted to use inside. when I iterate through the items, all I get are the builtins, file, package, path, name, and doc attributes of the script, and nothing else. I checked __name__ and it is coming up correctly ("test.py" is my py file's name and it returns "test" just fine). When I actually try to load my functions or globals (test, qa), the PyDict_GetItemString function returns NULL. What have I done wrong such that in tutorials this works fine, but in my test application, it doesn't work?
here is my Py script, maybe I've forgotten to do something that would allow my items to be seen?
qa = "hello test"
def test(a):
q = "hello world, I am " + a
#print q
return q
here is my C++ code as well, maybe I've forgotten something here?
#include <iostream>
#include <Python.h>
int main() {
Py_Initialize();
PyObject
*pName,
*pModule,
*pDict,
*pFunc,
*pArgs,
*pValue;
// get filename as a pystring
pName = PyString_FromString("test");
std::cout << std::endl << pName;
// Import module from filename
pModule = PyImport_Import(pName);
std::cout << std::endl << pModule;
// build the module's dict
pDict = PyModule_GetDict(pModule);
std::cout << std::endl << pDict << " " << PyDict_Size(pDict);
PyObject* keys = PyDict_Keys(pDict);
int s = PyList_Size(keys);
for (int i = 0; i < s; ++i) {
PyObject* item = PyList_GetItem(keys, i);
printf("\n");
printf(PyString_AsString(item));
}
PyObject* testvar = PyDict_GetItemString(pDict, "qa");
printf(PyString_AsString(testvar));
// get a function from the dict
pFunc = PyDict_GetItemString(pDict, "test");
std::cout << std::endl << pFunc;
// build the arg tuple
pArgs = PyTuple_New(1);
// create an argument
pValue = PyString_FromString("cee programme");
// set an argument
PyTuple_SetItem(pArgs, 0, pValue);
// call the function with the func and the args
PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
// error checking
if (pResult == NULL) {
printf("\nis broek");
}
char* res = PyString_AsString(pResult);
// "destroy the interpreter"
Py_Finalize();
printf(res);
return 0;
}

Passing two parameters (int and array) to embedded Python function

I need to call Python function from my module and set two parameters for it: int and array.
For a now I get segfault during calling this function and I have no idea what I'm doing wrong. Could someone specify where my mistake is?
Function in my Python module app.py. It works if I call it from Python code:
def get_model(rate, signal):
mfcc_train = MFCC().compute(rate, signal)
with open('mfcc_test', 'wb') as f:
pickle.dump(mfcc_train, f)
return clf()._fit(mfcc_train)
My C code that calls the function above. The last pring is "Before calling"
#include <Python.h>
#include <stdio.h>
#include "wav.h"
#include <numpy/arrayobject.h>
int main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pArgs;
uint8_t *samples = NULL;
wavread("test.wav", &samples);
printf("No. of channels: %d\n", header->num_channels);
printf("Sample rate: %d\n", header->sample_rate);
printf("Bit rate: %dkbps\n", header->byte_rate*8 / 1000);
printf("Bits per sample: %d\n\n", header->bps);
printf("Sample 0: %d\n", samples[0]);
printf("Sample 1: %d\n", samples[1]);
// Initialize the Python Interpreter
printf("Before init\n");
Py_Initialize();
PyObject *sysPath = PySys_GetObject("path");
const char *scriptDirectoryName = ".";
PyObject *path = PyUnicode_FromString(scriptDirectoryName);
int result = PyList_Insert(sysPath, 0, path);
printf("after init\n");
// Build the name object
pName = PyUnicode_DecodeFSDefault(argv[1]);
printf("after pname %s %d\n", argv[1], pName == NULL ? 1 : 0);
// Load the module object
pModule = PyImport_Import(pName);
printf("after pmodule %d\n", pModule == NULL ? 1 : 0);
// pFunc is also a borrowed reference
pFunc = PyObject_GetAttrString(pModule, "get_model");
printf("after pfunc\n");
if (PyCallable_Check(pFunc))
{
pArgs = PyTuple_New(2);
printf("after pytuple\n");
PyTuple_SetItem(pArgs, 0, PyLong_FromLong(header->sample_rate));
printf("after set item\n");
uint8_t* array = malloc(header->datachunk_size);
int dims[1];
dims[0] = header->datachunk_size;
printf("alloc\n");
import_array();
PyObject* pSamples = PyArray_SimpleNewFromData(1, dims, NPY_INT8, (void*)samples);
printf("pSamples\n");
PyArray_ENABLEFLAGS((PyArrayObject*)pSamples, NPY_ARRAY_OWNDATA);
PyTuple_SetItem(pArgs, 1, pSamples);
printf("Before calling\n");
pValue = PyObject_CallObject(pFunc, pArgs);
printf("After calling\n");
} else
{
PyErr_Print();
}
printf("pValue: %d\n", pValue);
// Clean up
Py_DECREF(pModule);
Py_DECREF(pFunc);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
free(header);
free(samples);
}
UPD: updated code where one issue was fixed. But another problem still exists. It's in line PyObject* pSamples = PyArray_SimpleNewFromData(1, dims, NPY_INT8, (void*)samples);. And I can't find out what is wrong with it.
And wav.h just in case:
#include <inttypes.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <err.h>
typedef struct {
char chunk_id[4];
uint32_t chunk_size;
char format[4];
char fmtchunk_id[4];
uint32_t fmtchunk_size;
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bps;
char datachunk_id[4];
uint32_t datachunk_size;
}WavHeader;
WavHeader *header;
void wavread(char *file_name, int16_t **samples)
{
int fd;
if (!file_name)
errx(1, "Filename not specified");
if ((fd = open(file_name, O_RDONLY)) < 1)
errx(1, "Error opening file");
if (!header)
header = (WavHeader*)malloc(sizeof(WavHeader));
if (read(fd, header, sizeof(WavHeader)) < sizeof(WavHeader))
errx(1, "File broken: header");
if (strncmp(header->chunk_id, "RIFF", 4) ||
strncmp(header->format, "WAVE", 4))
errx(1, "Not a wav file");
if (header->audio_format != 1)
errx(1, "Only PCM encoding supported");
if (*samples) free(*samples);
*samples = (int16_t*)malloc(header->datachunk_size);
if (!*samples)
errx(1, "Error allocating memory");
if (read(fd, *samples, header->datachunk_size) < header->datachunk_size)
errx(1, "File broken: samples");
close(fd);
}
It's difficult to tell without the definition of header but I believe the issue is in the line
PyTuple_SetItem(pArgs, 0, header->sample_rate);
PyTuple_SetItem expects a Python object and you're passing it what I think is an integer, which is being misinterpreted as a PyObject*.
I suspect you want
PyTuple_SetItem(pArgs, 0, PyInt_FromLong(header->sample_rate));
(PyLong_FromLong in Python3)
Second issue: you free samples twice. First you pass it to numpy and tell numpy that it owns the data:
PyObject* pSamples = PyArray_SimpleNewFromData(1, dims, NPY_INT8, (void*)samples);
PyArray_ENABLEFLAGS((PyArrayObject*)pSamples, NPY_ARRAY_OWNDATA);
then at the end of your code you free it
free(samples);
I suspect that you meant to pass your newly allocated array to numpy instead of samples. (You still need to copy the data between them too, if this is the case)
UPD: One more right solution from comments is to change type of dims from int to npy_intp

Python C API doesn't load module

I'm trying to load a python module that contains a math and numpy import in C, using the C API. I can load and run the module but, if I import the math module it doesn't work.
I'm using Arch Linux, Python 2.7.2 and gcc.
Here the codes:
#include <stdio.h>
#include <stdlib.h>
#include <python2.7/Python.h>
int main(int argc, char **argv)
{
PyObject *pName, *pModule, *pFunc, *pArg, *pDict, *pReturn, *pT1, *pT2, *pX, *pY;
int i;
double x, y;
Py_Initialize();
PySys_SetPath(".");
pName = PyString_FromString("func");
if (!pName)
{
printf("pName\n");
return 0;
}
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, "get_vals");
pArg = PyTuple_New(2);
PyTuple_SetItem(pArg, 0, PyFloat_FromDouble(4.0));
PyTuple_SetItem(pArg, 1, PyFloat_FromDouble(2.0));
pReturn = PyObject_CallObject(pFunc, pArg);
pT1 = PyTuple_GetItem(pReturn, 0);
pT2 = PyTuple_GetItem(pReturn, 1);
for (i = 0; i < PyTuple_Size(pT1); i++)
{
pX = PyTuple_GetItem(pT1, i);
pY = PyTuple_GetItem(pT2, i);
x = PyFloat_AsDouble(pX);
y = PyFloat_AsDouble(pY);
Py_XDECREF(pX);
Py_XDECREF(pY);
pX = NULL;
pY = NULL;
printf("Point p position is: %.2fx, %.2fy", x, y);
}
Py_XDECREF(pName); Py_XDECREF(pModule); Py_XDECREF(pFunc); Py_XDECREF(pArg); Py_XDECREF(pDict); Py_XDECREF(pReturn); Py_XDECREF(pT1); Py_XDECREF(pT2);
Py_Finalize();
return 0;
}
func.py
from math import cos
def get_vals(width, height):
x = (1, 2)
y = (cos(3), 4)
return x, y
And how can I embbed the Python script to C without need to use the script?
The PySys_SetPath(".") cleared the python path, so it could no longer find any library whatsoever. What you really need to do is import sys.path and then append your string to it:
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyString_FromString("."));
(I didn't test the above code, but it should be close. Also, you should do error checking)

Categories

Resources