I have a C++ class that is able to output strings in normal ASCII or wide format. I want to get the output in Python as a string. I am using SWIG (version 3.0.4) and have read the SWIG documentation. I'm using the following typemap to convert from a standard c string to my C++ class:
%typemap(out) myNamespace::MyString &
{
$result = PyString_FromString(const char *v);
}
This works fine in Windows with the VS2010 compiler, but it is not working completely in Linux. When I compile the wrap file under Linux, I get the following error:
error: cannot convert ‘std::string*’ to ‘myNamespace::MyString*’ in assignment
So I tried adding an extra typemap to the Linux interface file as so:
%typemap(in) myNamespace::MyString*
{
$result = PyString_FromString(std::string*);
}
But I still get the same error. If I manually go into the wrap code and fix the assignment like so:
arg2 = (myNamespace::MyString*) ptr;
then the code compiles just fine. I don't see why my additional typemap isn't working. Any ideas or solutions would be greatly appreciated. Thanks in advance.
It doesn't look like your typemap is using the arguments quite correctly. You should have something like this instead:
%typemap(out) myNamespace::MyString &
{
$result = PyString_FromString($1);
}
Where the '$1' is the first argument. See the SWIG special variables for more information [http://www.swig.org/Doc3.0/Typemaps.html#Typemaps_special_variables]
EDIT:
To handle the input typemap, you will need something like this:
%typemap(in) myNamespace::MyString*
{
const char* pChars = "";
if(PyString_Check($input))
{
pChars = PyString_AsString($input);
}
$1 = new myNamespace::MyString(pChars);
}
You can do more error checking and handle Unicode with the following code:
%typemap(in) myNamespace::MyString*
{
const char* pChars = "";
PyObject* pyobj = $input;
if(PyString_Check(pyobj))
{
pChars = PyString_AsString(pyobj);
$1 = new myNamespace::MyString(pChars);
}
else if(PyUnicode_Check(pyobj))
{
PyObject* tmp = PyUnicode_AsUTF8String(pyobj);
pChars = PyString_AsString(tmp);
$1 = new myNamespace::MyString(pChars);
}
else
{
std::string strTemp;
int rrr = SWIG_ConvertPtr(pyobj, (void **) &strTemp, $descriptor(String), 0);
if(!SWIG_IsOK(rrr))
SWIG_exception_fail(SWIG_ArgError(rrr), "Expected a String "
"in method '$symname', argument $argnum of type '$type'");
$1 = new myNamespace::MyString(strTemp);
}
}
Related
I'm trying to get to grips with using embedded Python from a C++ application. Specifically I want my C++ to launch some PyTorch code.
I am making some initialization function in Python to perform the device (CPU or GPU) discovery and would like to pass this back to the C++ code. The C++ will call another Python function for inference which is when the C++ will pass the device to Python.
pFunc_init = PyObject_GetAttrString(pModule, "torch_init");
if (pFunc_init && PyCallable_Check(pFunc_init)) {
pValue_device = PyObject_CallObject(pFunc_init, pArgs);
if (pArgs != NULL)
Py_DECREF(pArgs);
if (pValue_device != NULL) {
pFunc_infer = PyObject_GetAttrString(pModule, "torch_infer");
if (pFunc_infer && PyCallable_Check(pFunc_infer)) {
//
// TODO put object pValue_device into pArgs_device.
//
pValue_infer = PyObject_CallObject(pFunc_infer, pArgs_device);
if (pValue_infer != NULL) {
printf("Result pValue_infer: %ld\n", PyLong_AsLong(pValue_infer));
Py_DECREF(pValue_infer);
}
}
Py_DECREF(pValue_device);
}
else {
Py_DECREF(pFunc_init);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr, "Call failed\n");
return 1;
}
}
The TODO marks where I would like to put this code. With simple Python objects I think I know what I need but how to deal with this custom Python object?
You can define a Python function "detect_device" which returns a string say "cuda" or "cpu". After that in your C++ code, you can do something like this.
PyObject *detect_device, *pArgsDevice;
detect_device = PyObject_GetAttrString(pModule, "detect_device");
deviceObject = PyObject_CallObject(detect_device, NULL);
pArgsDevice = NULL;
pArgsDevice = PyTuple_New(1);
PyTuple_SetItem(pArgsDevice, 0, deviceObject);
PS: Wrote the answer in hurry due to some urgency. Will add explanation soon, but I think if you understand the code that you have written, you would be able to understand this. Letme know in comments about your progress.
I have some code in C++ and I want to call it from Python. The C++ code returns lists of dicts to the python code. I use boost.python to achieve this, in the following manner:
struct MyStruct {
int foo;
};
class MyClass
{
public:
std::vector<MyStruct> get_stuff();
};
struct MyStructConverter
{
static PyObject* convert(const std::vector<MyStruct>& v)
{
boost::python::list ret;
for (auto c : v) {
boost::python::dict *r = new boost::python::dict();
(*r)["foo"] = c.foo;
ret.append(boost::python::object(*r));
}
return boost::python::incref(ret.ptr());
}
};
/** Interface between C++ and Python
*/
BOOST_PYTHON_MODULE(glue)
{
boost::python::to_python_converter<std::vector<MyStruct>, MyStructConverter>();
class_<MyClass, boost::noncopyable>("MyClass")
.def("get_stuff", &MyClass::get_stuff);
}
This works to the extent that I can pass data from C++ to python. However, when used as follows:
# test.py
x = MyClass()
while True:
u = x.get_stuff()
# do something with u
it leaks memory (i.e. the VSZ of the python process keeps growing until the whole system grinds to a halt).
What am I doing wrong? How can I avoid this?
Now, I have called python to C++. Using ctype to connect between both of them. And I have a problem about core dump when in running time.
I have a library which is called "libfst.so"
This is my code.
NGramFST.h
#include <iostream>
class NGramFST{
private:
static NGramFST* m_Instace;
public:
NGramFST(){
}
static NGramFST* getInstance() {
if (m_Instace == NULL){
m_Instace = new NGramFST();
}
return m_Instace;
}
double getProbabilityOfWord(std::string word, std::string context) {
std::cout << "reloading..." << std::endl;
return 1;
}
};
NGramFST.cpp
#include "NGramFST.h"
NGramFST* NGramFST::m_Instace = NULL;
extern "C" {
double FST_getProbability(std::string word, std::string context){
return NGramFST::getInstance()->getProbabilityOfWord(word, context);
}
}
And this is my python code.
from ctypes import cdll
lib = cdll.LoadLibrary('./libfst.so')
#-------------------------main code------------------------
class FST(object):
def __init__(self):
print 'Initializing'
def getProbabilityOfWord(self, word, context):
lib.FST_getProbability(word, context)
fst = FST()
print fst.getProbabilityOfWord(c_wchar_p('jack london'), c_wchar_p('my name is'))
This is error
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted (core dumped)
I reviewed again but I can not detect where is my problem.
ctypes does not understand C++ types (it's not called c++types). It cannot handle std::string. It wouldn't know that your function expects std::string arguments anyway.
In order to work with ctypes, your library needs a C-compatible interface. extern "C" is necessary but not sufficient. The functions need to be actually callable from C.
Better yet, use a modern C++/Python binding library such as pybind11.
It work when I change python code below
string1 = "my string 1"
string2 = "my string 2"
# create byte objects from the strings
b_string1 = string1.encode('utf-8')
b_string2 = string2.encode('utf-8')
print fst.getProbabilityOfWord(b_string1, b_string2)
and c++ code change type of param bellow
FST_getProbability(const char* word, const char* context)
I'm trying to embed a Python function in C using PyPy and cffi. I'm following this guide from the PyPy documentation.
The problem is, all the examples I've found operate on ints, and my function takes a string and returns a string. I can't seem to figure out how to embed this function in C, as C doesn't seem to really have strings, rather making do with arrays of chars.
Here's what I've tried:
# interface.py
import cffi
ffi = cffi.FFI()
ffi.cdef('''
struct API {
char (*generate_cool_page)(char url[]);
};
''')
...
#ffi.callback("char[] (char[])")
def generate_cool_page(url):
# do some processing with BS4
return str(soup)
def fill_api(ptr):
global api
api = ffi.cast("struct API*", ptr)
api.generate_cool_page = generate_cool_page
--
// c_tests.c
#include "PyPy.h"
#include <stdio.h>
#include <stdlib.h>
struct API {
char (*generate_cool_page)(char url[]);
};
struct API api; /* global var */
int initialize_api(void)
{
static char source[] =
"import sys; sys.path.insert(0, '.'); "
"import interface; interface.fill_api(c_argument)";
int res;
rpython_startup_code();
res = pypy_setup_home(NULL, 1);
if (res) {
fprintf(stderr, "Error setting pypy home!\n");
return -1;
}
res = pypy_execute_source_ptr(source, &api);
if (res) {
fprintf(stderr, "Error calling pypy_execute_source_ptr!\n");
return -1;
}
return 0;
}
int main(void)
{
if (initialize_api() < 0)
return 1;
printf(api.generate_cool_page("https://example.com"));
return 0;
}
When I run gcc -I/opt/pypy3/include -Wno-write-strings c_tests.c -L/opt/pypy3/bin -lpypy3-c -g -o c_tests and then run ./c_tests, I get this error:
debug: OperationError:
debug: operror-type: CDefError
debug: operror-value: cannot render the type <char()(char *)>: it is a function type, not a pointer-to-function type
Error calling pypy_execute_source_ptr!
I don't have a ton of experience with C and I feel like I'm misrepresenting the string argument/return value. How do I do this properly?
Thanks for your help!
Note that you should not be using pypy's deprecated interface to embedding; instead, see http://cffi.readthedocs.io/en/latest/embedding.html.
The C language doesn't have "strings", but only arrays of chars. In C, a function that wants to return a "string" is usually written
differently: it accepts as first argument a pointer to a pre-existing buffer (of type char[]), and as a second argument the length of that buffer; and when called, it fills the buffer. This can be messy because you ideally need to handle buffer-too-small situations in the caller, e.g. allocate a bigger array and call the function again.
Alternatively, some functions give up and return a freshly malloc()-ed char *. Then the caller must remember to free() it, otherwise a leak occurs. I would recommend that approach in this case because guessing the maximum length of the string before the call might be difficult.
So, something like that. Assuming you start with
http://cffi.readthedocs.io/en/latest/embedding.html, change
plugin.h to contain::
// return type is "char *"
extern char *generate_cool_page(char url[]);
And change this bit of plugin_build.py::
ffibuilder.embedding_init_code("""
from my_plugin import ffi, lib
#ffi.def_extern()
def generate_cool_page(url):
url = ffi.string(url)
# do some processing
return lib.strdup(str(soup)) # calls malloc()
""")
ffibuilder.cdef("""
#include <string.h>
char *strdup(const char *);
""")
From the C code, you don't need initialize_api() at all in the
new embedding mode; instead, you just say #include "plugin.h"
and call the function directly::
char *data = generate_cool_page("https://example.com");
if (data == NULL) { handle_errors... }
printf("Got this: '%s'\n", data);
free(data); // important!
I'm using Boost.Python to create a wrapper for my C++ library, and I'm having some troubles, googling all the day did not produc any results. For example, I have the following code:
class Base
{
public:
virtual void func() = 0;
};
class Derived : public Base
{
public:
virtual void func()
{
cout << "Derived::func()"<< endl;
}
};
// wrapper for Base
struct BaseWrapper : Base, python::wrapper<Base>
{
virtual void func()
{
this->get_override("func");
}
};
Base* makeDerived()
{
return new Derived;
}
vector<Base*>* makeDerivedVec()
{
vector<Base*> *v = new vector<Base*>;
v->push_back(new Derived);
v->push_back(new Derived);
v->push_back(new Derived);
return v;
}
BOOST_PYTHON_MODULE(mylib)
{
// export Base
class_<BaseWrapper, noncopyable>("Base")
.def("func", pure_virtual(&Base::func));
class_<vector<Base*> >("BasePtrVec")
.def(vector_indexing_suite<vector<Base*> >());
// export Derived
class_<Derived, bases<Base> >("Derived")
.def("func", &Derived::func);
// export makeDerived()
def("makeDerived", &makeDerived, return_value_policy<manage_new_object>());
// export makeDerivedVec()
def("makeDerivedVec", &makeDerivedVec, return_value_policy<manage_new_object>());
}
So, I compile it, import in python and try this:
b = mylib.Base() b.func()
d = mylib.makeDerived() d.func()
The first line, as expected, throws an exception saying that b.func() is pure virtual, and the second line prints out
Derived::func()
And that's ok.
But the code
dlist = mylib.makeDerivedVec()
for d in dlist:
d.func()
does not work, and Python throws an exception:
TypeError: No to_python (by-value) converter found for C++ type: Base*
Why it handled correctly the Base* returned by makeDerived() and refuses to work with Base* contained in std::vector? How can I make it work?
You can fix this by registering Base* as a type that can be used to point to a BaseWrapper*:
class_<BaseWrapper, noncopyable, Base*>("Base")
.def("func", pure_virtual(&Base::func));
But it seems that this means that Base can't have a pure virtual function...