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
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
--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?).
uwsgi --help for more information on how to spawn a server using the protocol you need.
Screenshot of the app running in my browser:
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.