Python Template Weblog

June 6, 2005

Pity

— Tim @ 11:14 pm

I have named my lightweight CGI framework “Pity”, short for “Pthon Implementation Template test framework Y.” You can download it or browse its source at pity.python-hosting.com.

You can see Pity’s main loop in Pity.Controller.CGI.main(), to wit:

if not errors:
    try:
        # This is the main processing block
        backend = BackEnd.GetBackEnd(form=form,
                                base_directory=self.base_directory)
        engine = TemplateEngines.GetEngine(template, debug=debug)
        engine.populate(page, backend)
        engine.render()
        return

    except TemplateEngines.Error, err:
        errors.append('An error occurred:' + str(err))

self.showmenu(errors=errors)

This is fairly straightforward. The BackEnd object functions as a view layer (mostly based on the user’s form data), and the factory function GetEngine() will return the appropriate TemplateEngine subclass for a specified engine.

Each of the TemplateEngine subclasses has a single method populate() which does the main work. The TemplateEngines.BaseEngine.Engine superclass has some logic which figures out which page is being called (each is identified with a single string such as “pager” or “register”) and will call matching methods in the child classes if they exist.

The Pity interface is all contained in one big HTML file, menu/menu.html (source). It’s nothing too special; it displays a specific section of the form depending on the page the user requested and there are buttons for quickly populating the fields with specific dummy data. I am fairly pleased with the javascript involved in populating these buttons, which came out rather Pythonic, if I may so. The other thing that I like about the menu is that it is all contained in one big file, and so requires very little effort to deploy.

Purists may be interested to note that I have written my own little template system in Pity.Controller.CGI, one based on the almighty string.replace(). I will do my utmost not to let this fact color my objectivity.

The view objects themselves are very simple, and mostly consist of static class data which maps from the names of form fields to the names of instance variables. For example, here is the pager view object:

class Pager(ViewObject):
    """View object for the pager page."""
    viewname = 'pager'
    fields = {
        'current':      {'name': 'pager_current',   'default': '1'},
        'total':        {'name': 'pager_total',     'default': '0'},
        'tolerance':    {'name': 'pager_tolerance', 'default': '2'},
    }

    def __init__(self, form):
        super(Pager, self).__init__(form)
        # current and total are integers
        self.current, self.total = int(self.current), int(self.total)

Note that if the pager used strings instead of integers, it could omit the constructor altogether. I like this somewhat declarative style of doing things, which was indirectly inspired by SQLObject.