Error: Incompatible function arguments - python

I'm using pybind11 to access some functions which I wrote in C++ from python. I wish to return an initialized struct instance to python(from a class member function) so that I can access the instance values in python. I have provided a simplified version of my source file. One can reproduce the error with the following.
This is the c++ wrapper
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "sum.h"
namespace py = pybind11;
PYBIND11_PLUGIN(GetSum) {
py::module mod("GetSum", "wrapping caltri");
mod.def("get_instance", &GetSum::get_instance, py::return_value_policy::copy, "get instance of out");
py::class_<GetSum, std::shared_ptr<GetSum>>(mod, "GetSum")
.def(py::init<>())
.def("input", &GetSum::input);
return mod.ptr();
}
This is a part of the class header sum.h
extern "C" {
#include "mesh.h"
}
#include<iostream>
#include<vector>
class GetSum {
struct A out;
public:
GetSum();
void input(std::vector<float>);
struct A get_instance() {
return out; };
~GetSum();
};
This is class definition sum.cpp
#include "sum.h"
GetSum::GetSum() {
out.pointlist = nullptr;
}
void GetSum::input(std::vector<float> num){
out.pointlist = new float[num.size()];
for(size_t i = 0; i < num.size(); i++)
*(out.pointlist+i) = num[i];
}
GetSum::~GetSum(){
delete [] out.pointlist;
}
Struct definition: mesh.h
#include <stdio.h>
struct A {
float *pointlist;
};
and this is how I was calling it in python.
import GetSum
m = GetSum.GetSum()
m.input([1.0,2.0])
GetSum.s = GetSum.get_instance()
After which I get the error: get_instance(): incompatible function arguments. The following argument types are supported:
1. (arg0: GetSum) -> A
Can someone help me figure out where I might be going wrong?
Thanks!

You need to declare struct A to pybind11 before it can be used as a return type by adding at minimum:
py::class_<A>(mod, "A")
.def(py::init<>());
to your wrapper code. Further, since get_instance is not static, you need to call it as follows in your example python code:
GetSum.s = GetSum.get_instance(m)

Related

pybind std::function failed due to deleted copy constructor

I'm trying to bind a registerHandler() defined in a given class, which I can't modify.
The class:
class FG{
public:
//return DType, no input argument
using Handler = std::function<DType(void)>;
void RegisterHandler(Handler h);
}
class DType{
public:
DType() noexcept = default;
DType(DType const &) = delete;
DType(DType&& other) noexcept = default;
~DType() noexcept
{...
}
DType& operator=(DType const&) = delete;
DType& operator=(DType&& other) & noexcept = default;
...
}
If I bind it like below, it gives an error message saying "error: use of deleted function 'DType(const DType&)'.
#include <pybind/pybind11>
#include <pybind/stl_bind11>
#include <pybind/functional.h>
#include <pybind/stl.h>
using Handler = std::function<DType>(void);
void bind_FG(py::module& m)
{
py::class_<FG> pyClass(m, "FG", py::module_local());
pyClass.def("RegisterHandler" &RegisterHandler);
//or
// pyClass.def("RegisterHandler", [](FG& self, Handler h)
// {
// self.RegisterHandler(h);
// }
// );
}
I googled std::function, and it says it requires a copy ctor, does it mean that there is no way to bind the RegisterHandler() for my case?
At the same time, I'm confused we have implemented the handler function in the C++ side, it seems to be fine (build and work). Why doesn't it require a copy ctor for C++ code?

pybind11 how to use custom type caster for simple example class

Motivation
I am currently trying to use a custom class both in python and in c++ with pybind11. The motivation behind this is to use a python-trained classifier within c++.
There are some working examples, e.g. in the official documentation https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html or by the nice examples from tdegeus https://github.com/tdegeus/pybind11_examples/blob/master/09_numpy_cpp-custom-matrix/pybind_matrix.h
However, i still have problems to transfer this to a simple example with a custom class.
Below is a minimal working example with a wrapper function for pybind11 in c++ and the use of it in python.
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
//A custom data class
class class_DATA{
public:
std::vector<int> a;
};
//the actual function
class_DATA func_test(class_DATA data){
std::vector<int> a = {1,2};
data.a = a;
return data;
}
//the wrapper function that communicates with python
py::object wrapper(py::object data_py){
class_DATA data_cpp = class_DATA();
py::object a = data_py.attr("a");
data_cpp.a = a.cast<std::vector<int>>();
class_DATA data_result_cpp = func_test(data_cpp);
py::object data_result_py = data_py;
data_result_py.attr("a") = py::cast(data_result_cpp.a);
return data_result_py;
}
//defining the modules
PYBIND11_MODULE(TEST,m){
m.doc() = "pybind11 example plugin";
//the test function
m.def("func_test", &wrapper);
//the custom class
py::class_<class_DATA>(m, "class_DATA", py::dynamic_attr())
.def(py::init<>())
.def_readwrite("a", &class_DATA::a);
}
from build.Debug.TEST import func_test
//the custom data class in python
class class_DATA_py:
def __init__(self):
self.a = [0]
test_py = class_DATA_py()
data_return = func_test(test_py)
The output input is data.a = 0 and the output data_return.a = [1,2] as desired.
Question
How can I replace the wrapper function call with a custom caster? Most likely with the general shape outlined below (?)
namespace pybind11 { namespace detail {
template <> struct type_caster<class_DATA> : public type_caster_base<class_DATA> {
using base = type_caster_base<class_DATA>;
public:
PYBIND11_TYPE_CASTER(class_DATA, _("class_DATA"));
// Conversion part 1 (Python->C++):
bool load(py::handle src, bool convert){
PyObject *source = src.ptr();
//what to do here?
return true;
}
// Conversion part 2 (C++ -> Python):
static py::handle cast(class_DATA src, py::return_value_policy policy, py::handle parent){
//what to do here?
return base::cast(src, policy, parent);
}
};
}}
c++ is not my forte and python crashes repeatedly without any error messages when I meddle with this part, so any help would be really appreciated.

