Getting CherryPy Working With uWSGI

Since Python 3 is the future, I directly started with Python 3 for my projects. While, There are some frameworks for Python 3, but I’m not a fan of frameworks. I prefer to glue the components myself and write the application – even if it involves more work and boilerplate code, and that’s because of freedom.

When you use a particular framework, you’re bound to a few rules and and modifying the behavior of the rules gets quite difficult, unless you know the framework you’re using from head to tail completely in detail. Half knowledge is very bad.

I knew about CherryPy since Python 2, and when I studied how to write applications using that, it became my favorite framework. CherryPy is basically a minimal framework, or more specifically a server which handles the common headaches that are required to do when writing a web application in Python. The common headaches are like mapping a request into Controller/Action, handling HTTP errors, authentication, etc. No, these tasks are not difficult, but are rather time consuming because of the size of the code involved.

So, why not use a pre-built framework? I’m negating my own statement, eh? Yes. In this case, freedom is not a strict requirement as much as it is required in the application logic, and CherryPy supports Python 3 – Awesomeness.

CherryPy can be deployed by various methods – It has an inbuilt HTTP server, it can be used as a FastCGI, SCGI and CGI server as well. The point is, HTTP parsing is slow, and doing a slow task using an interpreted language – doesn’t get me. I could very well use CherryPy’s HTTP server as the server for website and stay quiet. That doesn’t work because we’ll be running a relatively slower code (as compared to C/C++, in which web servers are usually written) even for static resources! This is a big waste of resources.

CherryPy uses the Flup1 module for FastCGI/SCGI/CGI implementation and unfortunately, there’s isn’t a working release of the same for Python 3. It’s development seems to have stalled. I was able to install and use the Flup module in Python 3. It installed successfully, but it seems some of the code in it wasn’t ported to Python 3, running 2to3 fixed it. What about any Bugs in it? – The biggest problem. It doesn’t have a public release! If the author had released a version, I would have just used it.

uWSGI is a application container written in pure C. It has a lot of features like multiple protocol support, process management, easy configuration and a lot. You can learn more about it at the official website.

As per the Python PEP-33332, the WSGI application (a callable) should be named as application, should accept two parameters and return bytes after calling the function that comes as second parameter (usually named as start_response).

The same specification is used by uWSGI. But the problem here is, how to get CherryPy running with uWSGI, since the default method is to spawn a HTTP server if you use cherrypy.quickstart() or, use the cherryd command. You can spawn a FastCGI/SCGI/CGI server with the cherryd command (which requires the Flup module).

In the uWSGI case, the server processes are handled by uWSGI, so you need not spawn any processes in your application. After a lot of searching around, reading manuals and experimenting I finally found a workaround to get this thing working.

Here’s a simple code which deploys two apps (basically two classes) using cherrypy:

#!/usr/bin/python3

# Script written by NileshGR (http://nileshgr.com)
# This script is under BSD license

import cherrypy

class One:
  @cherrypy.expose
  def index(self):
    r = cherrypy.response
    r.headers['Content-Type'] = 'text/plain'
    return "Hello World"

class Two:
  @cherrypy.expose
  def default(self, *args, **kwargs):
    r = cherrypy.response
    r.headers['Content-Type'] = 'text/plain'
    content = "Positional arguments\n\n"
    for k in args:
      content += k + "\n"
    content += "\nKeyword arguments\n\n"
    for k in kwargs:
      content += k + ": " + kwargs[k] + "\n"
    return content

def application(environ, start_response):
  cherrypy.tree.mount(One(), '/', None)
  cherrypy.tree.mount(Two(), '/par', None)
  return cherrypy.tree(environ, start_response)

The first two classes are CherryPy applications. Notice the last part, after line #28, we’re defining a function named application(environ, start_response) as specified by PEP-33332.

In the function, we mount the first application at mount point / and the second application at mount point /par and finally return cherrypy.tree(environ, start_response which is transfers control to CherryPy. The secret here is in the fact that, cherrypy.tree is a WSGI compatible application and which is why this works!

Quoting the text from cherrypy.tree doc page (pydoc):

cherrypy.tree = class Tree(builtins.object)
 |  A registry of CherryPy applications, mounted at diverse points.
 |  
 |  An instance of this class may also be used as a WSGI callable
 |  (WSGI application object), in which case it dispatches to all
 |  mounted apps.

Starting the uWSGI server to run our CherryPy application:

uwsgi --http :8080 --wsgi-file cherrypy_uwsgi.py

I passed --http to uWSGI because I don’t have a WSGI capable HTTP server on my PC where I do all this development and test work. Anyway, if HTTP with uWSGI works, then the other protocols like WSGI, FastCGI, etc. that uWSGI implements should also work (isn’t that obvious?).

See uwsgi --help for more information on how to spawn a server using the protocol you need.

Screenshot of the app running in my browser:

cherrypy_uwsgi

The credit to what made me try this out and get it working goes to @unbit who helped me out on Twitter and pointed me to this article on CherryPy wiki.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: