CherryPy and WSGI
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
March 8th, 2006 at 12:00 pm
FANTASTIC summary. Thanks!
March 8th, 2006 at 1:34 pm
Very well put. Thanks for this and our discussion yesterday on #cherrypy IRC. It helps me understand the landscape better.
March 9th, 2006 at 2:43 am
Great post Chris! It helps me a lot
March 9th, 2006 at 6:30 am
Thanks for the feedback guys.
March 9th, 2006 at 10:03 am
[...] Christian Wyglendowski posts a great summary of where CherryPy 2.2 stands with regards to WSGI. If you’ve followed the discussion on the various mailing lists and thought CherryPy only minimally handled WSGI, this post does a great job of setting the record straight. CP2.2’s WSGI support is not 100% ideal, but it’s way better than 2.1 and you can do an awful lot with it. Big kudos to Christian, Robert Brewer, Ian Bicking and Phillip Eby for hashing it out and coming up with an implementation that meets CherryPy’s backwards compatibility needs and takes a big step forward. [...]
March 9th, 2006 at 10:18 am
Excellent post, Christian! I had not known about your wsgi_filter, and I appreciate the enlightenment.
I’ve got a followup here regarding TG and WSGI:
http://www.blueskyonmars.com/2006/03/09/cherrypy-and-wsgi/
April 20th, 2008 at 5:56 pm
Okay, I am using CP3.0. I understand this might not be the place for this question but…
I am using apache mod_rewrite, without a proxy, so CP gets a url request thats not what I want. Is there a way to change that?