Werkzeug

The Swiss Army Knife For Python Web Developers

Welcome

Werkzeug started as a simple collection of various utilities for WSGI applications and has become one of the most advanced WSGI utility modules. It includes a powerful debugger, fully featured request and response objects, HTTP utilities to handle entity tags, cache control headers, HTTP dates, cookie handling, file uploads, a powerful URL routing system and a bunch of community contributed addon modules.

Werkzeug is unicode aware and doesn't enforce a specific template engine, database adapter or anything else. It doesn't even enforce a specific way of handling requests and leaves all that up to the developer.

Werkzeug is most useful for end user applications which should work in as many server environments as possible (such as blogs, wikis, bulletin boards, etc.).

Nutshell

Here is a tiny example that shows how you can use Werkzeug and the Mako template engine to generate simple dynamic pages.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from os import path
from werkzeug import Request, Response, SharedDataMiddleware
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException
from mako.lookup import TemplateLookup


# calculate the path of the folder this file is in, the application will
# look for templates in that path
root_path = path.abspath(path.dirname(__file__))

# create a mako template loader for that folder and set the default input
# encoding to utf-8
template_lookup = TemplateLookup(directories=[path.join(root_path, 'templates')],
                                 input_encoding='utf-8')

# here we can create the URL map.  Some sort of internal two-way
# mod rewrite :-)  The endpoints of those URLs are the names of the
# templates without the .html suffix we will render in the `dispatch_request`
# function.
url_map = Map([
    Rule('/', endpoint='index'),
    Rule('/hello/', defaults={'name': 'World'}, endpoint='say_hello'),
    Rule('/hello/<name>', endpoint='say_hello'),
    Rule('/shared/<file>', endpoint='shared', build_only=True)
])


@Request.application
def application(request):
    """A simple dispatch function that is the complete WSGI application
    that does the template rendering and error handling.
    """
    # first we bind the url map to the current request
    adapter = url_map.bind_to_environ(request.environ)
    # then we wrap all the calls in a try/except for HTTP exceptions
    try:
        # get the endpoint and the values (variable or parts)
        # of the adapter.  If the match fails it raises a NotFound
        # exception which is a HTTPException which we catch
        endpoint, values = adapter.match()
        # now create an empty response object with the correct mimetype.
        response = Response(mimetype='text/html')
        # now get the template and render it.  Pass some useful stuff
        # into the template (request and response objects, the current
        # url endpoint, the url values and a url_for function which can
        # be used to generate urls)
        template = template_lookup.get_template(endpoint + '.html')
        response.data = template.render_unicode(
            request=request,
            response=response,
            endpoint=endpoint,
            url_for=lambda e, **v: adapter.build(e, v),
            url_values=values
        )
        # now return the response
        return response
    except HTTPException, e:
        # if an http exception is catched we can return it as response
        # because those exceptions render standard error messages when
        # called as wsgi application
        return e


# Apply a WSGI middleware for static file serving
application = SharedDataMiddleware(application, {
    '/shared':  path.join(root_path, 'shared')
})


# if the script is called from the command line start the application
# with the development server on localhost:4000
if __name__ == '__main__':
    from werkzeug import run_simple
    run_simple('localhost', 4000, application)

And for completeness sake here is the “say_hello.html” template as one example:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd">
<title>Hello World Fun!</title>
<h1>Hello ${url_values['name']|h}!</h1>
<p><a href="${url_for('index')}">back to the index</a></p>

Put that template into the templates folder in order to make it work.

Going to http://localhost:4000/hello/John gives you “Hello John!” while http://localhost:4000/hello/ gives you “Hello World!” because World was defined as URL default in our URL map.

If you go to http://localhost:4000/ you will get an error because the “index.html” template is missing. But you can easily add that yourself.