Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Regular Expressions: CherryPy proves its worth


UnixReview.com
May 2006

Regular Expressions: CherryPy proves its worth

by Miki Tebeka and Cameron Laird

So they've asked you for a "small" internal office application. Just a simple addressbook — how complicated can it be?

You're experienced enough to know better. Sure, programming it will be easy but:

  • You'll need to package it.
  • You'll need to provide an installer.
  • You'll need to support multiple platforms.
  • There will be more features and you'll need to upgrade.

As previous installments of Regular Expressions have mentioned, the magnitude of "simple" applications multiplies when everything after the programming is included. One way to regain a lot of simplicity, though, as we've earlier advocated, is to choose Web applications for your solutions because:

  • No need to package
  • No need to provide installer
  • Multiple platforms supported
  • Updates show up instantly

Maybe you're familiar with all these arguments, but other work has prevented you from learning Web development yourself. Is there a gentle way to break yourself in?

Web Frameworks

Sure! There are many, in fact. Web development has come a long way in the past 15 years. "Web development frameworks" provide just the right abstraction level for the job before us. This month, we'll take an easy tour of the Python-based CherryPy Web development framework and Cheetah "template engine". Please note that there are many, many other frameworks, even if you restrict yourself to a single development language like Python, PHP, or Perl. Deciding between them is a challenge. The good news, though, is that they largely rely on the same concepts, so much of what you learn with CherryPy, for example, would help you use Ruby on Rails or AOLserver. In fact, Cheetah's templating is sufficiently general to have applications even outside Web programming: you can use it as a code generator for clumsy C++ programming, for example.

Installation of CherryPy and Cheetah follows Python standards: retrieve the source distributions, unpack, and python setup.py install. Should you ever need Web service outside the Unix world, both packages also provide Windows installers.

Start with the interface

Start with the user interface; this will give you immediate practice with the underlying engine's capabilities and conventions.

Cheetah interprets source files which embed both HTML and Python. Begin by creating a "master page" that sets the layout of all other pages:

  #from time import ctime

  ## Header
  <html>
  <head>
  <title>
  LoonyTunes AddressBook
  </title>
  <head>
  <body>
  <center>
  <h1>
  LoonyTunes AddressBook
  </h1>
  </center>

  ## Body
  #block body

  ## Show error if this page is shown
  <h1><center><font color="RED">
  OOOPS!
  </font></center></h1>

  #end block body

  ## Footer
  <hr />
      <font size="-1">
          Generated $ctime() by <a href="mailto:[email protected]">duffy</a>
      </font>
  </body>
Notice that we import the ctime Python library for use in the footer. We also define a block for the the body of displayed pages; inheriting pages do their work by overriding this block. A block, delimited, conveniently enough, with #block, is a section of the template that can be selectively re-implemented in a subclass. Blocks are useful for managing parts of a template more rationally than by a copy-paste-edit of the template as a whole. Think of blocks as object methods whose inheriting classes may override with their own implementations. Next, we write an index page, derived, of course, from the master:
  #extends master

  ## Default attributes
  #attr $results = None
  #attr $query = ""

  #block body

  ## Search form
  <form>
  Query: <br />
  <input type="text" name="query" value="$query" size="50"/> <br />
  ## Search within results
  #if $results
  <input type="checkbox" name="within" />Search in results <br />
  #end if
  <input type="submit" value="Search" />
  </form>

  ## Query without hits
  #if (not $results) and $query
  No matches found for $query
  #end if

  ## We have results show them
  #if $results
  Found $len($results) result(s):
  <table width="80%" border="1">
      ## Header
      <tr>
          <td>Name</td>
          <td>Phone</td>
      </tr>
      #for $user in $results
      <tr>
          <td><a href="/users/$user.login">$user.name</a></td>
          <td>$user.phone</td>
      </tr>
      #end for
  </table>

  #end if

  #end block body
To understand Cheetah, keep in mind that:
  • Cheetah files end with the .tmpl extension.
  • We "extend" the master page, in close analogy with subclassing in Python itself, or a similar object-oriented language. The page attributes here are like class members visible "from outside", both for reading and writing.
  • This page's body block replaces the body block of the master page.
  • Python code starts with #. Unlike conventional Python source there is an explicit end tag: end closes code blocks.
  • Comments start with ##. #* and *# begin and end, respectively, multi-line comments.
