Writing the Python Wrapper

The C structures and functions that we wrap in Pyrex behave like C structures and functions, not like Python objects and methods. Therefor we write wrappers for the C functions so they behave normally. If we were writing procedual code we will need to create function wrappers, but if we were writing opbject-oriented code then we will need to write a class with its associated methods.

CUPS

Function Wrappers

The last part of out CUPS module that we have to write is a wrapper for the cupsGetDests function. We start it in the same way we would start any Python procedure.

def get_dests():

Next we declare all the local C-variables. The first is the return value for call to cupsGetDests, which is going to supply an array of cups_dest_t structures. The second is a variable that we are going to use in the for-loop below.

    cdef cups_dest_t *dests
    cdef cups_dest_t currDest

Now we make the call to the C function cupsGetDests.

    numDests = cupsGetDests(&dests)

Notice that numDests was not declared earlier because it is a normal Python integer.

The final job of our Python procedure is to unpack the C array and put the names into a Python list.

    retval = []
    for i in range(numDests):
        currDest = dests[i]
        retval.append(currDest.name)
    return retval

The loop starts by unpacking each element of the array dests into a local variable. Next, the name element of the cups_dest_t structure is appended to a list, before the list of names is returned.

The function is not indented because this code was not part of the original cups.h file.

Passing NULL

While it seems odd, you can pass NULL from within a function-wrapper. For example, the following passes NULL instead of a pointer to a cups_option_t structure. (Note you cannot pass 0 instead of NULL.)

def print_file(printer, filename, title):
    jobID = cupsPrintFile(printer, filename, title,
                          0, NULL)
    return jobID

XOSD

Writing a Class

There are three parts to a Pyrex extension-class:

C-Variable Declaration

Writing a Python class to wrap a C structure begins by declaring the local variables. The variable declarations are the same for classes as they are for functions. For the XOSD wrapper-class we declare the local variable xosdWin immediately after the class declaration, as follows.

cdef class XOSD:
    cdef xosd *xosdWin

Note: You cannot declare the C variables inside the constructor (__new__).

The Constructor and Destructor Methods

The constructor has to be written next. Use the __new__ method to create the constructor — instead of using the traditional __init__ — because __new__ is called before the object is created. Initialise all the C variables, and libraries inside the constructor; for XOSD, the xosd_create function is called.

    def __new__(self, font, colour):
        self.xosdWin = xosd_create(1)
        xosd_set_font(self.xosdWin, font)
        xosd_set_colour(self.xosdWin, colour)

To wrap the destructor, override the __dealloc__ method. The xosd_destroy function is called inside the destructor to remove the XOSD window.

    def __dealloc__(self):
        xosd_destroy(self.xosdWin)

Alert readers would have noticed that the functions xosd_set_font, xosd_set_colour, and xosd_destroy were not declared earlier. The declarations are left as an exercise to the reader.

Standard Methods

The final task is to write the standard methods that will be called by code outside the module. These methods are written in a similar way to standard Python functions. For our example, we will wrap up the xosd_display function, creating a display_text method that will display the text on the screen.

    def display_text(self, text):

Recall how xosd_display took a variable number of arguments? Because of this we have to convert text to the correct C-type ourselves, otherwise Pyrex would not know what type to make text. To do this we create a temporary C-variable, cText, that is passed to xosd_display.

        cdef char *cText
        cText = text
        xosd_display(self.xosdWin, 1, XOSD_string, cText)