The Occasional Occurence

CherryPy and WSGI

March 08, 2006 at 08:20 AM | categories: Python, cherrypy, General

Over the past few months, CherryPy has taken a bit of flack for the way its WSGI support has been implemented. With the explosion in popularity of TurboGears, people started wanting to do things with CherryPy that hadn't yet been perfected. There was some valid critcism raised against CP, and some good changes have come about because of it (and more will be coming!).

The future is bright for CherryPy, but the present isn't too dark either. Let's review some of the WSGI-related things you can do with the recently released CherryPy 2.2rc-1.

Multiple Apps One of the problems pointed out regarding CherryPy 2.1 was that it was hard to get multiple CherryPy apps to play nice in a single process. Some inroads have been made (mainly by Robert Brewer) in 2.2 to provide better support for this. Here is an example showing a wsgiutils WSGIServer serving a couple CherryPy applications and a web.py application wrapped with Paste's URLMap middleware:

# test_app.py
from wsgiutils import wsgiServer
from paste.urlmap import URLMap

from cpapps import wsgiApp
from webpyapp import wsgi_app

map_app = URLMap({})
map_app['/'] = wsgiApp
map_app['/apps/blog'] = wsgi_app
map_app['/apps/forum'] = wsgiApp

server = wsgiServer.WSGIServer(('localhost', 8080), {'':map_app,})

server.serve_forever()

That provides a server that dispatches to CherryPy for the paths / and /apps/forum and to web.py for /apps/blog.

Here is how you setup CherryPy to support multiple applications (imagine that Test and Forum are full fledged applications):

# cpapps.py
import cherrypy
from cherrypy._cpwsgi import wsgiApp

class Test(object):
    @cherrypy.expose
    def index(self):
        return "Hi from CP"

class Forum(object):
    @cherrypy.expose
    def index(self):
        return "Here is the forum"

cherrypy.tree.mount(Test(), "")
cherrypy.tree.mount(Forum(), "/apps/forum")

cherrypy.config.update({'autoreload.on':False,
                        'server.log_to_screen':False}
                      )

cherrypy.server.start(init_only=True, server_class=None, server=None)

The key in the example above using the cherrypy.tree.mount syntax to mount your applications on the CherryPy object tree.

It's not perfect. You have to tell both CherryPy and URLMap the layout of your CP url space. Using the same wsgiApp callable for two different CP apps is a bit strange compared to how most other frameworks are handling WSGI. But it does work. And it works today.

WSGI Environment In CP 2.1, the WSGI environment dictionary was not available inside of a running CherryPy application. In 2.2, it is available as cherrypy.request.wsgi_environ. Now your page handlers and filters can do stuff like path_info = cherrypy.request.wsgi_environ.get('PATH_INFO', ''). If you are using WSGI middleware that puts stuff in the environ dictionary (like some session middleware) you can get to that as well.

CherryPy's WSGI Server In CherryPy 2.1, the built-in CherryPyWSGIServer didn't dispatch correctly based on the WSGI SCRIPT_NAME and PATH_INFO variables. This has been corrected in 2.2. The CherryPyWSGIServer also supports mounting multiple WSGI applications, though that is easily accomplished with some dispatching middleware as well (like Paste's URLMap, used above).

Middleware and CherryPy's WSGI Server Some improvements were made to some other CherryPy internals that allow an application to be wrapped with WSGI middleware and served with CP's WSGI server fairly easily.

Hosting WSGI Applications within CherryPy If you want to use CherryPy as your main URL dispatcher, you can mount arbitrary WSGI applications on the CherryPy object tree using the WSGIApp class from my wsgi_filter. You could host a PyBloxsom blog and a MoinMoin wiki inside CP and apply CP filters to those apps.

In Conclusion ... Hopefully it is evident that WSGI support has not been shunned by the CherryPy dev team. CherryPy was around before WSGI and has had to make some changes to reach the level of support that it has for it today. More changes will come in the future to make it as WSGI friendly as possible.

In the meantime, I hope those of you looking for a pythonic web application system will take a serious look at CherryPy. For those of you who are using it already but are looking for better WSGI support; hang in there and let us know what you'd like to see. Even better, get to know the code and become a contributor.

Thanks for reading ;-)

cw