Paolo Celati
Paolo Celati

Reputation: 312

Can't return instance of class in Boost Python

I'm trying to return an instance of a C++ class and return it to Python using Boost.Python. What I'd like to do is have code like:

class foo {
    std::string name;
    public:
    void set_name(std::string name) {this->name = name;}
    std::string get_name() {return this->name;}
};
class bar {
    public:
    foo get_foo(std::string name) {
        foo my_foo;
        my_foo.set_name(name);
        return my_foo;
    }
};

and I'm wrapping it with:

BOOST_PYTHON_MODULE(foobar)
{
    class_<foo, boost::noncopyable>("foo")
    .def("set_name", &foo::set_name)
    .def("get_name", &foo::get_name)
;

    class_<bar, boost::noncopyable>("bar")
    .def("get_foo", &bar::get_foo);
 }

As you might have also noticed, I need both foo and bar to be noncopyable because in the real project, there are sockets inside. When trying to compile the above, I get a Python TypeError:

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

I'm calling it with Python like this:

Python 3.6.1 (default, Mar 22 2017, 06:17:05) 
[GCC 6.3.0 20170321] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import foobar
>>> a=foobar.bar()
>>> b=a.get_foo("myname")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: No to_python (by-value) converter found for C++ type: foo
Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 63, in apport_excepthook
    from apport.fileutils import likely_packaged, get_recent_crashes
  File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5, in <module>
    from apport.report import Report
  File "/usr/lib/python3/dist-packages/apport/report.py", line 30, in <module>
    import apport.fileutils
  File "/usr/lib/python3/dist-packages/apport/fileutils.py", line 23, in <module>
    from apport.packaging_impl import impl as packaging
  File "/usr/lib/python3/dist-packages/apport/packaging_impl.py", line 24, in <module>
    import apt
  File "/usr/lib/python3/dist-packages/apt/__init__.py", line 23, in <module>
    import apt_pkg
ModuleNotFoundError: No module named 'apt_pkg'

Original exception was:
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: No to_python (by-value) converter found for C++ type: foo
>>> 

Upvotes: 2

Views: 986

Answers (1)

Paolo Celati
Paolo Celati

Reputation: 312

I've found a way to make the code work. It seems I should use a pointer return type and boost::python::return_value_policy<boost::python::manage_new_object>().

#include <boost/python.hpp>
class foo {
    std::string name;
    public:
    void set_name(std::string name) {this->name = name;}
    std::string get_name() {return this->name;}
};
class bar {
    public:
    foo* get_foo(std::string name) {
        foo* my_foo = new foo();
        my_foo->set_name(name);
        return my_foo;
    }
};
BOOST_PYTHON_MODULE(foobar)
{
    boost::python::class_<foo, boost::noncopyable>("foo")
    .def("set_name", &foo::set_name)
    .def("get_name", &foo::get_name)
;

    boost::python::class_<bar, boost::noncopyable>("bar")
    .def("get_foo", &bar::get_foo, boost::python::return_value_policy<boost::python::manage_new_object>());

 }

Upvotes: 5

Related Questions