Boost.Python Call by Reference:Typeerror: No To_Python (By-Value) Converter Found for C++ Type:

Boost.Python call by reference : TypeError: No to_python (by-value) converter found for C++ type:

Change B.do_something(a); to B.do_something(boost::ref(a));.

See Calling Python Functions and Methods in the boost manual.

TypeError: No to_python (by-value) converter found for C++ type

This code works for me:

struct Base {
virtual ~Base() {};
virtual char const *hello() {
return "Hello. I'm Base.";
};
};

struct Derived : Base {
char const *hello() {
return "Hello. I'm Derived.";
};

Base &test(bool derived) {
static Base b;
static Derived d;
if (derived) {
return d;
} else {
return b;
}
}
};

BOOST_PYTHON_MODULE(wrapper)
{
using namespace boost::python;
class_<Base>("Base")
.def("hello", &Base::hello)
;

class_<Derived, bases<Base>>("Derived")
.def("test", &Derived::test, return_internal_reference<>())
;
}

Testing module:

>>> import wrapper
>>> d = wrapper.Derived()
>>> d.test(True).hello()
"Hello. I'm Derived."
>>> d.test(False).hello()
"Hello. I'm Base."
>>>

Object of self type in class - TypeError: No to_python (by-value) converter found for C++ type

Edit

I figured out that, replacing the line

boost::python::class_<Child>("Child")

by

boost::python::class_<Child, Child*>("Child")

in Wrapper.cpp solved my problem. The result is then as expected:

C:\Users\Visual Studio 2017\Projects\MinExBoostPython2\x64\Debug>Wrapper.py
0.0
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__instance_size__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'parent', 'val']
1.0
0.0

C:\Users\Visual Studio 2017\Projects\MinExBoostPython2\x64\Debug>

Hope it helps someone!

Boost Python No to_python converter found for std::string

Ok here is the entire to and from optional converter based on the original C++ sig post but rewritten to use the high level boost.python API (sorry about the weird spacing).

template<typename T>
struct optional_ : private boost::noncopyable
{
struct conversion :
public boost::python::converter::expected_from_python_type<T>
{
static PyObject* convert(boost::optional<T> const& value) {
using namespace boost::python;
return incref((value ? object(*value) : object()).ptr());
}
};

static void* convertible(PyObject *obj) {
using namespace boost::python;
return obj == Py_None || extract<T>(obj).check() ? obj : NULL;
}

static void constructor(PyObject *obj,
boost::python::converter::rvalue_from_python_stage1_data *data)
{
using namespace boost::python;
void *const storage =
reinterpret_cast<
converter::rvalue_from_python_storage<boost::optional<T> >*
>(data)->storage.bytes;
if(obj == Py_None) {
new (storage) boost::optional<T>();
} else {
new (storage) boost::optional<T>(extract<T>(obj));
}
data->convertible = storage;
}

explicit optional_() {
using namespace boost::python;
if(!extract<boost::optional<T> >(object()).check()) {
to_python_converter<boost::optional<T>, conversion, true>();
converter::registry::push_back(
&convertible,
&constructor,
type_id<boost::optional<T> >(),
&conversion::get_pytype
);
}
}
};

Convert type into python

Boost.Python call by reference : TypeError: No to_python (by-value) converter found for C++ type:

Boost::Python: no converter found for C++ type: boost::python::detail::kwds_proxy

user_add_wrapper(name, new_user) tries to pass new_user as a dictionary to user_add_wrapper(), rather than passing the unpacked contents of new_user. The new_user dictionary needs to be unpacked. Additionally, calling the python::object with an unpacked dictionary requires the first argument to be an unpacked boost::python::tuple. To account for these requirements, invoke user_add_wrapper() as follows:

user_add_wrapper(*bp::make_tuple(name), **new_user);

This behavior is part of the seamless interoperability provided by Boost.Python, but it is rather obscure and I only recall noticing it mentioned indirectly in the change log rather than the tutorial or reference.


Below is a complete minimal example. Given example.py:

def user_add(name, givenname, sn):
print locals()

The following program invokes user_add() by unpacking a dictionary:

#include <boost/python.hpp>

int main()
{
Py_Initialize(); // Start interpreter.

// Create the __main__ module.
namespace python = boost::python;
python::object main = python::import("__main__");
python::object main_namespace = main.attr("__dict__");

try
{
python::object example = python::import("example");
python::object example_namespace = example.attr("__dict__");

// Construct args.
std::string name = "Pythonist";
python::dict new_user;
new_user["givenname"] = "Test";
new_user["sn"] = "User";

// Invoke user_add by unpacking the new_user dictionary.
example_namespace["user_add"](*python::make_tuple(name), **new_user);
}
catch (const python::error_already_set&)
{
PyErr_Print();
}
}

And produces the following output:

{'givenname': 'Test', 'sn': 'User', 'name': 'Pythonist'}

(boost.python) Error exposing overloaded operator+(). TypeError: No to_python (by-value) converter found

It seems the matrix/vector library is using expression templates. In this case, and as you have remarked, operator+ is not returning a vector but a private type that represents the operation. The returned value is left trapped on the C++ side of things and can't be passed to Python as the private type is not registered.

Now I'm not too familiar with Boost.Python, but I think you can fix your problem with the return value policy. Passing a return_value_policy<to_python_value<DIM::Vector> > as policy would force converting the returned type to DIM::Vector, which you have registered. This would look like:

.def(self + self, return_value_policy<to_python_value<DIM::Vector> >())


Related Topics



Leave a reply



Submit