Download - werkzeug en
-
8/14/2019 werkzeug en
1/126
The Swiss-Army Knife for Python Web Developers
Armin Ronacher http://lucumr.pocoo.org/
http://lucumr.pocoo.org/http://lucumr.pocoo.org/ -
8/14/2019 werkzeug en
2/126
About Me
-
8/14/2019 werkzeug en
3/126
About Me
Name: Armin Ronacher Werkzeug, Jinja, Pygments, ubuntuusers.de
Python since 2005
WSGI warrior since the very beginning(well, not quite)
-
8/14/2019 werkzeug en
4/126
Why Python?
-
8/14/2019 werkzeug en
5/126
Why Python?
agile
active community
countless modules
powerful introspection functionality
WSGI
-
8/14/2019 werkzeug en
6/126
WSGI
-
8/14/2019 werkzeug en
7/126
WSGI
Web Server Gateway Interface
lowlevel interface between application andserver
allows to reuse code between applications
CGI / FastCGI / SCGI / AJP / mod_python /
mod_wsgi / twisted / standalone simple and fast
-
8/14/2019 werkzeug en
8/126
Hello World
-
8/14/2019 werkzeug en
9/126
Hello World
-
8/14/2019 werkzeug en
10/126
Hello World
-
8/14/2019 werkzeug en
11/126
Hello World
-
8/14/2019 werkzeug en
12/126
Deployment
-
8/14/2019 werkzeug en
13/126
Deployment
-
8/14/2019 werkzeug en
14/126
Deployment
-
8/14/2019 werkzeug en
15/126
Deployment
-
8/14/2019 werkzeug en
16/126
Deployment
-
8/14/2019 werkzeug en
17/126
-
8/14/2019 werkzeug en
18/126
Middlewares
-
8/14/2019 werkzeug en
19/126
Middlewares
middlewares work between server andapplication
-
8/14/2019 werkzeug en
20/126
Middlewares
middlewares work between server andapplication
can manipulate incoming and outgoing data
-
8/14/2019 werkzeug en
21/126
Middlewares
middlewares work between server andapplication
can manipulate incoming and outgoing data
useful to
log errors
fix broken server data combine multiple applications
-
8/14/2019 werkzeug en
22/126
But....
-
8/14/2019 werkzeug en
23/126
But....
...an application shouldnt depend on anmiddleware
-
8/14/2019 werkzeug en
24/126
But....
...an application shouldnt depend on anmiddleware
http://dirtsimple.org/2007/02/wsgi-middleware-considered-harmful.html
http://dirtsimple.org/2007/02/wsgi-middleware-considered-harmful.htmlhttp://dirtsimple.org/2007/02/wsgi-middleware-considered-harmful.html -
8/14/2019 werkzeug en
25/126
But....
...an application shouldnt depend on anmiddleware
http://dirtsimple.org/2007/02/wsgi-middleware-considered-harmful.html
http://dirtsimple.org/2007/02/wsgi-middleware-considered-harmful.htmlhttp://dirtsimple.org/2007/02/wsgi-middleware-considered-harmful.html -
8/14/2019 werkzeug en
26/126
Setup
-
8/14/2019 werkzeug en
27/126
Setup central runner file:
-
8/14/2019 werkzeug en
28/126
Setup central runner file:
application.fcgi mod_fastcgi
-
8/14/2019 werkzeug en
29/126
Setup central runner file:
application.fcgi mod_fastcgi
application.wsgi mod_wsgi
-
8/14/2019 werkzeug en
30/126
Setup central runner file:
application.fcgi mod_fastcgi
application.wsgi mod_wsgi
run-application.py standalone / wsgiref
-
8/14/2019 werkzeug en
31/126
Setup central runner file:
application.fcgi mod_fastcgi
application.wsgi mod_wsgi
run-application.py standalone / wsgiref
imports application and middlewares
-
8/14/2019 werkzeug en
32/126
Setup central runner file:
application.fcgi mod_fastcgi
application.wsgi mod_wsgi
run-application.py standalone / wsgiref
imports application and middlewares combines it and creates and application object
or calls the gateway
-
8/14/2019 werkzeug en
33/126
Setup central runner file:
application.fcgi mod_fastcgi
application.wsgi mod_wsgi
run-application.py standalone / wsgiref
imports application and middlewares combines it and creates and application object
or calls the gateway
-
8/14/2019 werkzeug en
34/126
Summary
-
8/14/2019 werkzeug en
35/126
Summary
application: callable object
-
8/14/2019 werkzeug en
36/126
Summary
application: callable object
environ incoming data
-
8/14/2019 werkzeug en
37/126
Summary
application: callable object
environ incoming data
start_response starts the response
-
8/14/2019 werkzeug en
38/126
Summary
application: callable object
environ incoming data
start_response starts the response
app_iter an iterator, each iteration sends
data to the client
-
8/14/2019 werkzeug en
39/126
Summary
application: callable object
environ incoming data
start_response starts the response
app_iter an iterator, each iteration sends
data to the client
middleware: between application and gateway
-
8/14/2019 werkzeug en
40/126
Summary
application: callable object
environ incoming data
start_response starts the response
app_iter an iterator, each iteration sends
data to the client
middleware: between application and gateway gateway: translates WSGI to CGI etc.
-
8/14/2019 werkzeug en
41/126
-
8/14/2019 werkzeug en
42/126
Werkzeug
unicode handling
-
8/14/2019 werkzeug en
43/126
Werkzeug
unicode handling
form data / file uploads / url parameter
parsing
-
8/14/2019 werkzeug en
44/126
Werkzeug
unicode handling
form data / file uploads / url parameter
parsing URL dispatching
-
8/14/2019 werkzeug en
45/126
Werkzeug
unicode handling
form data / file uploads / url parameter
parsing URL dispatching
HTTP parsing
-
8/14/2019 werkzeug en
46/126
Werkzeug
unicode handling
form data / file uploads / url parameter
parsing URL dispatching
HTTP parsing
development server
-
8/14/2019 werkzeug en
47/126
Werkzeug
unicode handling
form data / file uploads / url parameter
parsing URL dispatching
HTTP parsing
development server
autoreloader
-
8/14/2019 werkzeug en
48/126
Werkzeug
unicode handling
form data / file uploads / url parameter
parsing URL dispatching
HTTP parsing
development server
autoreloader
countless small helpers
-
8/14/2019 werkzeug en
49/126
What is it not?
-
8/14/2019 werkzeug en
50/126
What is it not?
ORM
-
8/14/2019 werkzeug en
51/126
What is it not?
ORM
template engine
-
8/14/2019 werkzeug en
52/126
What is it not?
ORM
template engine form-validation
-
8/14/2019 werkzeug en
53/126
What is it not?
ORM
template engine form-validation
i18n / l10n
-
8/14/2019 werkzeug en
54/126
What is it not?
ORM
template engine form-validation
i18n / l10n
component architecture
-
8/14/2019 werkzeug en
55/126
What is it not?
ORM
template engine form-validation
i18n / l10n
component architecture
a framework
-
8/14/2019 werkzeug en
56/126
Why not?
-
8/14/2019 werkzeug en
57/126
Why not?
such things exist already
-
8/14/2019 werkzeug en
58/126
Why not?
such things exist already you can combine them
-
8/14/2019 werkzeug en
59/126
Why not?
such things exist already you can combine them
everybody wants something else
-
8/14/2019 werkzeug en
60/126
Why not?
such things exist already you can combine them
everybody wants something else
cherry picking!
-
8/14/2019 werkzeug en
61/126
-
8/14/2019 werkzeug en
62/126
What does it look like?
-
8/14/2019 werkzeug en
63/126
-
8/14/2019 werkzeug en
64/126
DumpIt!a pastebin in 15 minutes
-
8/14/2019 werkzeug en
65/126
What do we use?
-
8/14/2019 werkzeug en
66/126
What do we use?
Werkzeug
-
8/14/2019 werkzeug en
67/126
What do we use?
Werkzeug
Jinja
-
8/14/2019 werkzeug en
68/126
What do we use?
Werkzeug
Jinja sqlite3
-
8/14/2019 werkzeug en
69/126
What do we use?
Werkzeug
Jinja sqlite3
Pygments
-
8/14/2019 werkzeug en
70/126
What do we use?
Werkzeug
Jinja sqlite3
Pygments
WSGI
-
8/14/2019 werkzeug en
71/126
What do we use?
Werkzeug
Jinja sqlite3
Pygments
WSGI
Templates
-
8/14/2019 werkzeug en
72/126
What do we use?
Werkzeug
Jinja sqlite3
Pygments
WSGI
TemplatesDatabase
-
8/14/2019 werkzeug en
73/126
What do we use?
Werkzeug
Jinja sqlite3
Pygments
WSGI
TemplatesDatabase
Code Highlighting
-
8/14/2019 werkzeug en
74/126
What do we use?
Werkzeug
Jinja sqlite3
Pygments
WSGI
TemplatesDatabase
Code Highlighting
-
8/14/2019 werkzeug en
75/126
#0: Database
-
8/14/2019 werkzeug en
76/126
#0: Database
-
8/14/2019 werkzeug en
77/126
#1: Imports
-
8/14/2019 werkzeug en
78/126
-
8/14/2019 werkzeug en
79/126
-
8/14/2019 werkzeug en
80/126
#2: Configuration
-
8/14/2019 werkzeug en
81/126
#3: Dispatching
-
8/14/2019 werkzeug en
82/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
83/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
84/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
85/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
86/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
87/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
88/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
http://localhost:5000/pygments.csshttp://localhost:5000/pygments.csshttp://localhost:5000/42/rawhttp://localhost:5000/42/rawhttp://localhost:5000/42http://localhost:5000/42http://localhost:5000/http://localhost:5000/ -
8/14/2019 werkzeug en
89/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
90/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
91/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
92/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
Di hi
-
8/14/2019 werkzeug en
93/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
3 Di hi
-
8/14/2019 werkzeug en
94/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
#3 Di hi
-
8/14/2019 werkzeug en
95/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
#3 Di hi
-
8/14/2019 werkzeug en
96/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
#3 Di t hi
-
8/14/2019 werkzeug en
97/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
#3 Di t hi
-
8/14/2019 werkzeug en
98/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
#3 Di t hi
-
8/14/2019 werkzeug en
99/126
#3: Dispatchingurl_map = Map([
Rule('/', endpoint='new_paste'),Rule('/', endpoint='show_paste'),
Rule('//raw', endpoint='download_paste'),Rule('/pygments.css', endpoint='pygments_style')
])
defapplication(environ, start_response):request = Request(environ)
request.db = sqlite3.connect(DATABASE)url_adapter = url_map.bind_to_environ(environ)
try:endpoint, values = url_adapter.match()
response = globals()[endpoint](request, **values) if isinstance(response, basestring):
response = Response(response, mimetype='text/html') except HTTPException, error:
response = error return response(environ, start_response)
-
8/14/2019 werkzeug en
100/126
#4 Vi
-
8/14/2019 werkzeug en
101/126
#4: Views
#4 Vi
-
8/14/2019 werkzeug en
102/126
#4: Views
#4 Vi
-
8/14/2019 werkzeug en
103/126
#4: Views
#4 Vi
-
8/14/2019 werkzeug en
104/126
#4: Views
#4 Vi
-
8/14/2019 werkzeug en
105/126
#4: Views
#5 M d l
-
8/14/2019 werkzeug en
106/126
#5: Model
#5 M d l
-
8/14/2019 werkzeug en
107/126
#5: Model
#5 M d l
-
8/14/2019 werkzeug en
108/126
#5: Model
#6 Templates
-
8/14/2019 werkzeug en
109/126
#6: Templates
#6 Templates
-
8/14/2019 werkzeug en
110/126
#6: Templates
#6: Templates
http://www.w3.org/TR/html4/strict.dtdhttp://www.w3.org/TR/html4/strict.dtd -
8/14/2019 werkzeug en
111/126
#6: Templates
#6: Templates
http://www.w3.org/TR/html4/strict.dtdhttp://www.w3.org/TR/html4/strict.dtd -
8/14/2019 werkzeug en
112/126
#6: Templates
http://www.w3.org/TR/html4/strict.dtdhttp://www.w3.org/TR/html4/strict.dtd -
8/14/2019 werkzeug en
113/126
Development Server
-
8/14/2019 werkzeug en
114/126
Development Server
-
8/14/2019 werkzeug en
115/126
Dump It! In Action
-
8/14/2019 werkzeug en
116/126
Dump It! In Action
Dump It! In Action
-
8/14/2019 werkzeug en
117/126
Dump It! In Action
Dump It! In Action
-
8/14/2019 werkzeug en
118/126
Dump It! In Action
-
8/14/2019 werkzeug en
119/126
More Than One Way
-
8/14/2019 werkzeug en
120/126
More Than One Way
Templates: XML / Text-based / Sandbox
More Than One Way
-
8/14/2019 werkzeug en
121/126
More Than One Way
Templates: XML / Text-based / Sandbox
Daten: SQL / CouchDB / Filesystem
More Than One Way
-
8/14/2019 werkzeug en
122/126
More Than One Way
Templates: XML / Text-based / Sandbox
Daten: SQL / CouchDB / Filesystem
AJAX: JSON / XML / HTML Fragments
More Than One Way
-
8/14/2019 werkzeug en
123/126
More Than One Way
Templates: XML / Text-based / Sandbox
Daten: SQL / CouchDB / Filesystem
AJAX: JSON / XML / HTML Fragments URLs: Regular Expressions / Werkzeug
Routing / Routes / Objekt-basierend / Query
Parameters
More Than One Way
-
8/14/2019 werkzeug en
124/126
More Than One Way
Templates: XML / Text-based / Sandbox
Daten: SQL / CouchDB / Filesystem
AJAX: JSON / XML / HTML Fragments URLs: Regular Expressions / Werkzeug
Routing / Routes / Objekt-basierend / Query
Parameters
Dispatching: Controller / View-Functions
More Than One Way
-
8/14/2019 werkzeug en
125/126
More Than One Way
Templates: XML / Text-based / Sandbox
Daten: SQL / CouchDB / Filesystem
AJAX: JSON / XML / HTML Fragments URLs: Regular Expressions / Werkzeug
Routing / Routes / Objekt-basierend / Query
Parameters
Dispatching: Controller / View-Functions Auth: Apache / LDAP / OpenID
-
8/14/2019 werkzeug en
126/126
http://werkzeug.pocoo.org/http://lucumr.pocoo.org/talks/ltgraz08/
http://lucumr.pocoo.org/talks/ltgraz08/http://lucumr.pocoo.org/talks/ltgraz08/http://werkzeug.pocoo.org/http://werkzeug.pocoo.org/