wrapped by a python

What do you get when you cross a best of breed intelligent predictive text entry platform with a fast dynamic object-oriented programming language?

Why, of course, you get a python binding for soothsayer!

The good people over at the OpenMAIA project have been working on a rewrite of their keyring application, which provides a sleek and unobstrusive on-screen keyboard, with a twist.

The keyring application simulates a physical ring, divided in several sections, each section marked by a key. The ring can be rotated left or right, and zoomed in or out. Zooming in into a section is the equivalent of pressing the key that section corresponds to.

Soothsayer and keyring can be made to fit together nicely. Imagine a ring that contains two types of keys: normal keys containing a single character, and extended keys containing strings obtained from the predictions generated by soothsayer. It's a perfect match!

The only trouble is that the keyring application, originally developed in C++, has recently been rewritten in Python. So how do you get keyring and soothsayer to work together?

Simple, you write a python binding for soothsayer. That could pose a bit of a problem if you know nothing about Python.

Fortunately, Python really is straightforward. Getting to grips with the language requires a minimal investment in time and effort, and after spending a few minutes browsing through the excellent documentation I got up to speed with the basics.

And if you add the excellent a Simplified Wrapper and Interface Generator (or SWIG for short) to the mix, you are almost done before you start.

SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages. SWIG is used with different types of languages including common scripting languages such as Perl, PHP, Python, Tcl, Ruby and PHP.

SWIG comes with an excellent documentation, both an informative and entertaining read. The only minor issue I encountered was with mapping C++ standard template containers and classes, namely std::vector< std::string > object returned by value.

After some smart googling, I discovered that the solution was to add the following to the soothsayer.i interface definition:

%module soothsayer
%include "std_vector.i"
%include "std_string.i"
#include "soothsayer.h"
namespace std {
    %template() vector< string >;
%include "soothsayer.h"

A bit of position independent compiling and shared library linking later, I had my Soothsayer Python extension module.

No binding is complete without an example Python application. The simplest I could think of is:

import soothsayer
config = "C:/cygwin/home/matt/soothsayer/trunk/bindings/soothsayer.xml"
soothie = soothsayer.Soothsayer(config)
print "Enter text at the prompt (press enter on empty line to exit):"
while str != "":
        str = raw_input(">  ")
        print soothie.predict(str)
del soothie