Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return python unicode instances from UTF-8 encoded char* using boost.python

I'm trying to do something which should be very simple, but I'm not having much luck figuring out how from the existing documentation.

For a python 2 project I am trying to return a list gettext-translated string as a unicode instances to python. The return value for gettext() is a UTF-8 encoded char*, which should be pretty simple to convert to a python unicode instrance using PyUnicode_FromString. I have a feeling this is trivial to do, but I can't seem to figure out how.

Basd on comments from Ignacio Vazquez-Abrams and Thomas K I did get this working for a single string; for that case you can bypass all the boost.python infrastructure. Here is an example:

        PyObject* PyMyFunc() {
            const char* txt =  BaseClass::MyFunc();
            return PyUnicode_FromString(txt); 
    }       

which is exposed with the usual def statement:

class_<MyCclass>("MyClass")
    .def("MyFunc", &MyClass::PyMyFunc);

Unfortuantely this does not work when you want to return a list of unicode instances. This is my naive implementation:

boost::python::list PyMyFunc() {
    std::vector<std::string> raw_strings = BaseClass::MyFunc();
    std::vector<std::string>::const_iterator i;
    boost::python::list result;

    for (i=raw_strings.begin(); i!=raw_strings.end(); i++)
        result.append(PyUnicode_FromString(i->c_str()));
    return result;
}

but this does not compile: boost::python::list does seem to handle PyObject values.

like image 279
Wichert Akkerman Avatar asked Nov 05 '22 02:11

Wichert Akkerman


1 Answers

With some help from the C++-SIG mailinglist I have this working now. There are two extra steps needed:

  1. use boost::python::handle<> to create a C++ wrapper around the PyObject* which takes care of reference handling
  2. use boost::python::object to create a C++ wrapper around the handle, which allows using a PyObject* instance as a (reasonably) normal C++ class instance, and thus something boost::python::list can handle.

With that knowledge the working code looks like this:

boost::python::list PyMyFunc() {
    std::vector<std::string> raw_strings = BaseClass::MyFunc();
    std::vector<std::string>::const_iterator i;
    boost::python::list result;

    for (i=raw_strings.begin(); i!=raw_strings.end(); i++)
        result.append(
             boost::python::object(
               boost::python::handle<>(
                 PyUnicode_FromString(i->c_str()))));
    return result;
}
like image 161
Wichert Akkerman Avatar answered Nov 12 '22 17:11

Wichert Akkerman