Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

CherryPy, Paste and WSGI

CherryPy, like Paste and a slew of other Python web projects, is a good fit for use in web applications built on/from a WSGI stack.

Playing Nice

Let's take a look at how Paste and CherryPy can be combined to piece together the skeleton of a website made from smaller component applications. For a real site, there would need to be plenty of customization beyond the initial WSGI composition, but it is a start.

The Players

  • CherryPy 3
  • Paste 1.1 (EvalException, URLMap, PasteDeploy and PasteScript)
  • WSGIUtils

The Home Team

To start with, we will need a small helper function to make an "app_factory" as defined by the PasteDeploy docs.

We also make sure that cherrypy.engine.start only gets called once. This is probably not the best solution, so if you come up with something better, please share on the cherrypy-users mailing list.

#cpwsgihelper.py

import cherrypy
from cherrypy._cpengine import STARTED, STARTING, STOPPED

# some friendly global config entries
cherrypy.config.update({'global':{'request.throw_errors':True,
                                  'log.screen':False,
                                  'engine.autoreload_on':False,
                                  }
                        })

def init_wsgi():
    """Start the CherryPy engine, but only once, in case there are multiple

    CP WSGI apps in use in one process.
    """
    
    if cherrypy.engine.state not in (STARTED, STARTING):
        cherrypy.engine.start(blocking=False)

def make_factory(root):
    """Return a PasteDeploy compatible app_factory that will configure
    the given Application root.
    """
    
    def app_factory(global_config, **local_conf):
        cherrypy.config.update(global_config)
        app = cherrypy.Application(root(), script_name=None)
        app.merge({'/': local_conf})
        init_wsgi()
        return app
    return app_factory

Now let's create a simple "application" that we will pretend is a blog:

#cp_blog_app.py

import cherrypy
from cpwsgihelper import make_factory

class BlogApp(object):
    @cherrypy.expose
    def index(self):
        return "Blog app index"

    @cherrypy.expose
    def foo(self):
        # this config value comes from the PasteDeply config file
        return cherrypy.request.config['bar']

    @cherrypy.expose
    def problem(self):
        assert 0, "Aaaaaahhhhh!"

# create an app factory for using the application with Paste Deploy
app_factory = make_factory(BlogApp)

Put that file into a folder called "blogapp" or something. The main thing to notice here is that we create a PasteDeploy compatible WSGI app_factory with the make_factory function. Paste is able to call that function with configuration information and get back a configured cherrypy.Application instance.

Now we need a setup script that will generate a setuptools egg for our application. CherryPy makes no assumptions on how you want to deploy your application, so creating the setup.py file is up to you.

Here's a super-simple example:

#setup.py
from setuptools import setup

setup(name="cp_blog_app",
      py_modules=["cp_blog_app"],
      entry_points={"paste.app_factory":["main=cp_blog_app:app_factory"]},
      )

The only special thing going on in setup.py is the definition of an "entry point" in the paste.app_factory entry point group. It is basically saying that applications that can make use of paste.app_factory can make use of our application via the "main" entry point. Read that over a few times and peek again at the source if you have to. You can also read more about entry points.

Go ahead and save that file in the same directory as cp_blog_app.py. Then, from a command prompt in that directory, run python setup.py develop. Basically, that will "install" the application to your Python site-packages location linked back to your the source in the current directory. I'm not going into it further - setuptools has completely adequate documentation already ;-)

Checkpoint 1

Let's take stock of what we have accomplished so far:

  • We have a module that provides a few utility functions to make working with independent CherryPy WSGI applications a little nicer.
  • We have a sweet blog application that we have written and installed as an Egg.
  • The blog application is installed with an "entry point" that allows us to easily use it from within PasteDeploy.

The Other Team Steps to the Plate

Ok, let's get some PasteDeploy action going. Save this as simple.conf:

[app:main]
use = egg:cp_blog_app#main
bar = let's play nice

[server:main]
use = egg:Paste#http
host = 127.0.0.1
port = 80

What we are doing here is telling PasteDeploy that we want to serve a single application from the cp_blog_app with the entry point "main" that we defined earlier. We also set a config value that will get passed along to the application (thanks to our make_factory}} function in {{{cpwsgihelpers). Finally, we define a server to launch that will host the application. Feel free to change the config defaults as necessary.

Let's test out what we've got. From a command prompt, run the following command:

Windows: c:\PythonXX\Scripts\paster serve simple.conf
*nix: paster serve simple.conf

If all goes well, that should start a server running on the specified port and you should be able to browse around to the various paths in the application ("/", "/foo" and "/problem"). Go ahead and try it out.

Checkpoint 2

In addition to everything in Checkpoint 1, we now have:

  • Our blog app configured by PasteDeploy.
  • Out blog app served by Paste's http server and launched via the paster serve command.

Pylons Steps up to the Plate

Pylons is an upcoming Python web framework that lives and breathes WSGI and Paste. Let's see if we can get it to play along too. I'm not going to go into creating and distributing a Pylons app - like setuptools, the documentation is out there if you want to do it yourself.

For a simple Pylons "helloworld" style app, all we need to do is adjust our PasteDeploy config file and allow something else to manage the URL space. We'll let Paste's URLMap handle that.

[composite:main]
use = egg:Paste#urlmap
/ = blogapp
/pylongs = pylonsapp

[app:blogapp]
use = egg:cp_blog_app#main
bar = let's play nice

[server:main]
use = egg:PasteScript#wsgiutils
host = 127.0.0.1
port = 80

[app:pylonsapp]
use = egg:helloworld#main
cache_dir = %(here)s/data
session_key = helloworld
session_secret = somesecret

There we are. We threw in the WSGIUtils WSGI server there for good measure as well. Run paster serve with your updated config file and you should have both a CherryPy and a Pylons app running in the same process.

Extra Innings

That's about it for the basics. There is a bit more in the archive attached to this wiki page. The source code for these examples plus an extended PasteDeploy config for two CP3 apps, one wrapped with middleware, and the Pylons helloworld app.

Attachments

Hosted by WebFaction

Log in as guest/cpguest to create tickets