We put this template to use with:
        page.query = query 
	page.results = results
	return str(page)
Similarly, the user page is
    #extends master
  
    #block body
  
    ## Display user
    <h1>$user.name</h1><table>
        <tr>
            <td>Login:</td>
  
            <td>$user.login</td>
        </tr>
        <tr>
            <td>Phone:</td>
            <td>$user.phone</td>
        </tr>
    </table>
  
    #end block body
Using the Templates Cheetah compiles the .tmpl pages to .py pages. If you have a base page (like our master), you must compile it. The cheetah-compile script does this.

We use a different approach: Cheetah Template classes, for which we load the template:

       def get_page(name):
           '''Get a page template'''
	   return Template(file = '%s.tmpl' % name)
    
The Web Server The CherryPy framework has the following conventions:
  • Set cherrypy.root to your Web application class.
  • expose all methods you want to be reflected as Web pages.
  • Use cherrypy.config to set server configuration.
  • The index method is the access point to your server.
  • Give a default value to each parameter you'll get from a Web form.
  • The default method catches all requests that don't have an explicit exposed method.
  • Enable "sessionFilter.on" to get session support.
Our index method just searches for the query, populates the template, and displays it:
    @expose
    def index(self, query = None, within = 0):
        '''Index'''
        page = get_page("index")
        # Initial page
        if query is None:
            return str(page)

        # Search and display results
        page.query = query
        if within and session.get(RESULTS, None):
            results = search(query, session[RESULTS])
        else:
            results = search(query)

        session[RESULTS] = results
        page.results = results

        return str(page) 
Note the decorator syntax. If you work with a version of Python before 2.4, you can write
      index.exposed = 1
Running the server is easy:
      cherrypy.root = AddrBook()
      config.update(CONFIG)
      server.start()
Configuration CherryPy configuration comes from either a file formatted in a style intended to be obvious, or with a dictionary. Typical content for the former — for the configuration file — might be:
[global]
sessionFilter.on = 1
autoreload.on    = 0 
Invoke this with:
config.update(file = "addressbook.conf")
The corresponding dictionary approach is to define:
      CONFIG = {
          'sessionFilter.on' : 1,
	  'autoreload.on'    : 0
and invoke:
config.update(CONFIG)    

CherryPy is quite flexible. Consult the manual for the all of the options it exposes to configuration control.

Among these, the two that we use are sessionFilter.on, which enables session support, and autoreload.on, which instructs the server to restart itself whenever one of the modules it is using changes. autoreload.on shortens the development cycle, because it eliminates the programmer's need to stop and start the server during development. It's typically turned off for production, though, on security and performance grounds.

Advanced Issues

CSS

Use CSS for better layout. All CherryPy requires is a reference to the CSS in your master template and a definition of and a definition of the CSS file as static in the server configuration.

Running Under a Web Server

CherryPy comes with its own Web server. To use it with a different one — perhaps one on which you already rely — you have the following options:

  • Run your application on a different port and connect to myserver:8283.
  • Proxy requests from your Web server to your Web application.
  • Run your server as an fcgi or scgi application.
  • Use mode_python.

Performance

Remember that "Premature optimization is the root of all evil". However, if you find out things are a bit slow for your needs, consider the following options:

  • Serve static content directly from your Web server.
  • Pre-compile all Cheetah templates.
  • Use the Cheetah caching mechanism.

Summary

We've built a Web-based addressbook in fewer than 150 lines of code!

This introduction demonstrates how easy Web development with CherryPy and Cheetah can be. Next time someone asks you for a "small" internal application that you'd conventionally do as a standalone executable, consider all the advantages Web applications enjoy in deployment, networking, security standardization, and even training. They're available to you.

Miki Tebeka is a Software Process Engineer for Qualcomm Corporation. Cameron Laird, vice president of Phaseit, Inc., has co-authored "Regular Expressions" for seven years.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.