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.
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.
NULLWhile 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
There are three parts to a Pyrex extension-class:
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 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.
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)