Wrapping C ++ classes containing wxString with Cython

I am working on a Python extension to associate it with a C ++ application written using wxWidgets for a graphical interface. I use Cython and have a basic system (build tools, as well as a starter extension with relevant version information, etc.) that work with pleasure.

I’m only interested in the possibility of creating a backend (not a GUI), such as parsing and processing files. However, all classes, and not just graphical interfaces, are used wxStringfor string data, for example, in the following minimal example:

#include <wx/string.h>

class MyClass{
    wxString name;
    wxString get_name(){
        return this->name;
    }
};

My question is the best way to wrap such a class? Is there an easy way to interact between a Python string and an instance wxString? Or do I need to wrap a class wxString? Can I somehow bind the wxPython port to avoid re-creating the wheel?

+3
source share
2 answers

I got it to work using a static function wxString::FromUTF8()to convert from Python to wxString, and wxString.ToUTF8()in a different direction. Below is the code I came up with:

# Import the parts of wxString we want to use.
cdef extern from "wx/string.h":
    cdef cppclass wxString:
        char* ToUTF8()


# Import useful static functions from the class.
cdef extern from "wx/string.h" namespace "wxString":
   wxString FromUTF8(char*)


# Function to convert from Python string to wxString. This can be given either
# a unicode string, or a UTF-8 encoded byte string. Results with other encodings
# are undefined and will probably lead to errors.
cdef inline wxString from_python(python_string):
    # If it is a Python unicode string, encode it to a UTF-8 byte string as this
    # is how we will pass it to wxString.
    if isinstance(python_string, unicode):
        byte_string = python_string.encode('UTF-8')

    # It is already a byte string, and we have no choice but to assume its valid
    # UTF-8 as theres no (sane/efficient) way to detect the encoding.
    else:
        byte_string = python_string

    # Turn the byte string (which is still a Python object) into a C-level char*
    # string.
    cdef char* c_string = byte_string

    # Use the static wxString::FromUTF8() function to get us a wxString.
    return FromUTF8(c_string)


# Function to convert a wxString to a UTF-8 encoded Python byte string.
cdef inline object to_python_utf8(wxString wx_string):
    return wx_string.ToUTF8()


# Function to convert a wxString to a Python unicode string.
cdef inline object to_python_unicode(wxString wx_string):
    # Since the wxString.ToUTF8() method returns a const char*, we'd have to try
    # and cast it if we wanted to do it all in here. I've tried this and can't
    # seem to get it to work. But calling the to_python_utf8() function
    # means Cython handles the conversions and it all just works. Plus, since
    # they are defined as inline functions this may well be simplified down when
    # compiled.
    byte_string = to_python_utf8(wx_string)

    # Decode it to a unicode string and we're done.
    return byte_string.decode('UTF-8')

Simply put, this is in the .pxd file (I personally put it in a subdirectory like wx/string.pxd- make sure that you also create wx/__init__.pdxif you decide to do the same). Then cimporthe will call the corresponding functions:

cimport wx.string

wx_string = wx.string.from_python(python_string)
python_string = wx.string.to_python_unicode(wx_string)
+2
source

, , - wxString:

wxString(const wxChar* psz, size_t nLength = wxSTRING_MAXLEN)

const char *, .

python wxString .

PyObject* PyString_FromStringAndSize(const char *v, Py_ssize_t len)

, , , wxString python.

wxString , PyString Python. Cython .

0

All Articles