PyContracts

In the past two years I have fallen in love with Python. In the course of my work I developed a few libraries that I use consistently across projects and save me quite a bit of development time. Some of them are worth sharing, and I hope to have the time to do it (ah!).

PyContracts is one such library, stable enough to merit a version number larger than 1.0. I uploaded it on the PyPI software repository, so that anybody can install it using:

easy_install PyContracts

(or: pip install PyContracts)

PyContracts can be used to declare constraints on the arguments and return value of the functions. While it can be used for type-checking, I found it much more valuable for expressing complicated constraints on the values rather than on the types. For example:

@contract(color='seq[3](>=0,<=1)')
def paint(color):
    ...

This checks that color is a sequence of 3 elements, and each element is a number between 0 and 1. Any sequence is allowed: lists, tuples, Numpy arrays, etc.

Note that it would be very tedious to do by hand:

def paint(color):
    if ( not isinstance(color, Sequence) 
         or len(color) != 3):
        raise ValueError('I need a sequence of length 3.')
    for c in color:
        if (not isinstance(c, (int, float)) 
           or c<0 or c>1):
            raise ValueError('Colors must be in [0,1]')
    ...

All these tests are done automatically by PyContracts, and similar error messages are given.

Here’s a more complicated example. Suppose you want to write a function blend() that takes a list of RGB or RGBA images, blends them together, and return the blended images.

There are several checks you need to do: the input is a list, there are at least two images, each image is RGB/RGBA, each image is the same size, and so on.

With PyContracts you can express all of that very compactly:

@contract(images="list[>=2]( array[HxWx(3|4)](uint8) )", 
         returns="array[HxWx3](uint8)")
def blend(images):
    ''' Blends a series of images together. '''
    ...

See the PyContracts home page for more information.