Memory Core Dump C++

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)

Adding custom code to SWIG wrapper

I am using SWIG to interface between C++ and Python. I want to add some code to the generated wrapper for setting a member variable in a struct. The closest I have found is this:
%allowexception TAxis::Min;
%exception TAxis::Min
%{
$action
do_something();
%}
struct TAxis
{
double Min;
double Max;
};
However, this will call do_something() when TAxis::Min is both read and written. I want it to be called only when TAxis::Min is written. Any suggestions are appreciated.
I will answer my own question. The following creates a macro VAR_WITH_SET_CODE, which can be used to do something before and after the variable is set.
%define VAR_WITH_SET_CODE(class, type, member, pre_code, post_code)
%extend class
{
type member;
}
%{
#define class ## _ ## member ## _get(self) self->member
#define class ## _ ## member ## _set(self, value) {pre_code} self->member = value; {post_code}
%}
%enddef
VAR_WITH_SET_CODE(TAxis, double, Min, do_before();, do_after();)
VAR_WITH_SET_CODE(TAxis, double, Max, do_before();, do_after();)
struct TAxis
{
//double Min;
//double Max;
};

Boost.Python create handle from type

In some places in exposing C++ code to python, I need to use a PyObject*. If I have an instance of a boost::python::class_ object, I can invoke ptr() on it. But what if I just have the type?
Basically, given the type list boost::python::bases<A, B, C>, I want to convert this to a boost::python::tuple of instances that I can pass into something like PyErr_NewExceptionWithDoc(). Is this possible?
Given a C++ type T, one can create a boost::python::type_id object, and then query into the Boost.Python registry for registration information. If an entry is found in the registry, then one can use it to obtain a handle to the Python class created for type T:
/// #brief Get the class object for a wrapped type that has been exposed
/// through Boost.Python.
template <typename T>
boost::python::object get_instance_class()
{
// Query into the registry for type T.
namespace python = boost::python;
python::type_info type = python::type_id<T>();
const python::converter::registration* registration =
python::converter::registry::query(type);
// If the class is not registered, return None.
if (!registration) return python::object();
python::handle<PyTypeObject> handle(python::borrowed(
registration->get_class_object()));
return python::object(handle);
}
Here is a complete example demonstrating locating a Python class object in the Boost.Python registry:
#include <boost/python.hpp>
#include <iostream>
/// #brief Get the class object for a wrapped type that has been exposed
/// through Boost.Python.
template <typename T>
boost::python::object get_instance_class()
{
// Query into the registry for type T.
namespace python = boost::python;
python::type_info type = python::type_id<T>();
const python::converter::registration* registration =
python::converter::registry::query(type);
// If the class is not registered, return None.
if (!registration) return python::object();
python::handle<PyTypeObject> handle(python::borrowed(
registration->get_class_object()));
return python::object(handle);
}
struct spam {};
int main()
{
Py_Initialize();
namespace python = boost::python;
try
{
// Create the __main__ module.
python::object main_module = python::import("__main__");
python::object main_namespace = main_module.attr("__dict__");
// Create `Spam` class.
// >>> class Spam: pass
auto spam_class_object = python::class_<spam>("Spam", python::no_init);
// >>> print Spam
main_module.attr("__builtins__").attr("print")(get_instance_class<spam>());
// >>> assert(spam is spam)
assert(spam_class_object.ptr() == get_instance_class<spam>().ptr());
}
catch (python::error_already_set&)
{
PyErr_Print();
return 1;
}
}
Output:
<class 'Spam'>
For more type related functionality, such as accepting type objects, is, and issubclass, see this answer.

Categories