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

CherryPy and the Interactive Interpreter

March 05, 2006 at 10:37 PM | categories: Python, cherrypy, General

I read a couple blog entries in the past week about the Python interactive interpreter and how great it is. I have always found the interactive interpreter extremely useful, not to mention downright fun to mess around with. It is truly one of the really neat features of Python.

Reading those entries reminded me that I wanted to post something about how easy it is to mess around with CherryPy from within the interactive interpreter. Maybe you can do this in some of the other hip Python web frameworks as well; I'm not sure.

To showcase this Python/CherryPy goodness, I have created my first nerd^H^H^H^Hscreencast*. It's short and pretty basic, but you should get the general idea. I think it further showcases the pythonic nature of CherryPy. Pardon the sketchy monologue by yours truly.

CherryPy Interactive ~1MB, Flash

The concepts in this simple demo can be used to do real interactive debugging. You could turn off the autoreloader and logging to screen in an app you are developing and run it like python -i start_your_app.py or ipython start_your_app.py. You are then inside the running application, and you can make requests to it from a browser and poke around inside using the interactive interpreter.

That's all. Feedback welcome.

cw

*Thanks to Wink, Audacity and swftools

CP 2.2 Applications and Configuration

February 28, 2006 at 06:34 AM | categories: cherrypy, General

So what best practices should one follow when planning for the configuration of a redistributable CherryPy 2.2 application? That's not a rhetorical question. ;-) I'm hoping to get a bit of brain dumping here from those of you in the CP community that will hopefully make its way into some official documentation.

In 2.2, there is new support for mounting applications at various points on the CP object tree.

import cherrypy
from myblog import App, blog_config

cherrypy.tree.mount(App(), '/blog', blog_config)

App, of course, is our main application class. /blog is the point that we want to mount the application at. Finally, blog_config is a dictionary of app specific configuration values or an INI-style config file.

Configuration

The problem I see with this setup is that values from blog_config are not available to App at its initialization point. That means only config information that is required per-request is useful to have in blog_config. Any configuration I need at initialization time can't be stored in the CP config file for App.

So what are my options? Here are a few I can think of:

  • Additional config file required by ``App``(use ConfigParser)

    System Message: WARNING/2 (<string>, line 24); backlink

    Inline literal start-string without end-string.

  • Pass config info to App's constructor

  • Require deployer to put an [app] section in their main CP config file

Did I miss anything?

The reason I am bringing this up is because I am trying to package Brockman, my Python project catalog application. In a sample start_brockman.py script, I did the following (which I guess is yet another way to handle configuration):

cherrypy.config.update(file='/path/to/brockman.conf', baseurl='/brockman')
cherrypy.tree.mount(brockman.app(), '/brockman')

Thinking of someone deploying my application (c'mon, a guy can dream, right ;-) ), I want to have as simple and robust a way as possible for configuration to happen.

So what are some thoughts?

cw

Deploying CherryPy (or other Python web) Applications

February 09, 2006 at 10:34 AM | categories: Python, cherrypy, General

I have been thinking lately about how it is still pretty involved to deploy a CherryPy (or any Python web) application to a "production" server (Apache, lighttpd, IIS, etc).

The easiest method that I know at this point is mod_proxy with Apache:

Virtualhost *
    ServerName cpsite.server.domain
    CustomLog "/var/log/apache/cpsite/access_log" combined
    ErrorLog /var/log/apache/cpsite/error_log
    ProxyPass / http://localhost:8081/
    ProxyPassReverse / http://localhost:8081/
/Virtualhost

As long as the "cpsite" app is running on port 8081, everything should be cool.

If you are running Apache 2, you can even do this (grabbed from the CP wiki):

Location /myapp
ProxyPass http://localhost:8080
ProxyPassReverse http://localhost:8080
RequestHeader set CP-Location /myapp
/Location

If you want to do WSGI, it starts getting quite a bit more complicated. You need FCGI or SCGI or mod_python support for Apache and a handful of other Python libraries/modules to glue your (CP) WSGI app to the production server.

Are there any other easier ways that I am missing?

One thing that I like about the way PHP works is how easy it is to deploy apps. It usually works like this.

  1. Stick app's folder somewhere in your document root
  2. Modify the app's config.php file
  3. (maybe) Browse to http://theserver/theapp/install.php and follow the steps

That's pretty simple. *sigh*

Dreaming of mod_wsgi,

cw

WSGI Mania

February 05, 2006 at 04:22 PM | categories: Python, cherrypy, General

I finally get it. I feel somewhat hip to WSGI.

A big thanks to Ben Bangert and his article WSGI and WSGI Middleware is Easy, which I like to call WSGI for Dummies ;-)

Anyhow, now that I "get it", I have been messing with WSGI a bit.

WSGIAppFilter for `CherryPy <http://www.cherrypy.org/>`_ (targetting 2.2) This handy filter allows you to mount a WSGI application in the CP object tree. A prerelease version is at my projects site. Some apps/frameworks I have tested running inside CP:

WSGI Middleware for `CherryPy <http://www.cherrypy.org/>`_ (and other stuff) I have been working towards the goal of wrapping the CherryPy wsgiApp callable in middleware. I wrote a replacement server and then began trying to integrate my changes into the core. It hasn't been a walk in the park, and the code isn't in CherryPy yet, but it has been a good learning experience if nothing else. Robert Brewer has made me rethink my approach a few times, which is never a bad thing. Ian Bicking has provided good insight into WSGI in general.

Adding WSGI to `Leonardo <http://www.jtauber.com/leonardo>`_ I recently came across the excellent Leonardo project. It is a very nice Python CMS/Blog/Wiki type web app. When looking around for apps to test out my WSGI filter, I thought I would check and see if it had a WSGI implementation. Turns out it didn't, but after a few hours I managed to wrap the necessary Leonardo functionality in a WSGI app callable and had it running under CherryPy with my WSGIAppFilter and under the wsgiref server. I shared the code with James Tauber, Leonardo's creator, and he is going to test it out and possibly integrate it into the project.

All in all, I have been having fun with Python (as usual) and WSGI. There is also something brewing on the Python WEB-SIG regarding a PEPified templating API that builds on the TurboGears/Buffet templating plugin standard. We'll see what comes of that.

cw

« Previous Page -- Next Page »