Vitaly Isaev
Vitaly Isaev

Reputation: 5815

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

We are trying to embed several Python procedures in our C++ code using and it fails with an error

TypeError: No to_python (by_value) converter found for C++ type: boost::python::detail::kwds_proxy

We honestly studied all the examples we managed to find over the network (this and this), but still we have no any clear solution for passing the ****kwargs** variable from C++ to Python. This failure seems to be very rare.

Python function we are trying to call recieves a string value and a dictionary:

from ipalib import api
user_kw = dict(givenname=u'Test', sn=u'User')
api.Command.user_add.(u'Pythonist', **user_kw)

This is its C++ implementation:

//Importing modules
bp::import("__main__");
ipalib = bp::import("ipalib");
ipalib_namespace = ipalib.attr("__dict__");
api = ipalib.attr("api");

... //Starting Python environment

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

//Calling the function
bp::object user_add_wrapper = api.attr("Command").attr("user_add");
user_add_wrapper(name, new_user);

And on the last line Boost throws an exception. What are we doing wrong? Thank you.

Upvotes: 1

Views: 1153

Answers (1)

Tanner Sansbury
Tanner Sansbury

Reputation: 51961

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'}

Upvotes: 3

Related Questions