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, full 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 on as many server environments as possible (such as blogs, wikis, bulletin boards, etc.).

Nutshell

Here 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 BaseRequest, BaseResponse, SharedDataMiddleware, responder
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)
])


def dispatch_request(environ, start_response):
    """
    A simple dispatch function that (if decorated with responder) 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(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 a new request object for the WSGI environment
        # passed
        request = BaseRequest(environ)
        # and create an empty response object with the correct mimetype.
        response = BaseResponse(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


# now finish the wsgi application by wrapping it in a middleware that
# serves static files in the shared folder and wrap the dispatch
# function in a responder so that the return value is called as wsgi
# application.
application = SharedDataMiddleware(responder(dispatch_request), {
    '/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 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>

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.

Now you can also add an index template with a link to the hello page or something like that.