Apr 9, 2013

CherryPy 101

CherryPy is one of the oldest frameworks for web development in the python world, most famously knows as http framework, and still there are a bunch of people who thinks that cherrypy is only a production grade webserver in python, but there is more to see in this wise framework that has been evolving in the last years.

This example demonstrate only the default dispatcher that is an object dispatcher, it looks for properties in the root object to find the handler for an specify URL, there are also a couple more of choices, a routes dispatcher which basically is a wrapper around routes and a method dispatcher, that I will cover on detail later on a different post.

import cherrypy

class WebApp(object):

    def __init__(self):
        self.user = User()

    def about(self):
        return ('Hi!, this is the about page '
                'go back to the <a href="/">Index page</a>.')

    def section(self, name):
        return ('Hi!, this is the section <b>%s</b> '
                'go back to the <a href="/">Index page</a>.'  % name)

    def index(self):
        """This is an special method which gets called when the url has no
        arguments, e.g.:  mysite.com/ or mysite.com/page/
        urls = [("/", "WebApp.index"),
                ("/about", "WebApp.about"),
                ("/section/a", "WebApp.section"),
                ("/section/b", "WebApp.section"),
                ("/section/c", "WebApp.section"),
                ("/a/b/c/d/e/f/g?one=1&amp;two=2&amp;three=3", "WebApp.default"),
                ("/user/", "User.index"),
                ("/user/list", "User.index"),
                ("/user/new", "User.new"),
                ("/user/edit/1", "User.edit"),
                ("/user/add", "User.add &lt;POST&gt; -> Method Not Allowed"),
                ("/user/delete", "User.delete &lt;POST&gt; -> Method Not Allowed")]
        pagecnt = ["<h1>CherryPy 101 Default dispatcher</h1>", ]
        pagecnt.append("<p>This are some (default can handle a lot more) "
                       " of the available pages: </p>")
        for url, method in urls:
            pagecnt.append('<li><a href="{0}">{0} -> {1}</a></li>'\
                           .format(url, method))
        for action in ['add', 'delete']:
            pagecnt.append('<form method="post" action="/user/%s">'
                           'User id: <input type="text" name="userid" value="1"/>'
                           '<input type="submit" value="%s user">'
                           '</form>' % (action, action.capitalize()))
        return ''.join(pagecnt)

    def default(self, *args, **kwargs):
        return ("This is a catch all page, it can handle any URL that you throw. "
                "If there is no match in any other previous handler this "
                "is going to be executed: <br/>"
                "<pre>args: %s \nkwargs: %s</pre>" % (args, kwargs))

class User(object):

    def new(self):
        return "New user"
    new.exposed = True # this is the real requirement to expose the method,
    # needs to have an attribute called "exposed" which need to be `True`.

    def index(self):
        return "List all the users "
    # but also the `expose` decorator had some tricks
    # the index method can be called also in /user/list/

    def edit(self, userid):
        return "Edit the user with id %s" % userid

    def add(self, **params):
        return "Adding new user with params %s" % params

    def delete(self, userid):
        return "The user with id: %s, has been removed." % userid

if __name__ == '__main__':

The cherrypy.quickstart function by default will start a webserver in the localhost listening to the port 8080, you can now go to you browser at the url http://localhost:8080 and see the results for yourself.

UPDATE: the post for the method dispatcher is here.

Tags: cherrypy webdev python