PyMaemo/Accessing APIs without Python bindings

Introduction

Sometimes you don't need a complete binding for some library, just a couple functions that will solve your problem. For these cases, you can use the ctypes module to cherry-pick the needed functions and use them inside Python, no further steps needed.

This page is not meant to be a complete ctypes guide; there is some great documentation at http://docs.python.org/library/ctypes.html.

Usage

Let's say you want to use libc's printf, for some reason. All you need in python is:

import ctypes
libc = ctypes.CDLL('libc.so.6')
libc.printf('Hello world!')

In a few words, you create an object correspondent to the library you need and use it to call the function directly. You can also store the functions in plain python objects to use them easily later:

c_printf = libc.printf
c_printf('Hello libc')

Remember that those are C functions, not Python ones, so you must supply arguments of the correct type to avoid undefined behavior. As a example, if I pass an integer to the above function, I get

>>> c_printf(1)
Segmentation fault (core dumped)

Wrapping function arguments

Quoting http://docs.python.org/library/ctypes.html#calling-functions:

None, integers, longs, byte strings and unicode strings are the only native Python objects that can directly be used as parameters in these function calls. None is passed as a C NULL pointer, byte strings and unicode strings are passed as pointer to the memory block that contains their data (char * or wchar_t *). Python integers and Python longs are passed as the platforms default C int type, their value is masked to fit into the C type.

For all other types, a ctypes C wrapper must be used; you can find them at http://docs.python.org/library/ctypes.html#fundamental-data-types.

An usage example of these wrappers is shown below:

>>> libc.printf("a integer: %d, a double: %f\n", 42, 3.14)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ctypes.ArgumentError: argument 3: <type 'exceptions.TypeError'>: Don't know how  to convert parameter 3

Integers are fine, but ctypes can't handle Python doubles directly. ctypes.c_double() will solve the problem here:

>>> libc.printf("a integer: %d, a double: %f\n", 42, ctypes.c_double(3.14))
a integer: 42, a double: 3.140000