├── examples ├── couchy │ ├── __init__.py │ ├── templates │ │ ├── display.html │ │ ├── not_found.html │ │ ├── layout.html │ │ ├── new.html │ │ └── list.html │ ├── README │ ├── models.py │ ├── application.py │ ├── static │ │ └── style.css │ ├── views.py │ └── utils.py ├── shorty │ ├── __init__.py │ ├── templates │ │ ├── display.html │ │ ├── not_found.html │ │ ├── layout.html │ │ ├── new.html │ │ └── list.html │ ├── models.py │ ├── application.py │ ├── views.py │ ├── static │ │ └── style.css │ └── utils.py ├── contrib │ ├── README │ ├── sessions.py │ └── securecookie.py ├── i18nurls │ ├── __init__.py │ ├── templates │ │ ├── about.html │ │ ├── blog.html │ │ ├── index.html │ │ └── layout.html │ ├── urls.py │ ├── views.py │ └── application.py ├── cupoftee │ ├── shared │ │ ├── up.png │ │ ├── down.png │ │ ├── header.png │ │ ├── logo.png │ │ ├── content.png │ │ ├── favicon.ico │ │ └── style.css │ ├── templates │ │ ├── missingpage.html │ │ ├── layout.html │ │ ├── server.html │ │ ├── search.html │ │ └── serverlist.html │ ├── __init__.py │ ├── utils.py │ ├── db.py │ ├── pages.py │ └── application.py ├── partial │ ├── README │ └── complex_routing.py ├── coolmagic │ ├── public │ │ └── style.css │ ├── templates │ │ ├── static │ │ │ ├── about.html │ │ │ ├── not_found.html │ │ │ └── index.html │ │ └── layout.html │ ├── views │ │ ├── __init__.py │ │ └── static.py │ ├── __init__.py │ ├── helpers.py │ ├── application.py │ └── utils.py ├── shortly │ ├── templates │ │ ├── 404.html │ │ ├── layout.html │ │ ├── new_url.html │ │ └── short_link_details.html │ └── static │ │ └── style.css ├── plnt │ ├── __init__.py │ ├── templates │ │ ├── about.html │ │ ├── layout.html │ │ └── index.html │ ├── views.py │ ├── webapp.py │ ├── database.py │ └── shared │ │ └── style.css ├── simplewiki │ ├── templates │ │ ├── action_show.html │ │ ├── missing_action.html │ │ ├── page_index.html │ │ ├── macros.xml │ │ ├── page_missing.html │ │ ├── recent_changes.html │ │ ├── action_diff.html │ │ ├── action_edit.html │ │ ├── action_revert.html │ │ ├── action_log.html │ │ └── layout.html │ ├── __init__.py │ └── specialpages.py ├── manage-couchy.py ├── manage-cupoftee.py ├── manage-i18nurls.py ├── manage-coolmagic.py ├── manage-shorty.py ├── webpylike │ ├── example.py │ └── webpylike.py ├── manage-webpylike.py ├── manage-simplewiki.py ├── upload.py ├── httpbasicauth.py ├── manage-plnt.py ├── README └── cookieauth.py ├── werkzeug ├── testsuite │ ├── res │ │ └── test.txt │ ├── multipart │ │ ├── ie6-2png1txt │ │ │ ├── text.txt │ │ │ ├── file1.png │ │ │ ├── file2.png │ │ │ └── request.txt │ │ ├── firefox3-2png1txt │ │ │ ├── text.txt │ │ │ ├── file1.png │ │ │ ├── file2.png │ │ │ └── request.txt │ │ ├── opera8-2png1txt │ │ │ ├── text.txt │ │ │ ├── file1.png │ │ │ ├── file2.png │ │ │ └── request.txt │ │ ├── webkit3-2png1txt │ │ │ ├── text.txt │ │ │ ├── file1.png │ │ │ ├── file2.png │ │ │ └── request.txt │ │ ├── firefox3-2pnglongtext │ │ │ ├── text.txt │ │ │ ├── file1.png │ │ │ ├── file2.png │ │ │ └── request.txt │ │ ├── ie7_full_path_request.txt │ │ └── collect.py │ ├── contrib │ │ ├── __init__.py │ │ ├── securecookie.py │ │ ├── sessions.py │ │ └── wrappers.py │ ├── compat.py │ ├── internal.py │ ├── exceptions.py │ └── serving.py ├── debug │ └── shared │ │ ├── less.png │ │ ├── more.png │ │ ├── source.png │ │ ├── ubuntu.ttf │ │ └── console.png └── contrib │ ├── __init__.py │ ├── limiter.py │ └── testtools.py ├── docs ├── logo.pdf ├── _static │ ├── contents.png │ ├── favicon.ico │ ├── header.png │ ├── shortly.png │ ├── werkzeug.png │ ├── background.png │ ├── navigation.png │ ├── codebackground.png │ ├── debug-screenshot.png │ ├── navigation_active.png │ ├── shorty-screenshot.png │ └── werkzeug.js ├── latexindex.rst ├── _themes │ ├── werkzeug │ │ ├── theme.conf │ │ ├── layout.html │ │ └── relations.html │ ├── README │ └── LICENSE ├── contrib │ ├── iterio.rst │ ├── lint.rst │ ├── atom.rst │ ├── profiler.rst │ ├── fixers.rst │ ├── index.rst │ ├── wrappers.rst │ ├── cache.rst │ ├── sessions.rst │ └── securecookie.rst ├── _templates │ ├── sidebarlogo.html │ └── sidebarintro.html ├── index.rst ├── makearchive.py ├── deployment │ ├── index.rst │ ├── cgi.rst │ ├── proxying.rst │ └── mod_wsgi.rst ├── werkzeugext.py ├── middlewares.rst ├── wsgi.rst ├── contents.rst.inc ├── terms.rst ├── utils.rst ├── transition.rst ├── debug.rst ├── make.bat ├── python3.rst ├── levels.rst ├── datastructures.rst ├── local.rst └── werkzeugstyle.sty ├── artwork └── logo.png ├── run-tests.py ├── setup.cfg ├── .gitignore ├── tox.ini ├── .travis.yml ├── MANIFEST.in ├── README.rst ├── Makefile ├── AUTHORS ├── LICENSE └── setup.py /examples/couchy/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/shorty/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /werkzeug/testsuite/res/test.txt: -------------------------------------------------------------------------------- 1 | FOUND 2 | -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/ie6-2png1txt/text.txt: -------------------------------------------------------------------------------- 1 | ie6 sucks :-/ -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/firefox3-2png1txt/text.txt: -------------------------------------------------------------------------------- 1 | example text -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/opera8-2png1txt/text.txt: -------------------------------------------------------------------------------- 1 | blafasel öäü -------------------------------------------------------------------------------- /docs/logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/logo.pdf -------------------------------------------------------------------------------- /artwork/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/artwork/logo.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/webkit3-2png1txt/text.txt: -------------------------------------------------------------------------------- 1 | this is another text with ümläüts -------------------------------------------------------------------------------- /examples/contrib/README: -------------------------------------------------------------------------------- 1 | This folder includes example applications for werkzeug.contrib 2 | -------------------------------------------------------------------------------- /examples/i18nurls/__init__.py: -------------------------------------------------------------------------------- 1 | from i18nurls.application import Application as make_app 2 | -------------------------------------------------------------------------------- /run-tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from werkzeug.testsuite import main 3 | main() 4 | -------------------------------------------------------------------------------- /docs/_static/contents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/contents.png -------------------------------------------------------------------------------- /docs/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/favicon.ico -------------------------------------------------------------------------------- /docs/_static/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/header.png -------------------------------------------------------------------------------- /docs/_static/shortly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/shortly.png -------------------------------------------------------------------------------- /docs/_static/werkzeug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/werkzeug.png -------------------------------------------------------------------------------- /docs/_static/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/background.png -------------------------------------------------------------------------------- /docs/_static/navigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/navigation.png -------------------------------------------------------------------------------- /werkzeug/debug/shared/less.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/debug/shared/less.png -------------------------------------------------------------------------------- /werkzeug/debug/shared/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/debug/shared/more.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/firefox3-2pnglongtext/text.txt: -------------------------------------------------------------------------------- 1 | --long text 2 | --with boundary 3 | --lookalikes-- -------------------------------------------------------------------------------- /docs/_static/codebackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/codebackground.png -------------------------------------------------------------------------------- /examples/cupoftee/shared/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/examples/cupoftee/shared/up.png -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [egg_info] 2 | tag_build = dev 3 | tag_date = true 4 | 5 | [aliases] 6 | release = egg_info -RDb '' 7 | -------------------------------------------------------------------------------- /werkzeug/debug/shared/source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/debug/shared/source.png -------------------------------------------------------------------------------- /werkzeug/debug/shared/ubuntu.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/debug/shared/ubuntu.ttf -------------------------------------------------------------------------------- /docs/_static/debug-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/debug-screenshot.png -------------------------------------------------------------------------------- /docs/_static/navigation_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/navigation_active.png -------------------------------------------------------------------------------- /docs/_static/shorty-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/docs/_static/shorty-screenshot.png -------------------------------------------------------------------------------- /examples/cupoftee/shared/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/examples/cupoftee/shared/down.png -------------------------------------------------------------------------------- /examples/cupoftee/shared/header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/examples/cupoftee/shared/header.png -------------------------------------------------------------------------------- /examples/cupoftee/shared/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/examples/cupoftee/shared/logo.png -------------------------------------------------------------------------------- /werkzeug/debug/shared/console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/debug/shared/console.png -------------------------------------------------------------------------------- /examples/cupoftee/shared/content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/examples/cupoftee/shared/content.png -------------------------------------------------------------------------------- /examples/cupoftee/shared/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/examples/cupoftee/shared/favicon.ico -------------------------------------------------------------------------------- /docs/latexindex.rst: -------------------------------------------------------------------------------- 1 | :orphan: 2 | 3 | Werkzeug Documentation 4 | ====================== 5 | 6 | .. include:: contents.rst.inc 7 | -------------------------------------------------------------------------------- /docs/_themes/werkzeug/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = basic 3 | stylesheet = werkzeug.css 4 | pygments_style = werkzeug_theme_support.WerkzeugStyle 5 | -------------------------------------------------------------------------------- /docs/contrib/iterio.rst: -------------------------------------------------------------------------------- 1 | ======= 2 | Iter IO 3 | ======= 4 | 5 | .. automodule:: werkzeug.contrib.iterio 6 | 7 | .. autoclass:: IterIO 8 | :members: 9 | -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/ie6-2png1txt/file1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/ie6-2png1txt/file1.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/ie6-2png1txt/file2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/ie6-2png1txt/file2.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/ie6-2png1txt/request.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/ie6-2png1txt/request.txt -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/ie7_full_path_request.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/ie7_full_path_request.txt -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/opera8-2png1txt/file1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/opera8-2png1txt/file1.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/opera8-2png1txt/file2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/opera8-2png1txt/file2.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/webkit3-2png1txt/file1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/webkit3-2png1txt/file1.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/webkit3-2png1txt/file2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/webkit3-2png1txt/file2.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/firefox3-2png1txt/file1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/firefox3-2png1txt/file1.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/firefox3-2png1txt/file2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/firefox3-2png1txt/file2.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/opera8-2png1txt/request.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/opera8-2png1txt/request.txt -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/webkit3-2png1txt/request.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/webkit3-2png1txt/request.txt -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/firefox3-2png1txt/request.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/firefox3-2png1txt/request.txt -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/firefox3-2pnglongtext/file1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/firefox3-2pnglongtext/file1.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/firefox3-2pnglongtext/file2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/firefox3-2pnglongtext/file2.png -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/firefox3-2pnglongtext/request.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simple/werkzeug/master/werkzeug/testsuite/multipart/firefox3-2pnglongtext/request.txt -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | MANIFEST 2 | build 3 | dist 4 | *.egg-info 5 | *.pyc 6 | *.pyo 7 | env 8 | .tox 9 | docs/_build 10 | bench/a 11 | bench/b 12 | .coverage 13 | coverage_out 14 | -------------------------------------------------------------------------------- /docs/_templates/sidebarlogo.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /examples/i18nurls/templates/about.html: -------------------------------------------------------------------------------- 1 |

2 | This is just another page. Maybe you want to head over to the 3 | blog. 4 |

5 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | Documentation Overview 3 | ====================== 4 | 5 | Welcome to the Werkzeug |version| documentation. 6 | 7 | .. include:: contents.rst.inc 8 | -------------------------------------------------------------------------------- /examples/partial/README: -------------------------------------------------------------------------------- 1 | This directory contains modules that have code but that are 2 | not excutable. For example routing definitions to play around 3 | in the python interactive prompt. 4 | -------------------------------------------------------------------------------- /docs/contrib/lint.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | Lint Validation Middleware 3 | ========================== 4 | 5 | .. automodule:: werkzeug.contrib.lint 6 | 7 | .. autoclass:: LintMiddleware 8 | -------------------------------------------------------------------------------- /examples/coolmagic/public/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 20px; 4 | font-family: sans-serif; 5 | font-size: 15px; 6 | } 7 | 8 | h1, a { 9 | color: #a00; 10 | } 11 | -------------------------------------------------------------------------------- /examples/i18nurls/templates/blog.html: -------------------------------------------------------------------------------- 1 |

Blog <% if mode == 'index' %>Index<% else %>Post $post_id<% endif %>

2 |

3 | How about going to the index. 4 |

5 | -------------------------------------------------------------------------------- /docs/contrib/atom.rst: -------------------------------------------------------------------------------- 1 | ================ 2 | Atom Syndication 3 | ================ 4 | 5 | .. automodule:: werkzeug.contrib.atom 6 | 7 | .. autoclass:: AtomFeed 8 | :members: 9 | 10 | .. autoclass:: FeedEntry 11 | -------------------------------------------------------------------------------- /docs/makearchive.py: -------------------------------------------------------------------------------- 1 | import os 2 | import conf 3 | name = "werkzeug-docs-" + conf.version 4 | os.chdir("_build") 5 | os.rename("html", name) 6 | os.system("tar czf %s.tar.gz %s" % (name, name)) 7 | os.rename(name, "html") 8 | -------------------------------------------------------------------------------- /examples/shortly/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}Page Not Found{% endblock %} 3 | {% block body %} 4 |

Page Not Found

5 |

I am sorry, but no such page was found here. 6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | python_files= werkzeug/testsuite/*.py 3 | 4 | [tox] 5 | envlist=py26,py27,pypy,py33 6 | 7 | [testenv] 8 | deps= 9 | greenlet 10 | redis 11 | pymemc 12 | commands= 13 | python ./run-tests.py [] 14 | -------------------------------------------------------------------------------- /examples/couchy/templates/display.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% block body %} 3 |

Shortened URL

4 |

5 | The URL {{ url.target|urlize(40, true) }} 6 | was shortened to {{ url.short_url|urlize }}. 7 |

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /examples/i18nurls/templates/index.html: -------------------------------------------------------------------------------- 1 |

Hello in the i18n URL example application.

2 |

Because I'm too lazy to translate here is just english content.

3 | 6 | -------------------------------------------------------------------------------- /examples/shorty/templates/display.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% block body %} 3 |

Shortened URL

4 |

5 | The URL {{ url.target|urlize(40, true) }} 6 | was shortened to {{ url.short_url|urlize }}. 7 |

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /examples/couchy/README: -------------------------------------------------------------------------------- 1 | couchy README 2 | 3 | Requirements : 4 | - werkzeug : http://werkzeug.pocoo.org 5 | - jinja : http://jinja.pocoo.org 6 | - couchdb 0.72 & above : http://www.couchdb.org 7 | - couchdb-python 0.3 & above : http://code.google.com/p/couchdb-python 8 | 9 | -------------------------------------------------------------------------------- /docs/contrib/profiler.rst: -------------------------------------------------------------------------------- 1 | ========================= 2 | WSGI Application Profiler 3 | ========================= 4 | 5 | .. automodule:: werkzeug.contrib.profiler 6 | 7 | .. autoclass:: MergeStream 8 | 9 | .. autoclass:: ProfilerMiddleware 10 | 11 | .. autofunction:: make_action 12 | -------------------------------------------------------------------------------- /examples/couchy/templates/not_found.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% block body %} 3 |

Page Not Found

4 |

5 | The page you have requested does not exist on this server. What about 6 | adding a new URL? 7 |

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /examples/shorty/templates/not_found.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% block body %} 3 |

Page Not Found

4 |

5 | The page you have requested does not exist on this server. What about 6 | adding a new URL? 7 |

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /docs/_static/werkzeug.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | Werkzeug = {}; 3 | 4 | $(function() { 5 | $('#toc h3').click(function() { 6 | $(this).next().slideToggle(); 7 | $(this).parent().toggleClass('toc-collapsed'); 8 | }).next().hide().parent().addClass('toc-collapsed'); 9 | }); 10 | })(); 11 | -------------------------------------------------------------------------------- /docs/_themes/werkzeug/layout.html: -------------------------------------------------------------------------------- 1 | {%- extends "basic/layout.html" %} 2 | {%- block relbar2 %}{% endblock %} 3 | {%- block footer %} 4 | 8 | {%- endblock %} 9 | -------------------------------------------------------------------------------- /examples/plnt/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | plnt 4 | ~~~~ 5 | 6 | Noun. plnt (plant) -- a planet application that sounds like a herb. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD. 10 | """ 11 | from plnt.webapp import Plnt 12 | -------------------------------------------------------------------------------- /examples/coolmagic/templates/static/about.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% set page_title = 'About the Magic' %} 3 | {% block page_body %} 4 |

5 | Nothing to see. It's just magic. 6 |

7 |

8 | back to the index 9 |

10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /examples/coolmagic/views/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | coolmagic.views 4 | ~~~~~~~~~~~~~~~ 5 | 6 | This module collects and assambles the urls. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | -------------------------------------------------------------------------------- /examples/cupoftee/templates/missingpage.html: -------------------------------------------------------------------------------- 1 |

Page Not Found

2 |

3 | The requested page does not exist on this server. If you expect something 4 | here (for example a server) it probably went away after the last update. 5 |

6 |

7 | go back to the server list. 8 |

9 | -------------------------------------------------------------------------------- /docs/contrib/fixers.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | Fixers 3 | ====== 4 | 5 | .. automodule:: werkzeug.contrib.fixers 6 | 7 | .. autoclass:: CGIRootFix 8 | 9 | .. autoclass:: PathInfoFromRequestUriFix 10 | 11 | .. autoclass:: ProxyFix 12 | :members: 13 | 14 | .. autoclass:: HeaderRewriterFix 15 | 16 | .. autoclass:: InternetExplorerFix 17 | -------------------------------------------------------------------------------- /examples/coolmagic/templates/static/not_found.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% set page_title = 'Missing Magic' %} 3 | {% block page_body %} 4 |

5 | The requested magic really does not exist. Maybe you want 6 | to look for it on the index. 7 |

8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /examples/coolmagic/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | coolmagic 4 | ~~~~~~~~~ 5 | 6 | Package description goes here. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | from coolmagic.application import make_app 12 | -------------------------------------------------------------------------------- /examples/cupoftee/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | cupoftee 4 | ~~~~~~~~ 5 | 6 | Werkzeug powered Teeworlds Server Browser. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | from cupoftee.application import make_app 12 | -------------------------------------------------------------------------------- /examples/shortly/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | {% block title %}{% endblock %} | shortly 3 | 4 |
5 |

shortly

6 |

Shortly is a URL shortener written with Werkzeug 7 | {% block body %}{% endblock %} 8 |

9 | -------------------------------------------------------------------------------- /docs/deployment/index.rst: -------------------------------------------------------------------------------- 1 | .. _deployment: 2 | 3 | ====================== 4 | Application Deployment 5 | ====================== 6 | 7 | This section covers running your application in production on a web 8 | server such as Apache or lighttpd. 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | cgi 14 | mod_wsgi 15 | fastcgi 16 | proxying 17 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/action_show.html: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | ${page.title} 8 | 9 | 10 | ${page.render()} 11 | 12 | 13 | -------------------------------------------------------------------------------- /docs/contrib/index.rst: -------------------------------------------------------------------------------- 1 | =================== 2 | Contributed Modules 3 | =================== 4 | 5 | A lot of useful code contributed by the community is shipped with Werkzeug 6 | as part of the `contrib` module: 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | atom 12 | sessions 13 | securecookie 14 | cache 15 | wrappers 16 | iterio 17 | fixers 18 | profiler 19 | lint 20 | -------------------------------------------------------------------------------- /examples/i18nurls/urls.py: -------------------------------------------------------------------------------- 1 | from werkzeug.routing import Map, Rule, Submount 2 | 3 | map = Map([ 4 | Rule('/', endpoint='#language_select'), 5 | Submount('/', [ 6 | Rule('/', endpoint='index'), 7 | Rule('/about', endpoint='about'), 8 | Rule('/blog/', endpoint='blog/index'), 9 | Rule('/blog/', endpoint='blog/show') 10 | ]) 11 | ]) 12 | -------------------------------------------------------------------------------- /examples/simplewiki/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | simplewiki 4 | ~~~~~~~~~~ 5 | 6 | Very simple wiki application based on Genshi, Werkzeug and SQLAlchemy. 7 | Additionally the creoleparser is used for the wiki markup. 8 | 9 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 10 | :license: BSD. 11 | """ 12 | from simplewiki.application import SimpleWiki 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.6" 4 | - "2.7" 5 | - "pypy" 6 | - "3.3" 7 | 8 | install: 9 | - "python setup.py install" 10 | 11 | script: make test 12 | 13 | branches: 14 | except: 15 | - website 16 | 17 | notifications: 18 | email: false 19 | irc: 20 | channels: 21 | - "chat.freenode.net#pocoo" 22 | on_success: change 23 | on_failure: always 24 | use_notice: true 25 | skip_join: true 26 | -------------------------------------------------------------------------------- /examples/shortly/templates/new_url.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}Create New Short URL{% endblock %} 3 | {% block body %} 4 |

Submit URL

5 |
6 | {% if error %} 7 |

Error: {{ error }} 8 | {% endif %} 9 |

URL: 10 | 11 | 12 |

13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /examples/shortly/templates/short_link_details.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}Details about /{{ short_id }}{% endblock %} 3 | {% block body %} 4 |

/{{ short_id }}

5 |
6 |
Target host: 7 |
{{ link_target|hostname }} 8 |
Full link 9 |
Click count: 11 |
{{ click_count }} 12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /docs/werkzeugext.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Werkzeug Sphinx Extensions 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Provides some more helpers for the werkzeug docs. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | from sphinx.ext.autodoc import cut_lines 12 | 13 | 14 | def setup(app): 15 | app.connect('autodoc-process-docstring', cut_lines(3, 3, what=['module'])) 16 | -------------------------------------------------------------------------------- /examples/coolmagic/templates/layout.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | {{ page_title }} — Cool Magic! 6 | 7 | 8 | 9 |

Cool Magic

10 |

{{ page_title }}

11 | {% block page_body %}{% endblock %} 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/cupoftee/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | cupoftee.utils 4 | ~~~~~~~~~~~~~~ 5 | 6 | Various utilities. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import re 12 | 13 | 14 | _sort_re = re.compile(r'\w+(?u)') 15 | 16 | 17 | def unicodecmp(a, b): 18 | x, y = map(_sort_re.search, [a, b]) 19 | return cmp((x and x.group() or a).lower(), (y and y.group() or b).lower()) 20 | -------------------------------------------------------------------------------- /examples/coolmagic/templates/static/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% set page_title = 'Welcome to the Magic' %} 3 | {% block page_body %} 4 |

5 | Welcome to the magic! This is a bigger example for the 6 | Werkzeug toolkit. And it contains a lot of magic. 7 |

8 |

9 | about the implementation or 10 | click here if you want to see a broken view. 12 |

13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /docs/contrib/wrappers.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Extra Wrappers 3 | ============== 4 | 5 | .. automodule:: werkzeug.contrib.wrappers 6 | 7 | .. autoclass:: JSONRequestMixin 8 | :members: 9 | 10 | .. autoclass:: ProtobufRequestMixin 11 | :members: 12 | 13 | .. autoclass:: RoutingArgsRequestMixin 14 | :members: 15 | 16 | .. autoclass:: ReverseSlashBehaviorRequestMixin 17 | :members: 18 | 19 | .. autoclass:: DynamicCharsetRequestMixin 20 | :members: 21 | 22 | .. autoclass:: DynamicCharsetResponseMixin 23 | :members: 24 | -------------------------------------------------------------------------------- /examples/manage-couchy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from werkzeug import script 3 | 4 | def make_app(): 5 | from couchy.application import Couchy 6 | return Couchy('http://localhost:5984') 7 | 8 | def make_shell(): 9 | from couchy import models, utils 10 | application = make_app() 11 | return locals() 12 | 13 | action_runserver = script.make_runserver(make_app, use_reloader=True) 14 | action_shell = script.make_shell(make_shell) 15 | action_initdb = lambda: make_app().init_database() 16 | 17 | script.run() 18 | -------------------------------------------------------------------------------- /examples/manage-cupoftee.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Manage Cup Of Tee 4 | ~~~~~~~~~~~~~~~~~ 5 | 6 | Manage the cup of tee application. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | from werkzeug import script 12 | 13 | 14 | def make_app(): 15 | from cupoftee import make_app 16 | return make_app('/tmp/cupoftee.db') 17 | action_runserver = script.make_runserver(make_app) 18 | 19 | script.run() 20 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/missing_action.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Action Not Found 6 | 7 | 8 |

Action “${action}” Not Found

9 |

The requested action does not exist.

10 |

Try to access the same URL without parameters.

11 | 12 | 13 | -------------------------------------------------------------------------------- /werkzeug/testsuite/contrib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.testsuite.contrib 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Tests the contrib modules. 7 | 8 | :copyright: (c) 2013 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import unittest 12 | from werkzeug.testsuite import iter_suites 13 | 14 | 15 | def suite(): 16 | suite = unittest.TestSuite() 17 | for other_suite in iter_suites(__name__): 18 | suite.addTest(other_suite) 19 | return suite 20 | -------------------------------------------------------------------------------- /docs/middlewares.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | Middlewares 3 | =========== 4 | 5 | .. module:: werkzeug.wsgi 6 | 7 | Middlewares wrap applications to dispatch between then or provide 8 | additional request handling. Additionally to the middlewares documented 9 | here, there is also the :class:`DebuggedApplication` class that is 10 | implemented as a WSGI middleware. 11 | 12 | .. autoclass:: SharedDataMiddleware 13 | :members: is_allowed 14 | 15 | .. autoclass:: DispatcherMiddleware 16 | 17 | Also there's the … 18 | 19 | .. autofunction:: werkzeug._internal._easteregg 20 | -------------------------------------------------------------------------------- /examples/coolmagic/helpers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | coolmagic.helpers 4 | ~~~~~~~~~~~~~~~~~ 5 | 6 | The star-import module for all views. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | from coolmagic.utils import Response, TemplateResponse, ThreadedRequest, \ 12 | export, url_for, redirect 13 | from werkzeug.utils import escape 14 | 15 | 16 | #: a thread local proxy request object 17 | request = ThreadedRequest() 18 | del ThreadedRequest 19 | -------------------------------------------------------------------------------- /examples/manage-i18nurls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Manage i18nurls 5 | ~~~~~~~~~~~~~~~ 6 | 7 | Manage the i18n url example application. 8 | 9 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | import os 13 | from i18nurls import make_app 14 | from werkzeug import script 15 | 16 | action_runserver = script.make_runserver(make_app) 17 | action_shell = script.make_shell(lambda: {}) 18 | 19 | if __name__ == '__main__': 20 | script.run() 21 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include Makefile CHANGES LICENSE AUTHORS 2 | recursive-include werkzeug/debug/shared * 3 | recursive-include werkzeug/debug/templates * 4 | recursive-include werkzeug/testsuite/res * 5 | recursive-include werkzeug/testsuite/multipart * 6 | recursive-include tests * 7 | recursive-include docs * 8 | recursive-include examples * 9 | recursive-exclude docs *.pyc 10 | recursive-exclude docs *.pyo 11 | recursive-exclude tests *.pyc 12 | recursive-exclude tests *.pyo 13 | recursive-exclude examples *.pyc 14 | recursive-exclude examples *.pyo 15 | recursive-include artwork * 16 | prune docs/_build 17 | -------------------------------------------------------------------------------- /examples/manage-coolmagic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Manage Coolmagic 5 | ~~~~~~~~~~~~~~~~ 6 | 7 | Manage the coolmagic example application. 8 | 9 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | import os 13 | from coolmagic import make_app 14 | from werkzeug import script 15 | 16 | action_runserver = script.make_runserver(make_app, use_reloader=True) 17 | action_shell = script.make_shell(lambda: {}) 18 | 19 | if __name__ == '__main__': 20 | script.run() 21 | -------------------------------------------------------------------------------- /examples/couchy/templates/layout.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Shorty 6 | 7 | 8 | 9 |

Shorty

10 |
{% block body %}{% endblock %}
11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/shorty/templates/layout.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Shorty 6 | 7 | 8 | 9 |

Shorty

10 |
{% block body %}{% endblock %}
11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/manage-shorty.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import tempfile 4 | from werkzeug import script 5 | 6 | def make_app(): 7 | from shorty.application import Shorty 8 | filename = os.path.join(tempfile.gettempdir(), "shorty.db") 9 | return Shorty('sqlite:///{0}'.format(filename)) 10 | 11 | def make_shell(): 12 | from shorty import models, utils 13 | application = make_app() 14 | return locals() 15 | 16 | action_runserver = script.make_runserver(make_app, use_reloader=True) 17 | action_shell = script.make_shell(make_shell) 18 | action_initdb = lambda: make_app().init_database() 19 | 20 | script.run() 21 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/page_index.html: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | Index 8 | 9 | 10 |

Index

11 | 12 |

${letter}

13 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/i18nurls/templates/layout.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | $title | Example Application 6 | 7 | 8 |

Example Application

9 |

10 | Request Language: $req.language 11 |

12 | $body 13 |
14 |

This page in other languages: 15 |

    16 | <% for lng in ['en', 'de', 'fr'] %> 17 |
  • $lng
  • 18 | <% endfor %> 19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/_themes/werkzeug/relations.html: -------------------------------------------------------------------------------- 1 |

Related Topics

2 | 20 | -------------------------------------------------------------------------------- /docs/contrib/cache.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Cache 3 | ===== 4 | 5 | .. automodule:: werkzeug.contrib.cache 6 | 7 | 8 | Cache System API 9 | ================ 10 | 11 | .. autoclass:: BaseCache 12 | :members: 13 | 14 | 15 | Cache Systems 16 | ============= 17 | 18 | .. autoclass:: NullCache 19 | 20 | .. autoclass:: SimpleCache 21 | 22 | .. autoclass:: MemcachedCache 23 | 24 | .. class:: GAEMemcachedCache 25 | 26 | This class is deprecated in favour of :class:`MemcachedCache` which 27 | now supports Google Appengine as well. 28 | 29 | .. versionchanged:: 0.8 30 | Deprecated in favour of :class:`MemcachedCache`. 31 | 32 | .. autoclass:: RedisCache 33 | 34 | .. autoclass:: FileSystemCache 35 | -------------------------------------------------------------------------------- /examples/partial/complex_routing.py: -------------------------------------------------------------------------------- 1 | from werkzeug.routing import Map, Rule, Subdomain, Submount, EndpointPrefix 2 | 3 | m = Map([ 4 | # Static URLs 5 | EndpointPrefix('static/', [ 6 | Rule('/', endpoint='index'), 7 | Rule('/about', endpoint='about'), 8 | Rule('/help', endpoint='help'), 9 | ]), 10 | # Knowledge Base 11 | Subdomain('kb', [EndpointPrefix('kb/', [ 12 | Rule('/', endpoint='index'), 13 | Submount('/browse', [ 14 | Rule('/', endpoint='browse'), 15 | Rule('//', defaults={'page': 1}, endpoint='browse'), 16 | Rule('//', endpoint='browse') 17 | ]) 18 | ])]) 19 | ]) 20 | -------------------------------------------------------------------------------- /examples/shorty/templates/new.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% block body %} 3 |

Create a Shorty-URL!

4 | {% if error %}
{{ error }}
{% endif %} 5 |
6 |

Enter the URL you want to shorten

7 |

8 |

Optionally you can give the URL a memorable name

9 |

{# 10 | #}

11 |

12 |

13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /werkzeug/contrib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.contrib 4 | ~~~~~~~~~~~~~~~~ 5 | 6 | Contains user-submitted code that other users may find useful, but which 7 | is not part of the Werkzeug core. Anyone can write code for inclusion in 8 | the `contrib` package. All modules in this package are distributed as an 9 | add-on library and thus are not part of Werkzeug itself. 10 | 11 | This file itself is mostly for informational purposes and to tell the 12 | Python interpreter that `contrib` is a package. 13 | 14 | :copyright: (c) 2013 by the Werkzeug Team, see AUTHORS for more details. 15 | :license: BSD, see LICENSE for more details. 16 | """ 17 | -------------------------------------------------------------------------------- /examples/couchy/templates/new.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% block body %} 3 |

Create a Shorty-URL!

4 | {% if error %}
{{ error }}
{% endif -%} 5 |
6 |

Enter the URL you want to shorten

7 |

8 |

Optionally you can give the URL a memorable name

9 |

{# 10 | #}

11 |

12 |

13 |
14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /examples/webpylike/example.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Example application based on weblikepy 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | The application from th web.py tutorial. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD. 10 | """ 11 | from webpylike import WebPyApp, View, Response 12 | 13 | 14 | urls = ( 15 | '/', 'index', 16 | '/about', 'about' 17 | ) 18 | 19 | 20 | class index(View): 21 | def GET(self): 22 | return Response('Hello World') 23 | 24 | 25 | class about(View): 26 | def GET(self): 27 | return Response('This is the about page') 28 | 29 | 30 | app = WebPyApp(urls, globals()) 31 | -------------------------------------------------------------------------------- /docs/_templates/sidebarintro.html: -------------------------------------------------------------------------------- 1 |

About Werkzeug

2 |

3 | Werkzeug is a WSGI utility library. It can serve as the basis for a 4 | custom framework. 5 |

6 |

Other Formats

7 |

8 | You can download the documentation in other formats as well: 9 |

10 | 14 |

Useful Links

15 | 20 | -------------------------------------------------------------------------------- /examples/i18nurls/views.py: -------------------------------------------------------------------------------- 1 | from i18nurls.application import TemplateResponse, Response, expose 2 | 3 | 4 | @expose('index') 5 | def index(req): 6 | return TemplateResponse('index.html', title='Index') 7 | 8 | @expose('about') 9 | def about(req): 10 | return TemplateResponse('about.html', title='About') 11 | 12 | @expose('blog/index') 13 | def blog_index(req): 14 | return TemplateResponse('blog.html', title='Blog Index', mode='index') 15 | 16 | @expose('blog/show') 17 | def blog_show(req, post_id): 18 | return TemplateResponse('blog.html', title='Blog Post #%d' % post_id, 19 | post_id=post_id, mode='show') 20 | 21 | def page_not_found(req): 22 | return Response('

Page Not Found

', mimetype='text/html') 23 | -------------------------------------------------------------------------------- /examples/plnt/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |

About Plnt

5 |

6 | Plnt is a small example application written using the 7 | Werkzeug WSGI toolkit, 8 | the Jinja template language, 9 | the SQLAlchemy database abstraction 10 | layer and ORM and last but not least the awesome 11 | feedparser library. 12 |

13 |

14 | It's one of the example applications developed to show some of the 15 | features werkzeug provides and could be the base of a real planet 16 | software. 17 |

18 |
19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/macros.xml: -------------------------------------------------------------------------------- 1 |
3 | 4 | 5 | 16 | 17 | 18 |
19 | -------------------------------------------------------------------------------- /examples/plnt/templates/layout.html: -------------------------------------------------------------------------------- 1 | 3 | Plnt Planet 4 | 5 | 6 |
7 |

Plnt Planet

8 |
This is the Plnt Planet Werkzeug Example Application
9 |
10 | 11 | 15 | 16 |
17 | {% block body %}{% endblock %} 18 |
19 | 20 | 24 | -------------------------------------------------------------------------------- /examples/couchy/templates/list.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% block body %} 3 |

List of URLs

4 |
    5 | {%- for url in pagination.entries %} 6 |
  • {{ url.id|e }} » 7 | {{ url.target|urlize(38, true) }}
  • 8 | {%- else %} 9 |
  • no URLs shortened yet
  • 10 | {%- endfor %} 11 |
12 | 19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /examples/shorty/templates/list.html: -------------------------------------------------------------------------------- 1 | {% extends 'layout.html' %} 2 | {% block body %} 3 |

List of URLs

4 |
    5 | {%- for url in pagination.entries %} 6 |
  • {{ url.uid|e }} » 7 | {{ url.target|urlize(38, true) }}
  • 8 | {%- else %} 9 |
  • no URLs shortened yet
  • 10 | {%- endfor %} 11 |
12 | 19 | {% endblock %} 20 | -------------------------------------------------------------------------------- /examples/cupoftee/templates/layout.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Teeworlds Server Browser 6 | 7 | 8 | 9 | 10 |

Teeworlds Server Browser

11 |
12 | ${body} 13 |
14 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/coolmagic/views/static.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | coolmagic.views.static 4 | ~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Some static views. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | from coolmagic.helpers import * 12 | 13 | 14 | @export('/', template='static/index.html') 15 | def index(): 16 | pass 17 | 18 | 19 | @export('/about', template='static/about.html') 20 | def about(): 21 | pass 22 | 23 | 24 | @export('/broken') 25 | def broken(): 26 | foo = request.args.get('foo', 42) 27 | raise RuntimeError('that\'s really broken') 28 | 29 | 30 | @export(None, template='static/not_found.html') 31 | def not_found(): 32 | """ 33 | This function is always executed if an url does not 34 | match or a `NotFound` exception is raised. 35 | """ 36 | pass 37 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/page_missing.html: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | Page Not Found 8 | 9 | 10 |

Page Not Found

11 |

The page you requested does not exist.

12 |

13 | It also could be that there is no such revision of that page. 14 |

15 |

16 | Feel free to create such a page. 18 |

19 |

20 | Although this page does not exist by now you cannot create it because 21 | the system protected the page name for future use. 22 |

23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/manage-webpylike.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Manage web.py like application 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | A small example application that is built after the web.py tutorial. We 8 | even use regular expression based dispatching. The original code can be 9 | found on the `webpy.org webpage`__ in the tutorial section. 10 | 11 | __ http://webpy.org/tutorial2.en 12 | 13 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 14 | :license: BSD, see LICENSE for more details. 15 | """ 16 | import os 17 | import sys 18 | sys.path.append(os.path.join(os.path.dirname(__file__), 'webpylike')) 19 | from example import app 20 | from werkzeug import script 21 | 22 | action_runserver = script.make_runserver(lambda: app) 23 | action_shell = script.make_shell(lambda: {}) 24 | 25 | if __name__ == '__main__': 26 | script.run() 27 | -------------------------------------------------------------------------------- /examples/cupoftee/templates/server.html: -------------------------------------------------------------------------------- 1 |

$escape(server.name)

2 |

3 | Take me back to the server list. 4 |

5 |
6 |
Map
7 |
$escape(server.map)
8 |
Gametype
9 |
$server.gametype
10 |
Number of players
11 |
$server.player_count
12 |
Server version
13 |
$server.version
14 |
Maximum number of players
15 |
$server.max_players
16 | <% if server.progression >= 0 %> 17 |
Game progression
18 |
$server.progression%
19 | <% endif %> 20 |
21 | <% if server.players %> 22 |

Players

23 |
    24 | <% for player in server.players %> 25 |
  • $escape(player.name) 26 | ($player.score)
  • 27 | <% endfor %> 28 |
29 | <% endif %> 30 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Werkzeug 2 | ======== 3 | 4 | Werkzeug started as simple collection of various utilities for WSGI 5 | applications and has become one of the most advanced WSGI utility 6 | modules. It includes a powerful debugger, full-featured request and 7 | response objects, HTTP utilities to handle entity tags, cache control 8 | headers, HTTP dates, cookie handling, file uploads, a powerful URL 9 | routing system and a bunch of community-contributed addon modules. 10 | 11 | Werkzeug is unicode aware and doesn't enforce a specific template 12 | engine, database adapter or anything else. It doesn't even enforce 13 | a specific way of handling requests and leaves all that up to the 14 | developer. It's most useful for end user applications which should work 15 | on as many server environments as possible (such as blogs, wikis, 16 | bulletin boards, etc.). 17 | 18 | Details and example applications are available on the 19 | `Werkzeug website `_. 20 | -------------------------------------------------------------------------------- /examples/shortly/static/style.css: -------------------------------------------------------------------------------- 1 | body { background: #E8EFF0; margin: 0; padding: 0; } 2 | body, input { font-family: 'Helvetica Neue', Arial, 3 | sans-serif; font-weight: 300; font-size: 18px; } 4 | .box { width: 500px; margin: 60px auto; padding: 20px; 5 | background: white; box-shadow: 0 1px 4px #BED1D4; 6 | border-radius: 2px; } 7 | a { color: #11557C; } 8 | h1, h2 { margin: 0; color: #11557C; } 9 | h1 a { text-decoration: none; } 10 | h2 { font-weight: normal; font-size: 24px; } 11 | .tagline { color: #888; font-style: italic; margin: 0 0 20px 0; } 12 | .link div { overflow: auto; font-size: 0.8em; white-space: pre; 13 | padding: 4px 10px; margin: 5px 0; background: #E5EAF1; } 14 | dt { font-weight: normal; } 15 | .error { background: #E8EFF0; padding: 3px 8px; color: #11557C; 16 | font-size: 0.9em; border-radius: 2px; } 17 | .urlinput { width: 300px; } 18 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/recent_changes.html: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | Recent Changes 8 | 9 | 10 |

Recent Changes

11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 |
DatePageChange Note
${format_datetime(entry.timestamp)}${entry.title}${entry.change_note}
24 | ${render_pagination(pagination)} 25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/action_diff.html: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | View Diff 8 | 9 | 10 | 11 |

Diff for “${page.title}

12 |

13 | Below you can see the differences between the revision from 14 | ${format_datetime(old_revision.timestamp)} and the 16 | revision from ${format_datetime(new_revision.timestamp)} in unified 18 | diff format. 19 |

20 |
${diff}
21 |
22 | 23 |

Cannot Display Diff

24 |

${error}

25 |
26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/plnt/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | {% for day in days %} 4 |
5 |

{{ day.date.strftime('%d %B %Y') }}

6 | {%- for entry in day.entries %} 7 |
8 |

{{ entry.title }}

9 |

by {{ entry.blog.name|e }} 10 | at {{ entry.pub_date.strftime('%H:%m') }}

11 |
{{ entry.text }}
12 |
13 | {%- endfor %} 14 |
15 | {%- endfor %} 16 | 17 | {% if pagination.pages > 1 %} 18 | 25 | {% endif %} 26 | {% endblock %} 27 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/action_edit.html: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | ${new and 'Create' or 'Edit'} Page 9 | 10 | 11 |

${new and 'Create' or 'Edit'} “${page.title or page_name}”

12 |

13 | You can now ${new and 'create' or 'modify'} the page contents. To 14 | format your text you can use creole markup. 15 |

16 |

${error}

17 |
18 |

19 |
20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /examples/cupoftee/templates/search.html: -------------------------------------------------------------------------------- 1 |

Nick Search

2 | <% if not user %> 3 |
4 |

5 | You have to enter a nickname. 6 |

7 |

8 | 9 | 10 |

11 |

12 | Take me back to the server list. 13 |

14 |
15 | <% else %> 16 | <% if results %> 17 |

18 | The nickname "$escape(user)" is currently playing on the 19 | following ${len(results) == 1 and 'server' or 'servers'}: 20 |

21 | 26 | <% else %> 27 |

28 | The nickname "$escape(user)" is currently not playing. 29 |

30 | <% endif %> 31 |

32 | You can bookmark this link 33 | to search for "$escape(user)" quickly or return 34 | to the server list. 35 |

36 | <% endif %> 37 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Werkzeug Makefile 3 | # ~~~~~~~~~~~~~~~~~ 4 | # 5 | # Shortcuts for various tasks. 6 | # 7 | # :copyright: (c) 2008 by the Werkzeug Team, see AUTHORS for more details. 8 | # :license: BSD, see LICENSE for more details. 9 | # 10 | 11 | documentation: 12 | @(cd docs; make html) 13 | 14 | release: 15 | python scripts/make-release.py 16 | 17 | test: 18 | python run-tests.py 19 | 20 | tox-test: 21 | tox 22 | 23 | coverage: 24 | @(nosetests $(TEST_OPTIONS) --with-coverage --cover-package=werkzeug --cover-html --cover-html-dir=coverage_out $(TESTS)) 25 | 26 | doctest: 27 | @(cd docs; sphinx-build -b doctest . _build/doctest) 28 | 29 | upload-docs: 30 | $(MAKE) -C docs html dirhtml latex 31 | $(MAKE) -C docs/_build/latex all-pdf 32 | cd docs/_build/; mv html werkzeug-docs; zip -r werkzeug-docs.zip werkzeug-docs; mv werkzeug-docs html 33 | rsync -a docs/_build/dirhtml/ pocoo.org:/var/www/werkzeug.pocoo.org/docs/ 34 | rsync -a docs/_build/latex/Werkzeug.pdf pocoo.org:/var/www/werkzeug.pocoo.org/docs/werkzeug-docs.pdf 35 | rsync -a docs/_build/werkzeug-docs.zip pocoo.org:/var/www/werkzeug.pocoo.org/docs/werkzeug-docs.zip 36 | -------------------------------------------------------------------------------- /examples/shorty/models.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from sqlalchemy import Table, Column, String, Boolean, DateTime 3 | from sqlalchemy.orm import mapper 4 | from shorty.utils import session, metadata, url_for, get_random_uid 5 | 6 | url_table = Table('urls', metadata, 7 | Column('uid', String(140), primary_key=True), 8 | Column('target', String(500)), 9 | Column('added', DateTime), 10 | Column('public', Boolean) 11 | ) 12 | 13 | class URL(object): 14 | query = session.query_property() 15 | 16 | def __init__(self, target, public=True, uid=None, added=None): 17 | self.target = target 18 | self.public = public 19 | self.added = added or datetime.utcnow() 20 | if not uid: 21 | while 1: 22 | uid = get_random_uid() 23 | if not URL.query.get(uid): 24 | break 25 | self.uid = uid 26 | session.add(self) 27 | 28 | @property 29 | def short_url(self): 30 | return url_for('link', uid=self.uid, _external=True) 31 | 32 | def __repr__(self): 33 | return '' % self.uid 34 | 35 | mapper(URL, url_table) 36 | -------------------------------------------------------------------------------- /docs/_themes/README: -------------------------------------------------------------------------------- 1 | Flask Sphinx Styles 2 | =================== 3 | 4 | This repository contains sphinx styles for Flask and Flask related 5 | projects. To use this style in your Sphinx documentation, follow 6 | this guide: 7 | 8 | 1. put this folder as _themes into your docs folder. Alternatively 9 | you can also use git submodules to check out the contents there. 10 | 2. add this to your conf.py: 11 | 12 | sys.path.append(os.path.abspath('_themes')) 13 | html_theme_path = ['_themes'] 14 | html_theme = 'flask' 15 | 16 | The following themes exist: 17 | 18 | - 'flask' - the standard flask documentation theme for large 19 | projects 20 | - 'flask_small' - small one-page theme. Intended to be used by 21 | very small addon libraries for flask. 22 | 23 | The following options exist for the flask_small theme: 24 | 25 | [options] 26 | index_logo = '' filename of a picture in _static 27 | to be used as replacement for the 28 | h1 in the index.rst file. 29 | index_logo_height = 120px height of the index logo 30 | github_fork = '' repository name on github for the 31 | "fork me" badge 32 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/action_revert.html: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | Revert Old Revision 8 | 9 | 10 | 11 |

Revert Old Revision of “${page.title}

12 |

13 | If you want to restore the old revision from 14 | ${format_datetime(old_revision.timestamp)} enter your change 16 | note and click “Revert”. 17 |

18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 |
26 | 27 |

Cannot Revert

28 |

${error}

29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/contrib/sessions.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Sessions 3 | ======== 4 | 5 | .. automodule:: werkzeug.contrib.sessions 6 | 7 | .. testsetup:: 8 | 9 | from werkzeug.contrib.sessions import * 10 | 11 | Reference 12 | ========= 13 | 14 | .. autoclass:: Session 15 | 16 | .. attribute:: sid 17 | 18 | The session ID as string. 19 | 20 | .. attribute:: new 21 | 22 | `True` is the cookie was newly created, otherwise `False` 23 | 24 | .. attribute:: modified 25 | 26 | Whenever an item on the cookie is set, this attribute is set to `True`. 27 | However this does not track modifications inside mutable objects 28 | in the session: 29 | 30 | >>> c = Session({}, sid='deadbeefbabe2c00ffee') 31 | >>> c["foo"] = [1, 2, 3] 32 | >>> c.modified 33 | True 34 | >>> c.modified = False 35 | >>> c["foo"].append(4) 36 | >>> c.modified 37 | False 38 | 39 | In that situation it has to be set to `modified` by hand so that 40 | :attr:`should_save` can pick it up. 41 | 42 | .. autoattribute:: should_save 43 | 44 | .. autoclass:: SessionStore 45 | :members: 46 | 47 | .. autoclass:: FilesystemSessionStore 48 | :members: list 49 | 50 | .. autoclass:: SessionMiddleware 51 | -------------------------------------------------------------------------------- /werkzeug/testsuite/compat.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.testsuite.compat 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Ensure that old stuff does not break on update. 7 | 8 | :copyright: (c) 2013 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import unittest 12 | import warnings 13 | from werkzeug.testsuite import WerkzeugTestCase 14 | 15 | from werkzeug.wrappers import Response 16 | from werkzeug.test import create_environ 17 | 18 | 19 | class CompatTestCase(WerkzeugTestCase): 20 | 21 | def test_old_imports(self): 22 | from werkzeug.utils import Headers, MultiDict, CombinedMultiDict, \ 23 | Headers, EnvironHeaders 24 | from werkzeug.http import Accept, MIMEAccept, CharsetAccept, \ 25 | LanguageAccept, ETags, HeaderSet, WWWAuthenticate, \ 26 | Authorization 27 | 28 | def test_exposed_werkzeug_mod(self): 29 | import werkzeug 30 | for key in werkzeug.__all__: 31 | # deprecated, skip it 32 | if key in ('templates', 'Template'): 33 | continue 34 | getattr(werkzeug, key) 35 | 36 | 37 | def suite(): 38 | suite = unittest.TestSuite() 39 | suite.addTest(unittest.makeSuite(CompatTestCase)) 40 | return suite 41 | -------------------------------------------------------------------------------- /examples/plnt/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | plnt.views 4 | ~~~~~~~~~~ 5 | 6 | Display the aggregated feeds. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD. 10 | """ 11 | from datetime import datetime, date 12 | from plnt.database import Blog, Entry 13 | from plnt.utils import Pagination, expose, render_template 14 | 15 | 16 | #: number of items per page 17 | PER_PAGE = 30 18 | 19 | 20 | @expose('/', defaults={'page': 1}) 21 | @expose('/page/') 22 | def index(request, page): 23 | """Show the index page or any an offset of it.""" 24 | days = [] 25 | days_found = set() 26 | query = Entry.query.order_by(Entry.pub_date.desc()) 27 | pagination = Pagination(query, PER_PAGE, page, 'index') 28 | for entry in pagination.entries: 29 | day = date(*entry.pub_date.timetuple()[:3]) 30 | if day not in days_found: 31 | days_found.add(day) 32 | days.append({'date': day, 'entries': []}) 33 | days[-1]['entries'].append(entry) 34 | return render_template('index.html', days=days, pagination=pagination) 35 | 36 | 37 | @expose('/about') 38 | def about(request): 39 | """Show the about page, so that we have another view func ;-)""" 40 | return render_template('about.html') 41 | -------------------------------------------------------------------------------- /examples/manage-simplewiki.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Manage SimpleWiki 5 | ~~~~~~~~~~~~~~~~~ 6 | 7 | This script provides some basic commands to debug and test SimpleWiki. 8 | 9 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | import os 13 | from werkzeug import script 14 | 15 | 16 | def make_wiki(): 17 | """Helper function that creates a new wiki instance.""" 18 | from simplewiki import SimpleWiki 19 | database_uri = os.environ.get('SIMPLEWIKI_DATABASE_URI') 20 | return SimpleWiki(database_uri or 'sqlite:////tmp/simplewiki.db') 21 | 22 | 23 | def shell_init_func(): 24 | """ 25 | Called on shell initialization. Adds useful stuff to the namespace. 26 | """ 27 | from simplewiki import database 28 | wiki = make_wiki() 29 | wiki.bind_to_context() 30 | return { 31 | 'wiki': wiki, 32 | 'db': database 33 | } 34 | 35 | 36 | action_runserver = script.make_runserver(make_wiki, use_reloader=True) 37 | action_shell = script.make_shell(shell_init_func) 38 | 39 | 40 | def action_initdb(): 41 | """Initialize the database""" 42 | make_wiki().init_database() 43 | 44 | 45 | if __name__ == '__main__': 46 | script.run() 47 | -------------------------------------------------------------------------------- /examples/contrib/sessions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from werkzeug.serving import run_simple 4 | from werkzeug.contrib.sessions import SessionStore, SessionMiddleware 5 | 6 | 7 | class MemorySessionStore(SessionStore): 8 | 9 | def __init__(self, session_class=None): 10 | SessionStore.__init__(self, session_class=None) 11 | self.sessions = {} 12 | 13 | def save(self, session): 14 | self.sessions[session.sid] = session 15 | 16 | def delete(self, session): 17 | self.sessions.pop(session.id, None) 18 | 19 | def get(self, sid): 20 | if not self.is_valid_key(sid) or sid not in self.sessions: 21 | return self.new() 22 | return self.session_class(self.sessions[sid], sid, False) 23 | 24 | 25 | def application(environ, start_response): 26 | start_response('200 OK', [('Content-Type', 'text/html')]) 27 | session = environ['werkzeug.session'] 28 | yield 'Session Example

Session Example

' 29 | if session.new: 30 | session['visit_count'] = 0 31 | yield '

This is a new session.

' 32 | session['visit_count'] += 1 33 | yield '

You visited this page %d times.

' % session['visit_count'] 34 | 35 | 36 | def make_app(): 37 | return SessionMiddleware(application, MemorySessionStore()) 38 | 39 | 40 | if __name__ == '__main__': 41 | run_simple('localhost', 5000, make_app()) 42 | -------------------------------------------------------------------------------- /examples/couchy/models.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from couchdb.schema import Document, TextField, BooleanField, DateTimeField 3 | from couchy.utils import url_for, get_random_uid 4 | 5 | 6 | class URL(Document): 7 | target = TextField() 8 | public = BooleanField() 9 | added = DateTimeField(default=datetime.utcnow()) 10 | shorty_id = TextField(default=None) 11 | db = None 12 | 13 | @classmethod 14 | def load(self, id): 15 | return super(URL, self).load(URL.db, id) 16 | 17 | @classmethod 18 | def query(self, code): 19 | return URL.db.query(code) 20 | 21 | def store(self): 22 | if getattr(self._data, 'id', None) is None: 23 | new_id = self.shorty_id if self.shorty_id else None 24 | while 1: 25 | id = new_id if new_id else get_random_uid() 26 | docid = None 27 | try: 28 | docid = URL.db.resource.put(content=self._data, path='/%s/' % str(id))['id'] 29 | except: 30 | continue 31 | if docid: 32 | break 33 | self._data = URL.db.get(docid) 34 | else: 35 | super(URL, self).store(URL.db) 36 | return self 37 | 38 | @property 39 | def short_url(self): 40 | return url_for('link', uid=self.id, _external=True) 41 | 42 | def __repr__(self): 43 | return '' % self.id 44 | -------------------------------------------------------------------------------- /examples/upload.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Simple Upload Application 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | All uploaded files are directly send back to the client. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | from werkzeug.serving import run_simple 12 | from werkzeug.wrappers import BaseRequest, BaseResponse 13 | from werkzeug.wsgi import wrap_file 14 | 15 | 16 | def view_file(req): 17 | if not 'uploaded_file' in req.files: 18 | return BaseResponse('no file uploaded') 19 | f = req.files['uploaded_file'] 20 | return BaseResponse(wrap_file(req.environ, f), mimetype=f.content_type, 21 | direct_passthrough=True) 22 | 23 | 24 | def upload_file(req): 25 | return BaseResponse(''' 26 |

Upload File

27 |
28 | 29 | 30 |
31 | ''', mimetype='text/html') 32 | 33 | 34 | def application(environ, start_response): 35 | req = BaseRequest(environ) 36 | if req.method == 'POST': 37 | resp = view_file(req) 38 | else: 39 | resp = upload_file(req) 40 | return resp(environ, start_response) 41 | 42 | 43 | if __name__ == '__main__': 44 | run_simple('localhost', 5000, application, use_debugger=True) 45 | -------------------------------------------------------------------------------- /werkzeug/contrib/limiter.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.contrib.limiter 4 | ~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | A middleware that limits incoming data. This works around problems with 7 | Trac_ or Django_ because those directly stream into the memory. 8 | 9 | .. _Trac: http://trac.edgewall.org/ 10 | .. _Django: http://www.djangoproject.com/ 11 | 12 | :copyright: (c) 2013 by the Werkzeug Team, see AUTHORS for more details. 13 | :license: BSD, see LICENSE for more details. 14 | """ 15 | from warnings import warn 16 | 17 | from werkzeug.wsgi import LimitedStream 18 | 19 | 20 | class StreamLimitMiddleware(object): 21 | """Limits the input stream to a given number of bytes. This is useful if 22 | you have a WSGI application that reads form data into memory (django for 23 | example) and you don't want users to harm the server by uploading tons of 24 | data. 25 | 26 | Default is 10MB 27 | 28 | .. versionchanged:: 0.9 29 | Deprecated middleware. 30 | """ 31 | 32 | def __init__(self, app, maximum_size=1024 * 1024 * 10): 33 | warn(DeprecationWarning('This middleware is deprecated')) 34 | self.app = app 35 | self.maximum_size = maximum_size 36 | 37 | def __call__(self, environ, start_response): 38 | limit = min(self.maximum_size, int(environ.get('CONTENT_LENGTH') or 0)) 39 | environ['wsgi.input'] = LimitedStream(environ['wsgi.input'], limit) 40 | return self.app(environ, start_response) 41 | -------------------------------------------------------------------------------- /docs/deployment/cgi.rst: -------------------------------------------------------------------------------- 1 | === 2 | CGI 3 | === 4 | 5 | If all other deployment methods do not work, CGI will work for sure. CGI 6 | is supported by all major servers but usually has a less-than-optimal 7 | performance. 8 | 9 | This is also the way you can use a Werkzeug application on Google's 10 | `AppEngine`_, there however the execution does happen in a CGI-like 11 | environment. The application's performance is unaffected because of that. 12 | 13 | .. _AppEngine: http://code.google.com/appengine/ 14 | 15 | Creating a `.cgi` file 16 | ====================== 17 | 18 | First you need to create the CGI application file. Let's call it 19 | `yourapplication.cgi`:: 20 | 21 | #!/usr/bin/python 22 | from wsgiref.handlers import CGIHandler 23 | from yourapplication import make_app 24 | 25 | application = make_app() 26 | CGIHandler().run(application) 27 | 28 | If you're running Python 2.4 you will need the :mod:`wsgiref` package. Python 29 | 2.5 and higher ship this as part of the standard library. 30 | 31 | Server Setup 32 | ============ 33 | 34 | Usually there are two ways to configure the server. Either just copy the 35 | `.cgi` into a `cgi-bin` (and use `mod_rerwite` or something similar to 36 | rewrite the URL) or let the server point to the file directly. 37 | 38 | In Apache for example you can put a like like this into the config: 39 | 40 | .. sourcecode:: apache 41 | 42 | ScriptAlias /app /path/to/the/application.cgi 43 | 44 | For more information consult the documentation of your webserver. 45 | -------------------------------------------------------------------------------- /examples/contrib/securecookie.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Secure Cookie Example 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Stores session on the client. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD. 10 | """ 11 | from time import asctime 12 | from werkzeug.serving import run_simple 13 | from werkzeug.wrappers import BaseRequest, BaseResponse 14 | from werkzeug.contrib.securecookie import SecureCookie 15 | 16 | SECRET_KEY = 'V\x8a$m\xda\xe9\xc3\x0f|f\x88\xbccj>\x8bI^3+' 17 | 18 | 19 | class Request(BaseRequest): 20 | 21 | def __init__(self, environ): 22 | BaseRequest.__init__(self, environ) 23 | self.session = SecureCookie.load_cookie(self, secret_key=SECRET_KEY) 24 | 25 | 26 | def index(request): 27 | return 'Set the Time or Get the time' 28 | 29 | 30 | def get_time(request): 31 | return 'Time: %s' % request.session.get('time', 'not set') 32 | 33 | 34 | def set_time(request): 35 | request.session['time'] = time = asctime() 36 | return 'Time set to %s' % time 37 | 38 | 39 | def application(environ, start_response): 40 | request = Request(environ) 41 | response = BaseResponse({ 42 | 'get': get_time, 43 | 'set': set_time 44 | }.get(request.path.strip('/'), index)(request), mimetype='text/html') 45 | request.session.save_cookie(response) 46 | return response(environ, start_response) 47 | 48 | 49 | if __name__ == '__main__': 50 | run_simple('localhost', 5000, application) 51 | -------------------------------------------------------------------------------- /examples/simplewiki/specialpages.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | simplewiki.specialpages 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | This module contains special pages such as the recent changes page. 7 | 8 | 9 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 10 | :license: BSD. 11 | """ 12 | from simplewiki.utils import Response, Pagination, generate_template, href 13 | from simplewiki.database import RevisionedPage, Page 14 | from simplewiki.actions import page_missing 15 | 16 | 17 | 18 | def page_index(request): 19 | """Index of all pages.""" 20 | letters = {} 21 | for page in Page.query.order_by(Page.name): 22 | letters.setdefault(page.name.capitalize()[0], []).append(page) 23 | return Response(generate_template('page_index.html', 24 | letters=sorted(letters.items()) 25 | )) 26 | 27 | 28 | def recent_changes(request): 29 | """Display the recent changes.""" 30 | page = max(1, request.args.get('page', type=int)) 31 | query = RevisionedPage.query \ 32 | .order_by(RevisionedPage.revision_id.desc()) 33 | return Response(generate_template('recent_changes.html', 34 | pagination=Pagination(query, 20, page, 'Special:Recent_Changes') 35 | )) 36 | 37 | 38 | def page_not_found(request, page_name): 39 | """ 40 | Displays an error message if a user tried to access 41 | a not existing special page. 42 | """ 43 | return page_missing(request, page_name, True) 44 | 45 | 46 | pages = { 47 | 'Index': page_index, 48 | 'Recent_Changes': recent_changes 49 | } 50 | -------------------------------------------------------------------------------- /docs/wsgi.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | WSGI Helpers 3 | ============ 4 | 5 | .. module:: werkzeug.wsgi 6 | 7 | The following classes and functions are designed to make working with 8 | the WSGI specification easier or operate on the WSGI layer. All the 9 | functionality from this module is available on the high-level 10 | :ref:`Request/Response classes `. 11 | 12 | 13 | Iterator / Stream Helpers 14 | ========================= 15 | 16 | These classes and functions simplify working with the WSGI application 17 | iterator and the input stream. 18 | 19 | .. autoclass:: ClosingIterator 20 | 21 | .. autoclass:: FileWrapper 22 | 23 | .. autoclass:: LimitedStream 24 | :members: 25 | 26 | .. autofunction:: make_line_iter 27 | 28 | .. autofunction:: make_chunk_iter 29 | 30 | .. autofunction:: wrap_file 31 | 32 | 33 | Environ Helpers 34 | =============== 35 | 36 | These functions operate on the WSGI environment. They extract useful 37 | information or perform common manipulations: 38 | 39 | .. autofunction:: get_host 40 | 41 | .. autofunction:: get_content_length 42 | 43 | .. autofunction:: get_input_stream 44 | 45 | .. autofunction:: get_current_url 46 | 47 | .. autofunction:: get_query_string 48 | 49 | .. autofunction:: get_script_name 50 | 51 | .. autofunction:: get_path_info 52 | 53 | .. autofunction:: pop_path_info 54 | 55 | .. autofunction:: peek_path_info 56 | 57 | .. autofunction:: extract_path_info 58 | 59 | .. autofunction:: host_is_trusted 60 | 61 | Convenience Helpers 62 | =================== 63 | 64 | .. autofunction:: responder 65 | 66 | .. autofunction:: werkzeug.testapp.test_app 67 | -------------------------------------------------------------------------------- /docs/contents.rst.inc: -------------------------------------------------------------------------------- 1 | Getting Started 2 | --------------- 3 | 4 | If you are new to Werkzeug or WSGI development in general you 5 | should start here. 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | 10 | installation 11 | transition 12 | tutorial 13 | levels 14 | quickstart 15 | python3 16 | 17 | Serving and Testing 18 | ------------------- 19 | 20 | The development server and testing support and management script 21 | utilities are covered here: 22 | 23 | .. toctree:: 24 | :maxdepth: 2 25 | 26 | serving 27 | test 28 | debug 29 | 30 | Reference 31 | --------- 32 | 33 | .. toctree:: 34 | :maxdepth: 2 35 | 36 | wrappers 37 | routing 38 | wsgi 39 | http 40 | datastructures 41 | utils 42 | local 43 | middlewares 44 | exceptions 45 | 46 | Deployment 47 | ---------- 48 | 49 | This section covers running your application in production on a web 50 | server such as Apache or lighttpd. 51 | 52 | .. toctree:: 53 | :maxdepth: 3 54 | 55 | deployment/index 56 | 57 | Contributed Modules 58 | ------------------- 59 | 60 | A lot of useful code contributed by the community is shipped with Werkzeug 61 | as part of the `contrib` module: 62 | 63 | .. toctree:: 64 | :maxdepth: 3 65 | 66 | contrib/index 67 | 68 | Additional Information 69 | ---------------------- 70 | 71 | .. toctree:: 72 | :maxdepth: 2 73 | 74 | terms 75 | unicode 76 | request_data 77 | changes 78 | 79 | If you can’t find the information you’re looking for, have a look at the 80 | index or try to find it using the search function: 81 | 82 | * :ref:`genindex` 83 | * :ref:`search` 84 | -------------------------------------------------------------------------------- /docs/contrib/securecookie.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Secure Cookie 3 | ============= 4 | 5 | .. automodule:: werkzeug.contrib.securecookie 6 | 7 | Security 8 | ======== 9 | 10 | The default implementation uses Pickle as this is the only module that 11 | used to be available in the standard library when this module was created. 12 | If you have simplejson available it's strongly recommended to create a 13 | subclass and replace the serialization method:: 14 | 15 | import json 16 | from werkzeug.contrib.securecookie import SecureCookie 17 | 18 | class JSONSecureCookie(SecureCookie): 19 | serialization_method = json 20 | 21 | The weakness of Pickle is that if someone gains access to the secret key 22 | the attacker can not only modify the session but also execute arbitrary 23 | code on the server. 24 | 25 | 26 | Reference 27 | ========= 28 | 29 | .. autoclass:: SecureCookie 30 | :members: 31 | 32 | .. attribute:: new 33 | 34 | `True` if the cookie was newly created, otherwise `False` 35 | 36 | .. attribute:: modified 37 | 38 | Whenever an item on the cookie is set, this attribute is set to `True`. 39 | However this does not track modifications inside mutable objects 40 | in the cookie: 41 | 42 | >>> c = SecureCookie() 43 | >>> c["foo"] = [1, 2, 3] 44 | >>> c.modified 45 | True 46 | >>> c.modified = False 47 | >>> c["foo"].append(4) 48 | >>> c.modified 49 | False 50 | 51 | In that situation it has to be set to `modified` by hand so that 52 | :attr:`should_save` can pick it up. 53 | 54 | 55 | .. autoexception:: UnquoteError 56 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Werkzeug is written and maintained by the Werkzeug Team and various 2 | contributors: 3 | 4 | Project Leader / Developer: 5 | 6 | - Armin Ronacher 7 | 8 | - Georg Brandl 9 | - Leif K-Brooks 10 | - Thomas Johansson 11 | - Marian Sigler 12 | - Ronny Pfannschmidt 13 | - Noah Slater 14 | - Alec Thomas 15 | - Shannon Behrens 16 | - Christoph Rauch 17 | - Clemens Hermann 18 | - Jason Kirtland 19 | - Ali Afshar 20 | - Christopher Grebs 21 | - Sean Cazzell 22 | - Florent Xicluna 23 | - Kyle Dawkins 24 | - Pedro Algarvio 25 | - Zahari Petkov 26 | - Ludvig Ericson 27 | - Kenneth Reitz 28 | - Daniel Neuhäuser 29 | 30 | Contributors of code for werkzeug/examples are: 31 | 32 | - Itay Neeman 33 | 34 | The SSL related parts of the Werkzeug development server are partially 35 | taken from Paste. Same thing is true for the range support which comes 36 | from WebOb which is a Paste project. The original code is MIT licensed which 37 | is largely compatible with the modfied BSD license. The following copyrights 38 | apply: 39 | 40 | - (c) 2005 Ian Bicking and contributors 41 | - (c) 2005 Clark C. Evans 42 | 43 | The rename() function from the posixemulation was taken almost unmodified 44 | from the Trac project's utility module. The original code is BSD licensed 45 | with the following copyrights from that module: 46 | 47 | - (c) 2003-2009 Edgewall Software 48 | - (c) 2003-2006 Jonas Borgström 49 | - (c) 2006 Matthew Good 50 | - (c) 2005-2006 Christian Boos 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 by the Werkzeug Team, see AUTHORS for more details. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following 12 | disclaimer in the documentation and/or other materials provided 13 | with the distribution. 14 | 15 | * The names of the contributors may not be used to endorse or 16 | promote products derived from this software without specific 17 | prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /examples/shorty/application.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from werkzeug.wrappers import Request 3 | from werkzeug.wsgi import ClosingIterator, SharedDataMiddleware 4 | from werkzeug.exceptions import HTTPException, NotFound 5 | from shorty.utils import STATIC_PATH, session, local, local_manager, \ 6 | metadata, url_map 7 | 8 | import shorty.models 9 | from shorty import views 10 | 11 | 12 | class Shorty(object): 13 | 14 | def __init__(self, db_uri): 15 | local.application = self 16 | self.database_engine = create_engine(db_uri, convert_unicode=True) 17 | 18 | self.dispatch = SharedDataMiddleware(self.dispatch, { 19 | '/static': STATIC_PATH 20 | }) 21 | 22 | def init_database(self): 23 | metadata.create_all(self.database_engine) 24 | 25 | def dispatch(self, environ, start_response): 26 | local.application = self 27 | request = Request(environ) 28 | local.url_adapter = adapter = url_map.bind_to_environ(environ) 29 | try: 30 | endpoint, values = adapter.match() 31 | handler = getattr(views, endpoint) 32 | response = handler(request, **values) 33 | except NotFound, e: 34 | response = views.not_found(request) 35 | response.status_code = 404 36 | except HTTPException, e: 37 | response = e 38 | return ClosingIterator(response(environ, start_response), 39 | [session.remove, local_manager.cleanup]) 40 | 41 | def __call__(self, environ, start_response): 42 | return self.dispatch(environ, start_response) 43 | -------------------------------------------------------------------------------- /examples/couchy/application.py: -------------------------------------------------------------------------------- 1 | from couchdb.client import Server 2 | from couchy.utils import STATIC_PATH, local, local_manager, \ 3 | url_map 4 | from werkzeug.wrappers import Request 5 | from werkzeug.wsgi import ClosingIterator, SharedDataMiddleware 6 | from werkzeug.exceptions import HTTPException, NotFound 7 | from couchy import views 8 | from couchy.models import URL 9 | import couchy.models 10 | 11 | 12 | class Couchy(object): 13 | 14 | def __init__(self, db_uri): 15 | local.application = self 16 | 17 | server = Server(db_uri) 18 | try: 19 | db = server.create('urls') 20 | except: 21 | db = server['urls'] 22 | self.dispatch = SharedDataMiddleware(self.dispatch, { 23 | '/static': STATIC_PATH 24 | }) 25 | 26 | URL.db = db 27 | 28 | def dispatch(self, environ, start_response): 29 | local.application = self 30 | request = Request(environ) 31 | local.url_adapter = adapter = url_map.bind_to_environ(environ) 32 | try: 33 | endpoint, values = adapter.match() 34 | handler = getattr(views, endpoint) 35 | response = handler(request, **values) 36 | except NotFound, e: 37 | response = views.not_found(request) 38 | response.status_code = 404 39 | except HTTPException, e: 40 | response = e 41 | return ClosingIterator(response(environ, start_response), 42 | [local_manager.cleanup]) 43 | 44 | def __call__(self, environ, start_response): 45 | return self.dispatch(environ, start_response) 46 | -------------------------------------------------------------------------------- /docs/terms.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Important Terms 3 | =============== 4 | 5 | .. module:: werkzeug 6 | 7 | This page covers important terms used in the documentation and Werkzeug 8 | itself. 9 | 10 | 11 | WSGI 12 | ---- 13 | 14 | WSGI a specification for Python web applications Werkzeug follows. It was 15 | specified in the :pep:`333` and is widely supported. Unlike previous solutions 16 | it gurantees that web applications, servers and utilties can work together. 17 | 18 | Response Object 19 | --------------- 20 | 21 | For Werkzeug, a response object is an object that works like a WSGI 22 | application but does not do any request processing. Usually you have a view 23 | function or controller method that processes the request and assambles a 24 | response object. 25 | 26 | A response object is *not* necessarily the :class:`BaseResponse` object or a 27 | subclass thereof. 28 | 29 | For example Pylons/webob provide a very similar response class that can 30 | be used as well (:class:`webob.Response`). 31 | 32 | View Function 33 | ------------- 34 | 35 | Often people speak of MVC (Model, View, Controller) when developing web 36 | applications. However, the Django framework coined MTV (Model, Template, 37 | View) which basically means the same but reduces the concept to the data 38 | model, a function that processes data from the request and the database and 39 | renders a template. 40 | 41 | Werkzeug itself does not tell you how you should develop applications, but the 42 | documentation often speaks of view functions that work roughly the same. The 43 | idea of a view function is that it's called with a request object (and 44 | optionally some parameters from an URL rule) and returns a response object. 45 | -------------------------------------------------------------------------------- /examples/httpbasicauth.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | HTTP Basic Auth Example 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Shows how you can implement HTTP basic auth support without an 7 | additional component. 8 | 9 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 10 | :license: BSD. 11 | """ 12 | from werkzeug.serving import run_simple 13 | from werkzeug.wrappers import Request, Response 14 | 15 | 16 | class Application(object): 17 | 18 | def __init__(self, users, realm='login required'): 19 | self.users = users 20 | self.realm = realm 21 | 22 | def check_auth(self, username, password): 23 | return username in self.users and self.users[username] == password 24 | 25 | def auth_required(self, request): 26 | return Response('Could not verify your access level for that URL.\n' 27 | 'You have to login with proper credentials', 401, 28 | {'WWW-Authenticate': 'Basic realm="%s"' % self.realm}) 29 | 30 | def dispatch_request(self, request): 31 | return Response('Logged in as %s' % request.authorization.username) 32 | 33 | def __call__(self, environ, start_response): 34 | request = Request(environ) 35 | auth = request.authorization 36 | if not auth or not self.check_auth(auth.username, auth.password): 37 | response = self.auth_required(request) 38 | else: 39 | response = self.dispatch_request(request) 40 | return response(environ, start_response) 41 | 42 | 43 | if __name__ == '__main__': 44 | application = Application({'user1': 'password', 'user2': 'password'}) 45 | run_simple('localhost', 5000, application) 46 | -------------------------------------------------------------------------------- /werkzeug/testsuite/multipart/collect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Hacky helper application to collect form data. 4 | """ 5 | from werkzeug.serving import run_simple 6 | from werkzeug.wrappers import Request, Response 7 | 8 | 9 | def copy_stream(request): 10 | from os import mkdir 11 | from time import time 12 | folder = 'request-%d' % time() 13 | mkdir(folder) 14 | environ = request.environ 15 | f = open(folder + '/request.txt', 'wb+') 16 | f.write(environ['wsgi.input'].read(int(environ['CONTENT_LENGTH']))) 17 | f.flush() 18 | f.seek(0) 19 | environ['wsgi.input'] = f 20 | request.stat_folder = folder 21 | 22 | 23 | def stats(request): 24 | copy_stream(request) 25 | f1 = request.files['file1'] 26 | f2 = request.files['file2'] 27 | text = request.form['text'] 28 | f1.save(request.stat_folder + '/file1.bin') 29 | f2.save(request.stat_folder + '/file2.bin') 30 | open(request.stat_folder + '/text.txt', 'w').write(text.encode('utf-8')) 31 | return Response('Done.') 32 | 33 | 34 | def upload_file(request): 35 | return Response(''' 36 |

Upload File

37 |
38 |
39 |
40 |
41 | 42 |
43 | ''', mimetype='text/html') 44 | 45 | 46 | def application(environ, start_responseonse): 47 | request = Request(environ) 48 | if request.method == 'POST': 49 | response = stats(request) 50 | else: 51 | response = upload_file(request) 52 | return response(environ, start_responseonse) 53 | 54 | 55 | if __name__ == '__main__': 56 | run_simple('localhost', 5000, application, use_debugger=True) 57 | -------------------------------------------------------------------------------- /docs/deployment/proxying.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | HTTP Proxying 3 | ============= 4 | 5 | Many people prefer using a standalone Python HTTP server and proxying that 6 | server via nginx, Apache etc. 7 | 8 | A very stable Python server is CherryPy. This part of the documentation 9 | shows you how to combine your WSGI application with the CherryPy WSGI 10 | server and how to configure the webserver for proxying. 11 | 12 | 13 | Creating a `.py` server 14 | ======================= 15 | 16 | To run your application you need a `start-server.py` file that starts up 17 | the WSGI Server. 18 | 19 | It looks something along these lines:: 20 | 21 | from cherrypy import wsgiserver 22 | from yourapplication import make_app 23 | server = wsgiserver.CherryPyWSGIServer(('localhost', 8080), make_app()) 24 | try: 25 | server.start() 26 | except KeyboardInterrupt: 27 | server.stop() 28 | 29 | If you now start the file the server will listen on `localhost:8080`. Keep 30 | in mind that WSGI applications behave slightly different for proxied setups. 31 | If you have not developed your application for proxying in mind, you can 32 | apply the :class:`~werkzeug.contrib.fixers.ProxyFix` middleware. 33 | 34 | 35 | Configuring nginx 36 | ================= 37 | 38 | As an example we show here how to configure nginx to proxy to the server. 39 | 40 | The basic nginx configuration looks like this:: 41 | 42 | location / { 43 | proxy_set_header Host $host; 44 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 45 | proxy_pass http://127.0.0.1:8080; 46 | proxy_redirect default; 47 | } 48 | 49 | Since Nginx doesn't start your server for you, you have to do it by yourself. You 50 | can either write an `init.d` script for that or execute it inside a screen 51 | session:: 52 | 53 | $ screen 54 | $ python start-server.py 55 | -------------------------------------------------------------------------------- /docs/_themes/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 by Armin Ronacher. 2 | 3 | Some rights reserved. 4 | 5 | Redistribution and use in source and binary forms of the theme, with or 6 | without modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following 14 | disclaimer in the documentation and/or other materials provided 15 | with the distribution. 16 | 17 | * The names of the contributors may not be used to endorse or 18 | promote products derived from this software without specific 19 | prior written permission. 20 | 21 | We kindly ask you to only use these themes in an unmodified manner just 22 | for Flask and Flask-related products, not for unrelated projects. If you 23 | like the visual style and want to use it for your own projects, please 24 | consider making some larger changes to the themes (such as changing 25 | font faces, sizes, colors or margins). 26 | 27 | THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 31 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE 37 | POSSIBILITY OF SUCH DAMAGE. 38 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/action_log.html: -------------------------------------------------------------------------------- 1 | 4 | 6 | 7 | Revisions for “${page.title}” 8 | 9 | 10 |

Revisions for “${page.title}

11 |

12 | In this list you can see all the revisions of the requested page. 13 |

14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 33 | 40 | 41 |
DateChange NoteActions
${format_datetime(revision.timestamp)}${revision.change_note} 28 | 30 | 32 | 34 | show 35 | | 36 | revert 38 | 39 |
42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/shorty/views.py: -------------------------------------------------------------------------------- 1 | from werkzeug.utils import redirect 2 | from werkzeug.exceptions import NotFound 3 | from shorty.utils import session, Pagination, render_template, expose, \ 4 | validate_url, url_for 5 | from shorty.models import URL 6 | 7 | @expose('/') 8 | def new(request): 9 | error = url = '' 10 | if request.method == 'POST': 11 | url = request.form.get('url') 12 | alias = request.form.get('alias') 13 | if not validate_url(url): 14 | error = "I'm sorry but you cannot shorten this URL." 15 | elif alias: 16 | if len(alias) > 140: 17 | error = 'Your alias is too long' 18 | elif '/' in alias: 19 | error = 'Your alias might not include a slash' 20 | elif URL.query.get(alias): 21 | error = 'The alias you have requested exists already' 22 | if not error: 23 | uid = URL(url, 'private' not in request.form, alias).uid 24 | session.commit() 25 | return redirect(url_for('display', uid=uid)) 26 | return render_template('new.html', error=error, url=url) 27 | 28 | @expose('/display/') 29 | def display(request, uid): 30 | url = URL.query.get(uid) 31 | if not url: 32 | raise NotFound() 33 | return render_template('display.html', url=url) 34 | 35 | @expose('/u/') 36 | def link(request, uid): 37 | url = URL.query.get(uid) 38 | if not url: 39 | raise NotFound() 40 | return redirect(url.target, 301) 41 | 42 | @expose('/list/', defaults={'page': 1}) 43 | @expose('/list/') 44 | def list(request, page): 45 | query = URL.query.filter_by(public=True) 46 | pagination = Pagination(query, 30, page, 'list') 47 | if pagination.page > 1 and not pagination.entries: 48 | raise NotFound() 49 | return render_template('list.html', pagination=pagination) 50 | 51 | def not_found(request): 52 | return render_template('not_found.html') 53 | -------------------------------------------------------------------------------- /examples/plnt/webapp.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | plnt.webapp 4 | ~~~~~~~~~~~ 5 | 6 | The web part of the planet. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD. 10 | """ 11 | from os import path 12 | from sqlalchemy import create_engine 13 | from werkzeug.wrappers import Request 14 | from werkzeug.wsgi import ClosingIterator, SharedDataMiddleware 15 | from werkzeug.exceptions import HTTPException, NotFound 16 | from plnt.utils import local, local_manager, url_map, endpoints 17 | from plnt.database import session, metadata 18 | 19 | # import the views module because it contains setup code 20 | import plnt.views 21 | 22 | #: path to shared data 23 | SHARED_DATA = path.join(path.dirname(__file__), 'shared') 24 | 25 | 26 | class Plnt(object): 27 | 28 | def __init__(self, database_uri): 29 | self.database_engine = create_engine(database_uri) 30 | 31 | self._dispatch = local_manager.middleware(self.dispatch_request) 32 | self._dispatch = SharedDataMiddleware(self._dispatch, { 33 | '/shared': SHARED_DATA 34 | }) 35 | 36 | def init_database(self): 37 | metadata.create_all(self.database_engine) 38 | 39 | def bind_to_context(self): 40 | local.application = self 41 | 42 | def dispatch_request(self, environ, start_response): 43 | self.bind_to_context() 44 | local.request = request = Request(environ, start_response) 45 | local.url_adapter = adapter = url_map.bind_to_environ(environ) 46 | try: 47 | endpoint, values = adapter.match(request.path) 48 | response = endpoints[endpoint](request, **values) 49 | except HTTPException, e: 50 | response = e 51 | return ClosingIterator(response(environ, start_response), 52 | session.remove) 53 | 54 | def __call__(self, environ, start_response): 55 | return self._dispatch(environ, start_response) 56 | -------------------------------------------------------------------------------- /werkzeug/testsuite/contrib/securecookie.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.testsuite.securecookie 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Tests the secure cookie. 7 | 8 | :copyright: (c) 2013 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import unittest 12 | 13 | from werkzeug.testsuite import WerkzeugTestCase 14 | 15 | from werkzeug.utils import parse_cookie 16 | from werkzeug.wrappers import Request, Response 17 | from werkzeug.contrib.securecookie import SecureCookie 18 | 19 | 20 | class SecureCookieTestCase(WerkzeugTestCase): 21 | 22 | def test_basic_support(self): 23 | c = SecureCookie(secret_key=b'foo') 24 | assert c.new 25 | assert not c.modified 26 | assert not c.should_save 27 | c['x'] = 42 28 | assert c.modified 29 | assert c.should_save 30 | s = c.serialize() 31 | 32 | c2 = SecureCookie.unserialize(s, b'foo') 33 | assert c is not c2 34 | assert not c2.new 35 | assert not c2.modified 36 | assert not c2.should_save 37 | self.assert_equal(c2, c) 38 | 39 | c3 = SecureCookie.unserialize(s, b'wrong foo') 40 | assert not c3.modified 41 | assert not c3.new 42 | self.assert_equal(c3, {}) 43 | 44 | def test_wrapper_support(self): 45 | req = Request.from_values() 46 | resp = Response() 47 | c = SecureCookie.load_cookie(req, secret_key=b'foo') 48 | assert c.new 49 | c['foo'] = 42 50 | self.assert_equal(c.secret_key, b'foo') 51 | c.save_cookie(resp) 52 | 53 | req = Request.from_values(headers={ 54 | 'Cookie': 'session="%s"' % parse_cookie(resp.headers['set-cookie'])['session'] 55 | }) 56 | c2 = SecureCookie.load_cookie(req, secret_key=b'foo') 57 | assert not c2.new 58 | self.assert_equal(c2, c) 59 | 60 | 61 | def suite(): 62 | suite = unittest.TestSuite() 63 | suite.addTest(unittest.makeSuite(SecureCookieTestCase)) 64 | return suite 65 | -------------------------------------------------------------------------------- /docs/utils.rst: -------------------------------------------------------------------------------- 1 | ========= 2 | Utilities 3 | ========= 4 | 5 | Various utility functions shipped with Werkzeug. 6 | 7 | 8 | HTML Helpers 9 | ============ 10 | 11 | .. module:: werkzeug.utils 12 | 13 | .. autoclass:: HTMLBuilder 14 | 15 | .. autofunction:: escape 16 | 17 | .. autofunction:: unescape 18 | 19 | 20 | General Helpers 21 | =============== 22 | 23 | .. autoclass:: cached_property 24 | :members: 25 | 26 | .. autoclass:: environ_property 27 | 28 | .. autoclass:: header_property 29 | 30 | .. autofunction:: parse_cookie 31 | 32 | .. autofunction:: dump_cookie 33 | 34 | .. autofunction:: redirect 35 | 36 | .. autofunction:: append_slash_redirect 37 | 38 | .. autofunction:: import_string 39 | 40 | .. autofunction:: find_modules 41 | 42 | .. autofunction:: validate_arguments 43 | 44 | .. autofunction:: secure_filename 45 | 46 | .. autofunction:: bind_arguments 47 | 48 | 49 | URL Helpers 50 | =========== 51 | 52 | .. module:: werkzeug.urls 53 | 54 | .. autoclass:: Href 55 | 56 | .. autofunction:: url_decode 57 | 58 | .. autofunction:: url_decode_stream 59 | 60 | .. autofunction:: url_encode 61 | 62 | .. autofunction:: url_encode_stream 63 | 64 | .. autofunction:: url_quote 65 | 66 | .. autofunction:: url_quote_plus 67 | 68 | .. autofunction:: url_unquote 69 | 70 | .. autofunction:: url_unquote_plus 71 | 72 | .. autofunction:: url_fix 73 | 74 | .. autofunction:: uri_to_iri 75 | 76 | .. autofunction:: iri_to_uri 77 | 78 | 79 | UserAgent Parsing 80 | ================= 81 | 82 | .. module:: werkzeug.useragents 83 | 84 | .. autoclass:: UserAgent 85 | :members: 86 | 87 | 88 | Security Helpers 89 | ================ 90 | 91 | .. module:: werkzeug.security 92 | 93 | .. versionadded:: 0.6.1 94 | 95 | .. autofunction:: generate_password_hash 96 | 97 | .. autofunction:: check_password_hash 98 | 99 | .. autofunction:: safe_str_cmp 100 | 101 | .. autofunction:: safe_join 102 | 103 | .. autofunction:: pbkdf2_hex 104 | 105 | .. autofunction:: pbkdf2_bin 106 | -------------------------------------------------------------------------------- /examples/simplewiki/templates/layout.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | <py:if 7 | test="title">${title} — </py:if>SimpleWiki 8 | 9 | ${select('*[local-name()!="title"]')} 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Simple Wiki

17 |
18 |
19 |
20 | This revision 21 | was created on ${format_datetime(page.timestamp)}. 22 |
23 | 38 | ${select('*|text()')} 39 |
40 | 43 |
44 | 45 |
46 | 47 | -------------------------------------------------------------------------------- /examples/plnt/database.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | plnt.database 4 | ~~~~~~~~~~~~~ 5 | 6 | The database definitions for the planet. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD. 10 | """ 11 | from sqlalchemy import MetaData, Table, Column, ForeignKey, Boolean, \ 12 | Integer, String, DateTime 13 | from sqlalchemy.orm import dynamic_loader, scoped_session, create_session, \ 14 | mapper 15 | from plnt.utils import application, local_manager 16 | 17 | 18 | def new_db_session(): 19 | return create_session(application.database_engine, autoflush=True, 20 | autocommit=False) 21 | 22 | metadata = MetaData() 23 | session = scoped_session(new_db_session, local_manager.get_ident) 24 | 25 | 26 | blog_table = Table('blogs', metadata, 27 | Column('id', Integer, primary_key=True), 28 | Column('name', String(120)), 29 | Column('description', String), 30 | Column('url', String(200)), 31 | Column('feed_url', String(250)) 32 | ) 33 | 34 | entry_table = Table('entries', metadata, 35 | Column('id', Integer, primary_key=True), 36 | Column('blog_id', Integer, ForeignKey('blogs.id')), 37 | Column('guid', String(200), unique=True), 38 | Column('title', String(140)), 39 | Column('url', String(200)), 40 | Column('text', String), 41 | Column('pub_date', DateTime), 42 | Column('last_update', DateTime) 43 | ) 44 | 45 | 46 | class Blog(object): 47 | query = session.query_property() 48 | 49 | def __init__(self, name, url, feed_url, description=u''): 50 | self.name = name 51 | self.url = url 52 | self.feed_url = feed_url 53 | self.description = description 54 | 55 | def __repr__(self): 56 | return '<%s %r>' % (self.__class__.__name__, self.url) 57 | 58 | 59 | class Entry(object): 60 | query = session.query_property() 61 | 62 | def __repr__(self): 63 | return '<%s %r>' % (self.__class__.__name__, self.guid) 64 | 65 | 66 | mapper(Entry, entry_table) 67 | mapper(Blog, blog_table, properties=dict( 68 | entries=dynamic_loader(Entry, backref='blog') 69 | )) 70 | -------------------------------------------------------------------------------- /examples/couchy/static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #333; 3 | font-family: 'Lucida Sans', 'Verdana', sans-serif; 4 | font-size: 16px; 5 | margin: 3em 0 3em 0; 6 | padding: 0; 7 | text-align: center; 8 | } 9 | 10 | a { 11 | color: #0C4850; 12 | } 13 | 14 | a:hover { 15 | color: #1C818F; 16 | } 17 | 18 | h1 { 19 | width: 500px; 20 | background-color: #24C0CE; 21 | text-align: center; 22 | font-size: 3em; 23 | margin: 0 auto 0 auto; 24 | padding: 0; 25 | } 26 | 27 | h1 a { 28 | display: block; 29 | padding: 0.3em; 30 | color: #fff; 31 | text-decoration: none; 32 | } 33 | 34 | h1 a:hover { 35 | color: #ADEEF7; 36 | background-color: #0E8A96; 37 | } 38 | 39 | div.footer { 40 | margin: 0 auto 0 auto; 41 | font-size: 13px; 42 | text-align: right; 43 | padding: 10px; 44 | width: 480px; 45 | background-color: #004C63; 46 | color: white; 47 | } 48 | 49 | div.footer a { 50 | color: #A0E9FF; 51 | } 52 | 53 | div.body { 54 | margin: 0 auto 0 auto; 55 | padding: 20px; 56 | width: 460px; 57 | background-color: #98CE24; 58 | color: black; 59 | } 60 | 61 | div.body h2 { 62 | margin: 0 0 0.5em 0; 63 | text-align: center; 64 | } 65 | 66 | div.body input { 67 | margin: 0.2em 0 0.2em 0; 68 | font-family: 'Lucida Sans', 'Verdana', sans-serif; 69 | font-size: 20px; 70 | background-color: #CCEB98; 71 | color: black; 72 | } 73 | 74 | div.body #url { 75 | width: 400px; 76 | } 77 | 78 | div.body #alias { 79 | width: 300px; 80 | margin-right: 10px; 81 | } 82 | 83 | div.body #submit { 84 | width: 90px; 85 | } 86 | 87 | div.body p { 88 | margin: 0; 89 | padding: 0.2em 0 0.2em 0; 90 | } 91 | 92 | div.body ul { 93 | margin: 1em 0 1em 0; 94 | padding: 0; 95 | list-style: none; 96 | } 97 | 98 | div.error { 99 | margin: 1em 0 1em 0; 100 | border: 2px solid #AC0202; 101 | background-color: #9E0303; 102 | font-weight: bold; 103 | color: white; 104 | } 105 | 106 | div.pagination { 107 | font-size: 13px; 108 | } 109 | -------------------------------------------------------------------------------- /examples/shorty/static/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #333; 3 | font-family: 'Lucida Sans', 'Verdana', sans-serif; 4 | font-size: 16px; 5 | margin: 3em 0 3em 0; 6 | padding: 0; 7 | text-align: center; 8 | } 9 | 10 | a { 11 | color: #0C4850; 12 | } 13 | 14 | a:hover { 15 | color: #1C818F; 16 | } 17 | 18 | h1 { 19 | width: 500px; 20 | background-color: #24C0CE; 21 | text-align: center; 22 | font-size: 3em; 23 | margin: 0 auto 0 auto; 24 | padding: 0; 25 | } 26 | 27 | h1 a { 28 | display: block; 29 | padding: 0.3em; 30 | color: #fff; 31 | text-decoration: none; 32 | } 33 | 34 | h1 a:hover { 35 | color: #ADEEF7; 36 | background-color: #0E8A96; 37 | } 38 | 39 | div.footer { 40 | margin: 0 auto 0 auto; 41 | font-size: 13px; 42 | text-align: right; 43 | padding: 10px; 44 | width: 480px; 45 | background-color: #004C63; 46 | color: white; 47 | } 48 | 49 | div.footer a { 50 | color: #A0E9FF; 51 | } 52 | 53 | div.body { 54 | margin: 0 auto 0 auto; 55 | padding: 20px; 56 | width: 460px; 57 | background-color: #98CE24; 58 | color: black; 59 | } 60 | 61 | div.body h2 { 62 | margin: 0 0 0.5em 0; 63 | text-align: center; 64 | } 65 | 66 | div.body input { 67 | margin: 0.2em 0 0.2em 0; 68 | font-family: 'Lucida Sans', 'Verdana', sans-serif; 69 | font-size: 20px; 70 | background-color: #CCEB98; 71 | color: black; 72 | } 73 | 74 | div.body #url { 75 | width: 400px; 76 | } 77 | 78 | div.body #alias { 79 | width: 300px; 80 | margin-right: 10px; 81 | } 82 | 83 | div.body #submit { 84 | width: 90px; 85 | } 86 | 87 | div.body p { 88 | margin: 0; 89 | padding: 0.2em 0 0.2em 0; 90 | } 91 | 92 | div.body ul { 93 | margin: 1em 0 1em 0; 94 | padding: 0; 95 | list-style: none; 96 | } 97 | 98 | div.error { 99 | margin: 1em 0 1em 0; 100 | border: 2px solid #AC0202; 101 | background-color: #9E0303; 102 | font-weight: bold; 103 | color: white; 104 | } 105 | 106 | div.pagination { 107 | font-size: 13px; 108 | } 109 | -------------------------------------------------------------------------------- /examples/cupoftee/db.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | cupoftee.db 4 | ~~~~~~~~~~~ 5 | 6 | A simple object database. As long as the server is not running in 7 | multiprocess mode that's good enough. 8 | 9 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | from __future__ import with_statement 13 | import gdbm 14 | from threading import Lock 15 | from pickle import dumps, loads 16 | 17 | 18 | class Database(object): 19 | 20 | def __init__(self, filename): 21 | self.filename = filename 22 | self._fs = gdbm.open(filename, 'cf') 23 | self._local = {} 24 | self._lock = Lock() 25 | 26 | def __getitem__(self, key): 27 | with self._lock: 28 | return self._load_key(key) 29 | 30 | def _load_key(self, key): 31 | if key in self._local: 32 | return self._local[key] 33 | rv = loads(self._fs[key]) 34 | self._local[key] = rv 35 | return rv 36 | 37 | def __setitem__(self, key, value): 38 | self._local[key] = value 39 | 40 | def __delitem__(self, key, value): 41 | with self._lock: 42 | self._local.pop(key, None) 43 | if self._fs.has_key(key): 44 | del self._fs[key] 45 | 46 | def __del__(self): 47 | self.close() 48 | 49 | def __contains__(self, key): 50 | with self._lock: 51 | try: 52 | self._load_key(key) 53 | except KeyError: 54 | pass 55 | return key in self._local 56 | 57 | def setdefault(self, key, factory): 58 | with self._lock: 59 | try: 60 | rv = self._load_key(key) 61 | except KeyError: 62 | self._local[key] = rv = factory() 63 | return rv 64 | 65 | def sync(self): 66 | with self._lock: 67 | for key, value in self._local.iteritems(): 68 | self._fs[key] = dumps(value, 2) 69 | self._fs.sync() 70 | 71 | def close(self): 72 | try: 73 | self.sync() 74 | self._fs.close() 75 | except: 76 | pass 77 | -------------------------------------------------------------------------------- /examples/webpylike/webpylike.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | webpylike 4 | ~~~~~~~~~ 5 | 6 | This module implements web.py like dispatching. What this module does 7 | not implement is a stream system that hooks into sys.stdout like web.py 8 | provides. I consider this bad design. 9 | 10 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 11 | :license: BSD. 12 | """ 13 | import re 14 | from werkzeug.wrappers import BaseRequest, BaseResponse 15 | from werkzeug.exceptions import HTTPException, MethodNotAllowed, \ 16 | NotImplemented, NotFound 17 | 18 | 19 | class Request(BaseRequest): 20 | """Encapsulates a request.""" 21 | 22 | 23 | class Response(BaseResponse): 24 | """Encapsulates a response.""" 25 | 26 | 27 | class View(object): 28 | """Baseclass for our views.""" 29 | 30 | def __init__(self, app, req): 31 | self.app = app 32 | self.req = req 33 | 34 | def GET(self): 35 | raise MethodNotAllowed() 36 | POST = DELETE = PUT = GET 37 | 38 | def HEAD(self): 39 | return self.GET() 40 | 41 | 42 | class WebPyApp(object): 43 | """ 44 | An interface to a web.py like application. It works like the web.run 45 | function in web.py 46 | """ 47 | 48 | def __init__(self, urls, views): 49 | self.urls = [(re.compile('^%s$' % urls[i]), urls[i + 1]) 50 | for i in xrange(0, len(urls), 2)] 51 | self.views = views 52 | 53 | def __call__(self, environ, start_response): 54 | try: 55 | req = Request(environ) 56 | for regex, view in self.urls: 57 | match = regex.match(req.path) 58 | if match is not None: 59 | view = self.views[view](self, req) 60 | if req.method not in ('GET', 'HEAD', 'POST', 61 | 'DELETE', 'PUT'): 62 | raise NotImplemented() 63 | resp = getattr(view, req.method)(*match.groups()) 64 | break 65 | else: 66 | raise NotFound() 67 | except HTTPException, e: 68 | resp = e 69 | return resp(environ, start_response) 70 | -------------------------------------------------------------------------------- /examples/couchy/views.py: -------------------------------------------------------------------------------- 1 | from werkzeug.utils import redirect 2 | from werkzeug.exceptions import NotFound 3 | from couchy.utils import render_template, expose, \ 4 | validate_url, url_for, Pagination 5 | from couchy.models import URL 6 | 7 | 8 | @expose('/') 9 | def new(request): 10 | error = url = '' 11 | if request.method == 'POST': 12 | url = request.form.get('url') 13 | alias = request.form.get('alias') 14 | if not validate_url(url): 15 | error = "I'm sorry but you cannot shorten this URL." 16 | elif alias: 17 | if len(alias) > 140: 18 | error = 'Your alias is too long' 19 | elif '/' in alias: 20 | error = 'Your alias might not include a slash' 21 | elif URL.load(alias): 22 | error = 'The alias you have requested exists already' 23 | if not error: 24 | url = URL(target=url, public='private' not in request.form, shorty_id=alias if alias else None) 25 | url.store() 26 | uid = url.id 27 | return redirect(url_for('display', uid=uid)) 28 | return render_template('new.html', error=error, url=url) 29 | 30 | @expose('/display/') 31 | def display(request, uid): 32 | url = URL.load(uid) 33 | if not url: 34 | raise NotFound() 35 | return render_template('display.html', url=url) 36 | 37 | @expose('/u/') 38 | def link(request, uid): 39 | url = URL.load(uid) 40 | if not url: 41 | raise NotFound() 42 | return redirect(url.target, 301) 43 | 44 | @expose('/list/', defaults={'page': 1}) 45 | @expose('/list/') 46 | def list(request, page): 47 | def wrap(doc): 48 | data = doc.value 49 | data['_id'] = doc.id 50 | return URL.wrap(data) 51 | 52 | code = '''function(doc) { if (doc.public){ map([doc._id], doc); }}''' 53 | docResults = URL.query(code) 54 | results = [wrap(doc) for doc in docResults] 55 | pagination = Pagination(results, 1, page, 'list') 56 | if pagination.page > 1 and not pagination.entries: 57 | raise NotFound() 58 | return render_template('list.html', pagination=pagination) 59 | 60 | def not_found(request): 61 | return render_template('not_found.html') 62 | -------------------------------------------------------------------------------- /examples/cupoftee/templates/serverlist.html: -------------------------------------------------------------------------------- 1 |

Server List

2 |

3 | Currently $len(players) players are playing on 4 | $len(servers) servers. 5 | <% if cup.master.last_sync %> 6 | This list was last synced on 7 | $cup.master.last_sync.strftime('%d %B %Y at %H:%M UTC'). 8 | <% else %> 9 | Syncronization with master server in progress. Reload the page in a minute 10 | or two, to see the server list. 11 | <% endif %> 12 |

13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | <% for server in servers %> 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | <% endfor %> 33 | 34 |
$self.order_link('name', 'Name')$self.order_link('map', 'Map')$self.order_link('gametype', 'Gametype')$self.order_link('players', 'Players')$self.order_link('progression', 'Progression')
$escape(server.name)$escape(server.map)$server.gametype$server.player_count / $server.max_players${server.progression >= 0 and '%d%%' % server.progression or '?'}
35 |

Players online

36 |

37 | The following map represents the users playing currently. The bigger their name 38 | the higher their score in the current game. Clicking on the name takes you to 39 | the detail page of the server for some more information. 40 |

41 |
42 | <% for player in players %> 43 | $escape(player.name) 45 | <% endfor %> 46 |
47 |

Find User

48 |

49 | Find a user by username. The result page contains a link you can bookmark to 50 | find your buddy easily. Because currently there is no central user database 51 | users can appear on multiple servers for too generic usernames (like the 52 | default "nameless tee" user). 53 |

54 |
55 |

56 | 57 | 58 |

59 |
60 | -------------------------------------------------------------------------------- /examples/manage-plnt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Manage plnt 5 | ~~~~~~~~~~~ 6 | 7 | This script manages the plnt application. 8 | 9 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 10 | :license: BSD, see LICENSE for more details. 11 | """ 12 | import os 13 | from werkzeug import script 14 | 15 | 16 | def make_app(): 17 | """Helper function that creates a plnt app.""" 18 | from plnt import Plnt 19 | database_uri = os.environ.get('PLNT_DATABASE_URI') 20 | app = Plnt(database_uri or 'sqlite:////tmp/plnt.db') 21 | app.bind_to_context() 22 | return app 23 | 24 | 25 | action_runserver = script.make_runserver(make_app, use_reloader=True) 26 | action_shell = script.make_shell(lambda: {'app': make_app()}) 27 | 28 | 29 | def action_initdb(): 30 | """Initialize the database""" 31 | from plnt.database import Blog, session 32 | make_app().init_database() 33 | # and now fill in some python blogs everybody should read (shamelessly 34 | # added my own blog too) 35 | blogs = [ 36 | Blog('Armin Ronacher', 'http://lucumr.pocoo.org/', 37 | 'http://lucumr.pocoo.org/cogitations/feed/'), 38 | Blog('Georg Brandl', 'http://pyside.blogspot.com/', 39 | 'http://pyside.blogspot.com/feeds/posts/default'), 40 | Blog('Ian Bicking', 'http://blog.ianbicking.org/', 41 | 'http://blog.ianbicking.org/feed/'), 42 | Blog('Amir Salihefendic', 'http://amix.dk/', 43 | 'http://feeds.feedburner.com/amixdk'), 44 | Blog('Christopher Lenz', 'http://www.cmlenz.net/blog/', 45 | 'http://www.cmlenz.net/blog/atom.xml'), 46 | Blog('Frederick Lundh', 'http://online.effbot.org/', 47 | 'http://online.effbot.org/rss.xml') 48 | ] 49 | # okay. got tired here. if someone feels that he is missing, drop me 50 | # a line ;-) 51 | for blog in blogs: 52 | session.add(blog) 53 | session.commit() 54 | print 'Initialized database, now run manage-plnt.py sync to get the posts' 55 | 56 | 57 | def action_sync(): 58 | """Sync the blogs in the planet. Call this from a cronjob.""" 59 | from plnt.sync import sync 60 | make_app().bind_to_context() 61 | sync() 62 | 63 | 64 | if __name__ == '__main__': 65 | script.run() 66 | -------------------------------------------------------------------------------- /werkzeug/testsuite/contrib/sessions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.testsuite.sessions 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Added tests for the sessions. 7 | 8 | :copyright: (c) 2013 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import unittest 12 | import shutil 13 | from tempfile import mkdtemp, gettempdir 14 | 15 | from werkzeug.testsuite import WerkzeugTestCase 16 | from werkzeug.contrib.sessions import FilesystemSessionStore 17 | 18 | 19 | 20 | class SessionTestCase(WerkzeugTestCase): 21 | 22 | def setup(self): 23 | self.session_folder = mkdtemp() 24 | 25 | def teardown(self): 26 | shutil.rmtree(self.session_folder) 27 | 28 | def test_default_tempdir(self): 29 | store = FilesystemSessionStore() 30 | assert store.path == gettempdir() 31 | 32 | def test_basic_fs_sessions(self): 33 | store = FilesystemSessionStore(self.session_folder) 34 | x = store.new() 35 | assert x.new 36 | assert not x.modified 37 | x['foo'] = [1, 2, 3] 38 | assert x.modified 39 | store.save(x) 40 | 41 | x2 = store.get(x.sid) 42 | assert not x2.new 43 | assert not x2.modified 44 | assert x2 is not x 45 | assert x2 == x 46 | x2['test'] = 3 47 | assert x2.modified 48 | assert not x2.new 49 | store.save(x2) 50 | 51 | x = store.get(x.sid) 52 | store.delete(x) 53 | x2 = store.get(x.sid) 54 | # the session is not new when it was used previously. 55 | assert not x2.new 56 | 57 | def test_renewing_fs_session(self): 58 | store = FilesystemSessionStore(self.session_folder, renew_missing=True) 59 | x = store.new() 60 | store.save(x) 61 | store.delete(x) 62 | x2 = store.get(x.sid) 63 | assert x2.new 64 | 65 | def test_fs_session_lising(self): 66 | store = FilesystemSessionStore(self.session_folder, renew_missing=True) 67 | sessions = set() 68 | for x in range(10): 69 | sess = store.new() 70 | store.save(sess) 71 | sessions.add(sess.sid) 72 | 73 | listed_sessions = set(store.list()) 74 | assert sessions == listed_sessions 75 | 76 | 77 | def suite(): 78 | suite = unittest.TestSuite() 79 | suite.addTest(unittest.makeSuite(SessionTestCase)) 80 | return suite 81 | -------------------------------------------------------------------------------- /examples/couchy/utils.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | from urlparse import urlparse 3 | from random import sample, randrange 4 | from jinja import Environment, FileSystemLoader 5 | from werkzeug.local import Local, LocalManager 6 | from werkzeug.utils import cached_property 7 | from werkzeug.wrappers import Response 8 | from werkzeug.routing import Map, Rule 9 | 10 | TEMPLATE_PATH = path.join(path.dirname(__file__), 'templates') 11 | STATIC_PATH = path.join(path.dirname(__file__), 'static') 12 | ALLOWED_SCHEMES = frozenset(['http', 'https', 'ftp', 'ftps']) 13 | URL_CHARS = 'abcdefghijkmpqrstuvwxyzABCDEFGHIJKLMNPQRST23456789' 14 | 15 | local = Local() 16 | local_manager = LocalManager([local]) 17 | application = local('application') 18 | 19 | url_map = Map([Rule('/static/', endpoint='static', build_only=True)]) 20 | 21 | jinja_env = Environment(loader=FileSystemLoader(TEMPLATE_PATH)) 22 | 23 | 24 | def expose(rule, **kw): 25 | def decorate(f): 26 | kw['endpoint'] = f.__name__ 27 | url_map.add(Rule(rule, **kw)) 28 | return f 29 | return decorate 30 | 31 | def url_for(endpoint, _external=False, **values): 32 | return local.url_adapter.build(endpoint, values, force_external=_external) 33 | jinja_env.globals['url_for'] = url_for 34 | 35 | def render_template(template, **context): 36 | return Response(jinja_env.get_template(template).render(**context), 37 | mimetype='text/html') 38 | 39 | def validate_url(url): 40 | return urlparse(url)[0] in ALLOWED_SCHEMES 41 | 42 | def get_random_uid(): 43 | return ''.join(sample(URL_CHARS, randrange(3, 9))) 44 | 45 | class Pagination(object): 46 | 47 | def __init__(self, results, per_page, page, endpoint): 48 | self.results = results 49 | self.per_page = per_page 50 | self.page = page 51 | self.endpoint = endpoint 52 | 53 | @cached_property 54 | def count(self): 55 | return len(self.results) 56 | 57 | @cached_property 58 | def entries(self): 59 | return self.results[((self.page - 1) * self.per_page):(((self.page - 1) * self.per_page)+self.per_page)] 60 | 61 | has_previous = property(lambda x: x.page > 1) 62 | has_next = property(lambda x: x.page < x.pages) 63 | previous = property(lambda x: url_for(x.endpoint, page=x.page - 1)) 64 | next = property(lambda x: url_for(x.endpoint, page=x.page + 1)) 65 | pages = property(lambda x: max(0, x.count - 1) // x.per_page + 1) 66 | -------------------------------------------------------------------------------- /examples/cupoftee/shared/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Verdana', sans-serif; 3 | background: #2b93ad; 4 | margin: 0; 5 | padding: 0; 6 | font-size: 15px; 7 | text-align: center; 8 | } 9 | 10 | h1 { 11 | font-size: 0; 12 | margin: 0; 13 | padding: 10px 0 0 10px; 14 | height: 124px; 15 | line-height: 100px; 16 | background: url(header.png); 17 | color: white; 18 | } 19 | 20 | h1 a { 21 | display: block; 22 | margin: 0 auto 0 auto; 23 | height: 90px; 24 | width: 395px; 25 | background: url(logo.png); 26 | } 27 | 28 | div.contents { 29 | background: white url(content.png) repeat-x; 30 | margin: -8px auto 0 auto; 31 | text-align: left; 32 | padding: 15px; 33 | max-width: 1000px; 34 | } 35 | 36 | div.contents a { 37 | margin: 0 5px 0 5px; 38 | } 39 | 40 | div.footer { 41 | max-width: 1014px; 42 | margin: 0 auto 0 auto; 43 | background: #1a6f96; 44 | padding: 8px; 45 | font-size: 10px; 46 | color: white; 47 | } 48 | 49 | div.footer a { 50 | color: #79b9d7; 51 | } 52 | 53 | a { 54 | color: #1a6f96; 55 | text-decoration: none; 56 | } 57 | 58 | a:hover { 59 | color: #ffb735; 60 | } 61 | 62 | h2 { 63 | margin: 0 0 0.5em 0; 64 | padding: 0 0 0.1em 0; 65 | color: #ffb735; 66 | font-size: 2em; 67 | border-bottom: 1px solid #ccc; 68 | } 69 | 70 | h3 { 71 | margin: 1em 0 0.7em 0; 72 | color: #ffb735; 73 | font-size: 1.5em; 74 | } 75 | 76 | table { 77 | width: 100%; 78 | border-collapse: collapse; 79 | border: 3px solid #79b9d7; 80 | } 81 | 82 | table td, table th { 83 | border: 1px solid #79b9d7; 84 | padding: 3px 6px 3px 6px; 85 | font-weight: normal; 86 | text-align: center; 87 | font-size: 13px; 88 | } 89 | 90 | table th { 91 | background: #f2f8fb; 92 | text-align: left; 93 | } 94 | 95 | table thead th { 96 | font-weight: bold; 97 | background-color: #79b9d7; 98 | text-align: center; 99 | } 100 | 101 | table thead th a { 102 | color: white; 103 | } 104 | 105 | table thead th a.up { 106 | background: url(up.png) no-repeat right; 107 | padding-right: 20px; 108 | } 109 | 110 | table thead th a.down { 111 | background: url(down.png) no-repeat right; 112 | padding-right: 20px; 113 | } 114 | 115 | div.players { 116 | font-size: 11px; 117 | } 118 | 119 | dl dt { 120 | font-weight: bold; 121 | padding: 5px 0 0 0; 122 | } 123 | -------------------------------------------------------------------------------- /docs/transition.rst: -------------------------------------------------------------------------------- 1 | Transition to Werkzeug 1.0 2 | ========================== 3 | 4 | Werkzeug originally had a magical import system hook that enabled 5 | everything to be imported from one module and still loading the actual 6 | implementations lazily as necessary. Unfortunately this turned out be 7 | slow and also unreliable on alternative Python implementations and 8 | Google's App Engine. 9 | 10 | Starting with 0.7 we recommend against the short imports and strongly 11 | encourage starting importing from the actual implementation module. 12 | Werkzeug 1.0 will disable the magical import hook completely. 13 | 14 | Because finding out where the actual functions are imported and rewriting 15 | them by hand is a painful and boring process we wrote a tool that aids in 16 | making this transition. 17 | 18 | Automatically Rewriting Imports 19 | ------------------------------- 20 | 21 | For instance, with Werkzeug < 0.7 the recommended way to use the escape function 22 | was this:: 23 | 24 | from werkzeug import escape 25 | 26 | With Werkzeug 0.7, the recommended way to import this function is 27 | directly from the utils module (and with 1.0 this will become mandatory). 28 | To automatically rewrite all imports one can use the 29 | `werkzeug-import-rewrite `_ script. 30 | 31 | You can use it by executing it with Python and with a list of folders with 32 | Werkzeug based code. It will then spit out a hg/git compatible patch 33 | file. Example patch file creation:: 34 | 35 | $ python werkzeug-import-rewrite.py . > new-imports.udiff 36 | 37 | To apply the patch one of the following methods work: 38 | 39 | hg: 40 | 41 | :: 42 | 43 | hg import new-imports.udiff 44 | 45 | git: 46 | 47 | :: 48 | 49 | git apply new-imports.udiff 50 | 51 | patch: 52 | 53 | :: 54 | 55 | patch -p1 < new-imports.udiff 56 | 57 | Stop Using Deprecated Things 58 | ---------------------------- 59 | 60 | A few things in Werkzeug will stop being supported and for others, we're 61 | suggesting alternatives even if they will stick around for a longer time. 62 | 63 | Do not use: 64 | 65 | - `werkzeug.script`, replace it with custom scripts written with 66 | `argparse` or something similar. 67 | - `werkzeug.template`, replace with a proper template engine. 68 | - `werkzeug.contrib.jsrouting`, stop using URL generation for 69 | JavaScript, it does not scale well with many public routing. 70 | - `werkzeug.contrib.kickstart`, replace with hand written code, the 71 | Werkzeug API became better in general that this is no longer 72 | necessary. 73 | - `werkzeug.contrib.testtools`, not useful really. 74 | -------------------------------------------------------------------------------- /docs/debug.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | Debugging Applications 3 | ====================== 4 | 5 | .. module:: werkzeug.debug 6 | 7 | Depending on the WSGI gateway/server, exceptions are handled differently. 8 | But most of the time, exceptions go to stderr or the error log. 9 | 10 | Since this is not the best debugging environment, Werkzeug provides a 11 | WSGI middleware that renders nice debugging tracebacks, optionally with an 12 | AJAX based debugger (which allows to execute code in the context of the 13 | traceback's frames). 14 | 15 | The interactive debugger however does not work in forking environments 16 | which makes it nearly impossible to use on production servers. Also the 17 | debugger allows the execution of arbitrary code which makes it a major 18 | security risk and **must never be used on production machines** because of 19 | that. 20 | 21 | Enabling the Debugger 22 | ===================== 23 | 24 | You can enable the debugger by wrapping the application in a 25 | :class:`DebuggedApplication` middleware. Additionally there are 26 | parameters to the :func:`run_simple` function to enable it because this 27 | is a common task during development. 28 | 29 | .. autoclass:: DebuggedApplication 30 | 31 | Using the Debugger 32 | ================== 33 | 34 | Once enabled and an error happens during a request you will see a detailed 35 | traceback instead of a general "internal server error". If you have the 36 | `evalex` feature enabled you can also get a traceback for every frame in 37 | the traceback by clicking on the console icon. 38 | 39 | Once clicked a console opens where you can execute Python code in: 40 | 41 | .. image:: _static/debug-screenshot.png 42 | :alt: a screenshot of the interactive debugger 43 | :align: center 44 | 45 | Inside the interactive consoles you can execute any kind of Python code. 46 | Unlike regular Python consoles the output of the object reprs is colored 47 | and stripped to a reasonable size by default. If the output is longer 48 | than what the console decides to display a small plus sign is added to 49 | the repr and a click will expand the repr. 50 | 51 | To display all variables that are defined in the current frame you can 52 | use the `dump()` function. You can call it without arguments to get a 53 | detailed list of all variables and their values, or with an object as 54 | argument to get a detailed list of all the attributes it has. 55 | 56 | Pasting Errors 57 | ============== 58 | 59 | If you click on the `Traceback` title the traceback switches over to a text 60 | based one. The text based one can be pasted to `paste.pocoo.org`_ with one 61 | click. 62 | 63 | 64 | .. _paste.pocoo.org: http://paste.pocoo.org/ 65 | -------------------------------------------------------------------------------- /werkzeug/contrib/testtools.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.contrib.testtools 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | This module implements extended wrappers for simplified testing. 7 | 8 | `TestResponse` 9 | A response wrapper which adds various cached attributes for 10 | simplified assertions on various content types. 11 | 12 | :copyright: (c) 2013 by the Werkzeug Team, see AUTHORS for more details. 13 | :license: BSD, see LICENSE for more details. 14 | """ 15 | from werkzeug.utils import cached_property, import_string 16 | from werkzeug.wrappers import Response 17 | 18 | from warnings import warn 19 | warn(DeprecationWarning('werkzeug.contrib.testtools is deprecated and ' 20 | 'will be removed with Werkzeug 1.0')) 21 | 22 | 23 | class ContentAccessors(object): 24 | """ 25 | A mixin class for response objects that provides a couple of useful 26 | accessors for unittesting. 27 | """ 28 | 29 | def xml(self): 30 | """Get an etree if possible.""" 31 | if 'xml' not in self.mimetype: 32 | raise AttributeError( 33 | 'Not a XML response (Content-Type: %s)' 34 | % self.mimetype) 35 | for module in ['xml.etree.ElementTree', 'ElementTree', 36 | 'elementtree.ElementTree']: 37 | etree = import_string(module, silent=True) 38 | if etree is not None: 39 | return etree.XML(self.body) 40 | raise RuntimeError('You must have ElementTree installed ' 41 | 'to use TestResponse.xml') 42 | xml = cached_property(xml) 43 | 44 | def lxml(self): 45 | """Get an lxml etree if possible.""" 46 | if ('html' not in self.mimetype and 'xml' not in self.mimetype): 47 | raise AttributeError('Not an HTML/XML response') 48 | from lxml import etree 49 | try: 50 | from lxml.html import fromstring 51 | except ImportError: 52 | fromstring = etree.HTML 53 | if self.mimetype=='text/html': 54 | return fromstring(self.data) 55 | return etree.XML(self.data) 56 | lxml = cached_property(lxml) 57 | 58 | def json(self): 59 | """Get the result of simplejson.loads if possible.""" 60 | if 'json' not in self.mimetype: 61 | raise AttributeError('Not a JSON response') 62 | try: 63 | from simplejson import loads 64 | except ImportError: 65 | from json import loads 66 | return loads(self.data) 67 | json = cached_property(json) 68 | 69 | 70 | class TestResponse(Response, ContentAccessors): 71 | """Pass this to `werkzeug.test.Client` for easier unittesting.""" 72 | -------------------------------------------------------------------------------- /examples/cupoftee/pages.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | cupoftee.pages 4 | ~~~~~~~~~~~~~~ 5 | 6 | The pages. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import operator 12 | from werkzeug.utils import redirect 13 | from werkzeug.exceptions import NotFound 14 | from cupoftee.application import Page 15 | from cupoftee.utils import unicodecmp 16 | 17 | 18 | class ServerList(Page): 19 | url_rule = '/' 20 | 21 | def order_link(self, name, title): 22 | cls = '' 23 | link = '?order_by=' + name 24 | desc = False 25 | if name == self.order_by: 26 | desc = not self.order_desc 27 | cls = ' class="%s"' % (desc and 'down' or 'up') 28 | if desc: 29 | link += '&dir=desc' 30 | return '%s' % (link, cls, title) 31 | 32 | def process(self): 33 | self.order_by = self.request.args.get('order_by') or 'name' 34 | sort_func = { 35 | 'name': lambda x: x, 36 | 'map': lambda x: x.map, 37 | 'gametype': lambda x: x.gametype, 38 | 'players': lambda x: x.player_count, 39 | 'progression': lambda x: x.progression, 40 | }.get(self.order_by) 41 | if sort_func is None: 42 | return redirect(self.url_for('serverlist')) 43 | 44 | self.servers = self.cup.master.servers.values() 45 | self.servers.sort(key=sort_func) 46 | if self.request.args.get('dir') == 'desc': 47 | self.servers.reverse() 48 | self.order_desc = True 49 | else: 50 | self.order_desc = False 51 | 52 | self.players = reduce(lambda a, b: a + b.players, self.servers, []) 53 | self.players.sort(lambda a, b: unicodecmp(a.name, b.name)) 54 | 55 | 56 | class Server(Page): 57 | url_rule = '/server/' 58 | 59 | def process(self, id): 60 | try: 61 | self.server = self.cup.master.servers[id] 62 | except KeyError: 63 | raise NotFound() 64 | 65 | 66 | class Search(Page): 67 | url_rule = '/search' 68 | 69 | def process(self): 70 | self.user = self.request.args.get('user') 71 | if self.user: 72 | self.results = [] 73 | for server in self.cup.master.servers.itervalues(): 74 | for player in server.players: 75 | if player.name == self.user: 76 | self.results.append(server) 77 | 78 | 79 | class MissingPage(Page): 80 | 81 | def get_response(self): 82 | response = super(MissingPage, self).get_response() 83 | response.status_code = 404 84 | return response 85 | -------------------------------------------------------------------------------- /examples/shorty/utils.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | from urlparse import urlparse 3 | from random import sample, randrange 4 | from jinja2 import Environment, FileSystemLoader 5 | from werkzeug.local import Local, LocalManager 6 | from werkzeug.utils import cached_property 7 | from werkzeug.wrappers import Response 8 | from werkzeug.routing import Map, Rule 9 | from sqlalchemy import MetaData 10 | from sqlalchemy.orm import create_session, scoped_session 11 | 12 | 13 | TEMPLATE_PATH = path.join(path.dirname(__file__), 'templates') 14 | STATIC_PATH = path.join(path.dirname(__file__), 'static') 15 | ALLOWED_SCHEMES = frozenset(['http', 'https', 'ftp', 'ftps']) 16 | URL_CHARS = 'abcdefghijkmpqrstuvwxyzABCDEFGHIJKLMNPQRST23456789' 17 | 18 | local = Local() 19 | local_manager = LocalManager([local]) 20 | application = local('application') 21 | 22 | metadata = MetaData() 23 | url_map = Map([Rule('/static/', endpoint='static', build_only=True)]) 24 | 25 | session = scoped_session(lambda: create_session(application.database_engine, 26 | autocommit=False, 27 | autoflush=False)) 28 | jinja_env = Environment(loader=FileSystemLoader(TEMPLATE_PATH)) 29 | 30 | 31 | def expose(rule, **kw): 32 | def decorate(f): 33 | kw['endpoint'] = f.__name__ 34 | url_map.add(Rule(rule, **kw)) 35 | return f 36 | return decorate 37 | 38 | def url_for(endpoint, _external=False, **values): 39 | return local.url_adapter.build(endpoint, values, force_external=_external) 40 | jinja_env.globals['url_for'] = url_for 41 | 42 | def render_template(template, **context): 43 | return Response(jinja_env.get_template(template).render(**context), 44 | mimetype='text/html') 45 | 46 | def validate_url(url): 47 | return urlparse(url)[0] in ALLOWED_SCHEMES 48 | 49 | def get_random_uid(): 50 | return ''.join(sample(URL_CHARS, randrange(3, 9))) 51 | 52 | 53 | class Pagination(object): 54 | 55 | def __init__(self, query, per_page, page, endpoint): 56 | self.query = query 57 | self.per_page = per_page 58 | self.page = page 59 | self.endpoint = endpoint 60 | 61 | @cached_property 62 | def count(self): 63 | return self.query.count() 64 | 65 | @cached_property 66 | def entries(self): 67 | return self.query.offset((self.page - 1) * self.per_page) \ 68 | .limit(self.per_page).all() 69 | 70 | has_previous = property(lambda x: x.page > 1) 71 | has_next = property(lambda x: x.page < x.pages) 72 | previous = property(lambda x: url_for(x.endpoint, page=x.page - 1)) 73 | next = property(lambda x: url_for(x.endpoint, page=x.page + 1)) 74 | pages = property(lambda x: max(0, x.count - 1) // x.per_page + 1) 75 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | set SPHINXBUILD=sphinx-build 6 | set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% . 7 | if NOT "%PAPER%" == "" ( 8 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 9 | ) 10 | 11 | if "%1" == "" goto help 12 | 13 | if "%1" == "help" ( 14 | :help 15 | echo.Please use `make ^` where ^ is one of 16 | echo. html to make standalone HTML files 17 | echo. pickle to make pickle files 18 | echo. json to make JSON files 19 | echo. htmlhelp to make HTML files and a HTML help project 20 | echo. qthelp to make HTML files and a qthelp project 21 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 22 | echo. changes to make an overview over all changed/added/deprecated items 23 | echo. linkcheck to check all external links for integrity 24 | goto end 25 | ) 26 | 27 | if "%1" == "clean" ( 28 | for /d %%i in (_build\*) do rmdir /q /s %%i 29 | del /q /s _build\* 30 | goto end 31 | ) 32 | 33 | if "%1" == "html" ( 34 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html 35 | echo. 36 | echo.Build finished. The HTML pages are in _build/html. 37 | goto end 38 | ) 39 | 40 | if "%1" == "pickle" ( 41 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle 42 | echo. 43 | echo.Build finished; now you can process the pickle files. 44 | goto end 45 | ) 46 | 47 | if "%1" == "json" ( 48 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json 49 | echo. 50 | echo.Build finished; now you can process the JSON files. 51 | goto end 52 | ) 53 | 54 | if "%1" == "htmlhelp" ( 55 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp 56 | echo. 57 | echo.Build finished; now you can run HTML Help Workshop with the ^ 58 | .hhp project file in _build/htmlhelp. 59 | goto end 60 | ) 61 | 62 | if "%1" == "qthelp" ( 63 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp 64 | echo. 65 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 66 | .qhcp project file in _build/qthelp, like this: 67 | echo.^> qcollectiongenerator _build\qthelp\Werkzeug.qhcp 68 | echo.To view the help file: 69 | echo.^> assistant -collectionFile _build\qthelp\Werkzeug.ghc 70 | goto end 71 | ) 72 | 73 | if "%1" == "latex" ( 74 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex 75 | echo. 76 | echo.Build finished; the LaTeX files are in _build/latex. 77 | goto end 78 | ) 79 | 80 | if "%1" == "changes" ( 81 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes 82 | echo. 83 | echo.The overview file is in _build/changes. 84 | goto end 85 | ) 86 | 87 | if "%1" == "linkcheck" ( 88 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck 89 | echo. 90 | echo.Link check complete; look for any errors in the above output ^ 91 | or in _build/linkcheck/output.txt. 92 | goto end 93 | ) 94 | 95 | :end 96 | -------------------------------------------------------------------------------- /docs/python3.rst: -------------------------------------------------------------------------------- 1 | .. _python3: 2 | 3 | ============== 4 | Python 3 Notes 5 | ============== 6 | 7 | This part of the documentation outlines special information required to 8 | use Werkzeug and WSGI on Python 3. 9 | 10 | .. warning:: 11 | 12 | Python 3 support in Werkzeug is currently highly experimental. Please 13 | give feedback on it and help us improve it. 14 | 15 | 16 | WSGI Environment 17 | ================ 18 | 19 | The WSGI environment on Python 3 works slightly different than it does on 20 | Python 2. For the most part Werkzeug hides the differences from you if 21 | you work on the higher level APIs. The main difference between Python 2 22 | and Python 3 is that on Python 2 the WSGI environment contains bytes 23 | whereas the environment on Python 3 contains a range of differently 24 | encoded strings. 25 | 26 | There are two different kinds of strings in the WSGI environ on Python 3: 27 | 28 | - unicode strings restricted to latin1 values. These are the used for 29 | HTTP headers and a few other things. 30 | - unicode strings carrying binary payload, roundtripped through latin1 31 | values. This is usually referred as “WSGI encoding dance” throughout 32 | Werkzeug. 33 | 34 | Werkzeug provides you with functionality to deal with these automatically 35 | so that you don't need to be aware of the inner workings. The following 36 | functions and classes should be used to read information out of the 37 | WSGI environment: 38 | 39 | - :func:`~werkzeug.wsgi.get_current_url` 40 | - :func:`~werkzeug.wsgi.get_host` 41 | - :func:`~werkzeug.wsgi.get_script_name` 42 | - :func:`~werkzeug.wsgi.get_path_info` 43 | - :func:`~werkzeug.wsgi.get_query_string` 44 | - :func:`~werkzeug.datastructures.EnvironHeaders` 45 | 46 | Applications are strongly discouraged to create and modify a WSGI 47 | environment themselves on Python 3 unless they take care of the proper 48 | decoding step. All high level interfaces in Werkzeug will apply the 49 | correct encoding and decoding steps as necessary. 50 | 51 | URLs 52 | ==== 53 | 54 | URLs in Werkzeug attempt to represent themselves as unicode strings on 55 | Python 3. All the parsing functions generally also provide functionality 56 | that allow operations on bytes. In some cases functions that deal with 57 | URLs allow passing in `None` as charset to change the return value to byte 58 | objects. Internally Werkzeug will now unify URIs and IRIs as much as 59 | possible. 60 | 61 | Request Cleanup 62 | =============== 63 | 64 | Request objects on Python 3 and PyPy require explicit closing when file 65 | uploads are involved. This is required to properly close temporary file 66 | objects created by the multipart parser. For that purpose the ``close()`` 67 | method was introduced. 68 | 69 | In addition to that request objects now also act as context managers that 70 | automatically close. 71 | -------------------------------------------------------------------------------- /docs/levels.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | API Levels 3 | ========== 4 | 5 | .. module:: werkzeug 6 | 7 | Werkzeug is intended to be a utility rather than a framework. Because of that 8 | the user-friendly API is separated from the lower-level API so that Werkzeug 9 | can easily be used to extend another system. 10 | 11 | All the functionality the :class:`Request` and :class:`Response` objects (aka 12 | the "wrappers") provide is also available in small utility functions. 13 | 14 | Example 15 | ======= 16 | 17 | This example implements a small `Hello World` application that greets the 18 | user with the name entered:: 19 | 20 | from werkzeug.utils import escape 21 | from werkzeug.wrappers import Request, Response 22 | 23 | @Request.application 24 | def hello_world(request): 25 | result = ['Greeter'] 26 | if request.method == 'POST': 27 | result.append('

Hello %s!

' % escape(request.form['name'])) 28 | result.append(''' 29 |
30 |

Name: 31 | 32 |

33 | ''') 34 | return Response(''.join(result), mimetype='text/html') 35 | 36 | Alternatively the same application could be used without request and response 37 | objects but by taking advantage of the parsing functions werkzeug provides:: 38 | 39 | from werkzeug.formparser import parse_form_data 40 | from werkzeug.utils import escape 41 | 42 | def hello_world(environ, start_response): 43 | result = ['Greeter'] 44 | if environ['REQUEST_METHOD'] == 'POST': 45 | form = parse_form_data(environ)[1] 46 | result.append('

Hello %s!

' % escape(form['name'])) 47 | result.append(''' 48 |
49 |

Name: 50 | 51 |

52 | ''') 53 | start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')]) 54 | return [''.join(result)] 55 | 56 | High or Low? 57 | ============ 58 | 59 | Usually you want to use the high-level layer (the request and response 60 | objects). But there are situations where this might not be what you want. 61 | 62 | For example you might be maintaining code for an application written in 63 | Django or another framework and you have to parse HTTP headers. You can 64 | utilize Werkzeug for that by accessing the lower-level HTTP header parsing 65 | functions. 66 | 67 | Another situation where the low level parsing functions can be useful are 68 | custom WSGI frameworks, unit-testing or modernizing an old CGI/mod_python 69 | application to WSGI as well as WSGI middlewares where you want to keep the 70 | overhead low. 71 | -------------------------------------------------------------------------------- /examples/plnt/shared/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Luxi Sans', 'Lucida Sans', 'Verdana', sans-serif; 3 | margin: 1em; 4 | padding: 0; 5 | background-color: #BDE1EC; 6 | color: #0B2B35; 7 | } 8 | 9 | a { 10 | color: #50ACC4; 11 | } 12 | 13 | a:hover { 14 | color: #0B2B35; 15 | } 16 | 17 | div.header { 18 | display: block; 19 | margin: -1em -1em 0 -1em; 20 | padding: 1em; 21 | background-color: #0B2B35; 22 | color: white; 23 | } 24 | 25 | div.header h1 { 26 | font-family: 'Georgia', serif; 27 | margin: 0; 28 | font-size: 1.8em; 29 | } 30 | 31 | div.header blockquote { 32 | margin: 0; 33 | padding: 0.5em 0 0 1em; 34 | font-size: 0.9em; 35 | } 36 | 37 | div.footer { 38 | margin: 1em -1em -1em -1em; 39 | padding: 0.5em; 40 | color: #F3F7F8; 41 | background-color: #1F6070; 42 | } 43 | 44 | div.footer p { 45 | margin: 0; 46 | padding: 0; 47 | font-size: 0.8em; 48 | text-align: right; 49 | } 50 | 51 | ul.navigation { 52 | float: right; 53 | padding: 0.7em 1em 0.7em 1em; 54 | background-color: #F3F7F8; 55 | border: 1px solid #85CADB; 56 | border-right-color: #50ACC4; 57 | border-bottom-color: #50ACC4; 58 | list-style: none; 59 | } 60 | 61 | ul.navigation li { 62 | padding: 0.3em 0 0.3em 0; 63 | } 64 | 65 | ul.navigation li a { 66 | color: #0B2B35; 67 | } 68 | 69 | ul.navigation li a:hover { 70 | color: #50ACC4; 71 | } 72 | 73 | div.pagination { 74 | margin: 0.5em 0 0.5em 0; 75 | padding: 0.7em; 76 | text-align: center; 77 | max-width: 50em; 78 | background-color: white; 79 | border: 1px solid #B1CDD4; 80 | } 81 | 82 | div.day, div.page { 83 | max-width: 50em; 84 | background-color: white; 85 | border: 1px solid #50ACC4; 86 | margin: 1em 0 1em 0; 87 | padding: 0.7em; 88 | } 89 | 90 | div.day h2, div.page h2 { 91 | margin: 0 0 0.5em 0; 92 | padding: 0; 93 | color: black; 94 | font-size: 1.7em; 95 | } 96 | 97 | div.page p { 98 | margin: 0.7em 1em 0.7em 1em; 99 | line-height: 1.5em; 100 | } 101 | 102 | div.day div.entry { 103 | margin: 0.5em 0.25em 0.5em 1em; 104 | padding: 1em; 105 | background-color: #F3F7F8; 106 | border: 1px solid #85CADB; 107 | border-left-color: #50ACC4; 108 | border-top-color: #50ACC4; 109 | } 110 | 111 | div.day div.entry h3 { 112 | margin: 0; 113 | padding: 0; 114 | } 115 | 116 | div.day div.entry h3 a { 117 | color: #1C6D81; 118 | text-decoration: none; 119 | } 120 | 121 | div.day div.entry p.meta { 122 | color: #666; 123 | font-size: 0.85em; 124 | margin: 0.3em 0 0.6em 0; 125 | } 126 | 127 | div.day div.entry p.meta a { 128 | color: #666; 129 | } 130 | 131 | div.day div.entry div.text { 132 | padding: 0 0 0 0.5em; 133 | } 134 | -------------------------------------------------------------------------------- /examples/coolmagic/application.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | coolmagic.application 4 | ~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | This module provides the WSGI application. 7 | 8 | The WSGI middlewares are applied in the `make_app` factory function 9 | that automatically wraps the application within the require 10 | middlewares. Per default only the `SharedDataMiddleware` is applied. 11 | 12 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 13 | :license: BSD, see LICENSE for more details. 14 | """ 15 | from os import path, listdir 16 | from coolmagic.utils import Request, local_manager, redirect 17 | from werkzeug.routing import Map, Rule, RequestRedirect 18 | from werkzeug.exceptions import HTTPException, NotFound 19 | 20 | 21 | class CoolMagicApplication(object): 22 | """ 23 | The application class. It's passed a directory with configuration values. 24 | """ 25 | 26 | def __init__(self, config): 27 | self.config = config 28 | 29 | for fn in listdir(path.join(path.dirname(__file__), 'views')): 30 | if fn.endswith('.py') and fn != '__init__.py': 31 | __import__('coolmagic.views.' + fn[:-3]) 32 | 33 | from coolmagic.utils import exported_views 34 | rules = [ 35 | # url for shared data. this will always be unmatched 36 | # because either the middleware or the webserver 37 | # handles that request first. 38 | Rule('/public/', 39 | endpoint='shared_data') 40 | ] 41 | self.views = {} 42 | for endpoint, (func, rule, extra) in exported_views.iteritems(): 43 | if rule is not None: 44 | rules.append(Rule(rule, endpoint=endpoint, **extra)) 45 | self.views[endpoint] = func 46 | self.url_map = Map(rules) 47 | 48 | def __call__(self, environ, start_response): 49 | urls = self.url_map.bind_to_environ(environ) 50 | req = Request(environ, urls) 51 | try: 52 | endpoint, args = urls.match(req.path) 53 | resp = self.views[endpoint](**args) 54 | except NotFound, e: 55 | resp = self.views['static.not_found']() 56 | except (HTTPException, RequestRedirect), e: 57 | resp = e 58 | return resp(environ, start_response) 59 | 60 | 61 | def make_app(config=None): 62 | """ 63 | Factory function that creates a new `CoolmagicApplication` 64 | object. Optional WSGI middlewares should be applied here. 65 | """ 66 | config = config or {} 67 | app = CoolMagicApplication(config) 68 | 69 | # static stuff 70 | from werkzeug.utils import SharedDataMiddleware 71 | app = SharedDataMiddleware(app, { 72 | '/public': path.join(path.dirname(__file__), 'public') 73 | }) 74 | 75 | # clean up locals 76 | app = local_manager.make_middleware(app) 77 | 78 | return app 79 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Werkzeug 4 | ======== 5 | 6 | Werkzeug started as simple collection of various utilities for WSGI 7 | applications and has become one of the most advanced WSGI utility 8 | modules. It includes a powerful debugger, full featured request and 9 | response objects, HTTP utilities to handle entity tags, cache control 10 | headers, HTTP dates, cookie handling, file uploads, a powerful URL 11 | routing system and a bunch of community contributed addon modules. 12 | 13 | Werkzeug is unicode aware and doesn't enforce a specific template 14 | engine, database adapter or anything else. It doesn't even enforce 15 | a specific way of handling requests and leaves all that up to the 16 | developer. It's most useful for end user applications which should work 17 | on as many server environments as possible (such as blogs, wikis, 18 | bulletin boards, etc.). 19 | 20 | Details and example applications are available on the 21 | `Werkzeug website `_. 22 | 23 | 24 | Features 25 | -------- 26 | 27 | - unicode awareness 28 | 29 | - request and response objects 30 | 31 | - various utility functions for dealing with HTTP headers such as 32 | `Accept` and `Cache-Control` headers. 33 | 34 | - thread local objects with proper cleanup at request end 35 | 36 | - an interactive debugger 37 | 38 | - A simple WSGI server with support for threading and forking 39 | with an automatic reloader. 40 | 41 | - a flexible URL routing system with REST support. 42 | 43 | - fully WSGI compatible 44 | 45 | 46 | Development Version 47 | ------------------- 48 | 49 | The Werkzeug development version can be installed by cloning the git 50 | repository from `github`_:: 51 | 52 | git clone git@github.com:mitsuhiko/werkzeug.git 53 | 54 | .. _github: http://github.com/mitsuhiko/werkzeug 55 | """ 56 | try: 57 | from setuptools import setup 58 | except ImportError: 59 | from distutils.core import setup 60 | 61 | 62 | setup( 63 | name='Werkzeug', 64 | version='0.10-dev', 65 | url='http://werkzeug.pocoo.org/', 66 | license='BSD', 67 | author='Armin Ronacher', 68 | author_email='armin.ronacher@active-4.com', 69 | description='The Swiss Army knife of Python web development', 70 | long_description=__doc__, 71 | classifiers=[ 72 | 'Development Status :: 5 - Production/Stable', 73 | 'Environment :: Web Environment', 74 | 'Intended Audience :: Developers', 75 | 'License :: OSI Approved :: BSD License', 76 | 'Operating System :: OS Independent', 77 | 'Programming Language :: Python', 78 | 'Programming Language :: Python :: 3', 79 | 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 80 | 'Topic :: Software Development :: Libraries :: Python Modules' 81 | ], 82 | packages=['werkzeug', 'werkzeug.debug', 'werkzeug.contrib', 83 | 'werkzeug.testsuite', 'werkzeug.testsuite.contrib'], 84 | include_package_data=True, 85 | test_suite='werkzeug.testsuite.suite', 86 | zip_safe=False, 87 | platforms='any' 88 | ) 89 | -------------------------------------------------------------------------------- /docs/deployment/mod_wsgi.rst: -------------------------------------------------------------------------------- 1 | =================== 2 | `mod_wsgi` (Apache) 3 | =================== 4 | 5 | If you are using the `Apache`_ webserver you should consider using `mod_wsgi`_. 6 | 7 | .. _Apache: http://httpd.apache.org/ 8 | 9 | Installing `mod_wsgi` 10 | ===================== 11 | 12 | If you don't have `mod_wsgi` installed yet you have to either install it using 13 | a package manager or compile it yourself. 14 | 15 | The mod_wsgi `installation instructions`_ cover installation instructions for 16 | source installations on UNIX systems. 17 | 18 | If you are using ubuntu / debian you can apt-get it and activate it as follows:: 19 | 20 | # apt-get install libapache2-mod-wsgi 21 | 22 | On FreeBSD install `mod_wsgi` by compiling the `www/mod_wsgi` port or by using 23 | pkg_add:: 24 | 25 | # pkg_add -r mod_wsgi 26 | 27 | If you are using pkgsrc you can install `mod_wsgi` by compiling the 28 | `www/ap2-wsgi` package. 29 | 30 | If you encounter segfaulting child processes after the first apache reload you 31 | can safely ignore them. Just restart the server. 32 | 33 | Creating a `.wsgi` file 34 | ======================= 35 | 36 | To run your application you need a `yourapplication.wsgi` file. This file 37 | contains the code `mod_wsgi` is executing on startup to get the application 38 | object. The object called `application` in that file is then used as 39 | application. 40 | 41 | For most applications the following file should be sufficient:: 42 | 43 | from yourapplication import make_app 44 | application = make_app() 45 | 46 | If you don't have a factory function for application creation but a singleton 47 | instance you can directly import that one as `application`. 48 | 49 | Store that file somewhere where you will find it again (eg: 50 | `/var/www/yourapplication`) and make sure that `yourapplication` and all 51 | the libraries that are in use are on the python load path. If you don't 52 | want to install it system wide consider using a `virtual python`_ instance. 53 | 54 | Configuring Apache 55 | ================== 56 | 57 | The last thing you have to do is to create an Apache configuration file for 58 | your application. In this example we are telling `mod_wsgi` to execute the 59 | application under a different user for security reasons: 60 | 61 | .. sourcecode:: apache 62 | 63 | 64 | ServerName example.com 65 | 66 | WSGIDaemonProcess yourapplication user=user1 group=group1 processes=2 threads=5 67 | WSGIScriptAlias / /var/www/yourapplication/yourapplication.wsgi 68 | 69 | 70 | WSGIProcessGroup yourapplication 71 | WSGIApplicationGroup %{GLOBAL} 72 | Order deny,allow 73 | Allow from all 74 | 75 | 76 | 77 | For more information consult the `mod_wsgi wiki`_. 78 | 79 | .. _mod_wsgi: http://code.google.com/p/modwsgi/ 80 | .. _installation instructions: http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide 81 | .. _virtual python: http://pypi.python.org/pypi/virtualenv 82 | .. _mod_wsgi wiki: http://code.google.com/p/modwsgi/wiki/ 83 | -------------------------------------------------------------------------------- /examples/i18nurls/application.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | from werkzeug.templates import Template 3 | from werkzeug.wrappers import BaseRequest, BaseResponse 4 | from werkzeug.routing import NotFound, RequestRedirect 5 | from werkzeug.exceptions import HTTPException, NotFound 6 | from i18nurls.urls import map 7 | 8 | TEMPLATES = path.join(path.dirname(__file__), 'templates') 9 | views = {} 10 | 11 | 12 | def expose(name): 13 | """Register the function as view.""" 14 | def wrapped(f): 15 | views[name] = f 16 | return f 17 | return wrapped 18 | 19 | 20 | class Request(BaseRequest): 21 | 22 | def __init__(self, environ, urls): 23 | super(Request, self).__init__(environ) 24 | self.urls = urls 25 | self.matched_url = None 26 | 27 | def url_for(self, endpoint, **args): 28 | if not 'lang_code' in args: 29 | args['lang_code'] = self.language 30 | if endpoint == 'this': 31 | endpoint = self.matched_url[0] 32 | tmp = self.matched_url[1].copy() 33 | tmp.update(args) 34 | args = tmp 35 | return self.urls.build(endpoint, args) 36 | 37 | 38 | class Response(BaseResponse): 39 | pass 40 | 41 | 42 | class TemplateResponse(Response): 43 | 44 | def __init__(self, template_name, **values): 45 | self.template_name = template_name 46 | self.template_values = values 47 | Response.__init__(self, mimetype='text/html') 48 | 49 | def __call__(self, environ, start_response): 50 | req = environ['werkzeug.request'] 51 | values = self.template_values.copy() 52 | values['req'] = req 53 | values['body'] = self.render_template(self.template_name, values) 54 | self.write(self.render_template('layout.html', values)) 55 | return Response.__call__(self, environ, start_response) 56 | 57 | def render_template(self, name, values): 58 | return Template.from_file(path.join(TEMPLATES, name)).render(values) 59 | 60 | 61 | class Application(object): 62 | 63 | def __init__(self): 64 | from i18nurls import views 65 | self.not_found = views.page_not_found 66 | 67 | def __call__(self, environ, start_response): 68 | urls = map.bind_to_environ(environ) 69 | req = Request(environ, urls) 70 | try: 71 | endpoint, args = urls.match(req.path) 72 | req.matched_url = (endpoint, args) 73 | if endpoint == '#language_select': 74 | lng = req.accept_languages.best 75 | lng = lng and lng.split('-')[0].lower() or 'en' 76 | index_url = urls.build('index', {'lang_code': lng}) 77 | resp = Response('Moved to %s' % index_url, status=302) 78 | resp.headers['Location'] = index_url 79 | else: 80 | req.language = args.pop('lang_code', None) 81 | resp = views[endpoint](req, **args) 82 | except NotFound: 83 | resp = self.not_found(req) 84 | except (RequestRedirect, HTTPException), e: 85 | resp = e 86 | return resp(environ, start_response) 87 | -------------------------------------------------------------------------------- /werkzeug/testsuite/internal.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.testsuite.internal 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Internal tests. 7 | 8 | :copyright: (c) 2013 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import unittest 12 | 13 | from datetime import datetime 14 | from warnings import filterwarnings, resetwarnings 15 | 16 | from werkzeug.testsuite import WerkzeugTestCase 17 | from werkzeug.wrappers import Request, Response 18 | 19 | from werkzeug import _internal as internal 20 | from werkzeug.test import create_environ 21 | 22 | 23 | class InternalTestCase(WerkzeugTestCase): 24 | 25 | def test_date_to_unix(self): 26 | assert internal._date_to_unix(datetime(1970, 1, 1)) == 0 27 | assert internal._date_to_unix(datetime(1970, 1, 1, 1, 0, 0)) == 3600 28 | assert internal._date_to_unix(datetime(1970, 1, 1, 1, 1, 1)) == 3661 29 | x = datetime(2010, 2, 15, 16, 15, 39) 30 | assert internal._date_to_unix(x) == 1266250539 31 | 32 | def test_easteregg(self): 33 | req = Request.from_values('/?macgybarchakku') 34 | resp = Response.force_type(internal._easteregg(None), req) 35 | assert b'About Werkzeug' in resp.get_data() 36 | assert b'the Swiss Army knife of Python web development' in resp.get_data() 37 | 38 | def test_wrapper_internals(self): 39 | req = Request.from_values(data={'foo': 'bar'}, method='POST') 40 | req._load_form_data() 41 | assert req.form.to_dict() == {'foo': 'bar'} 42 | 43 | # second call does not break 44 | req._load_form_data() 45 | assert req.form.to_dict() == {'foo': 'bar'} 46 | 47 | # check reprs 48 | assert repr(req) == "" 49 | resp = Response() 50 | assert repr(resp) == '' 51 | resp.set_data('Hello World!') 52 | assert repr(resp) == '' 53 | resp.response = iter(['Test']) 54 | assert repr(resp) == '' 55 | 56 | # unicode data does not set content length 57 | response = Response([u'Hällo Wörld']) 58 | headers = response.get_wsgi_headers(create_environ()) 59 | assert u'Content-Length' not in headers 60 | 61 | response = Response([u'Hällo Wörld'.encode('utf-8')]) 62 | headers = response.get_wsgi_headers(create_environ()) 63 | assert u'Content-Length' in headers 64 | 65 | # check for internal warnings 66 | filterwarnings('error', category=Warning) 67 | response = Response() 68 | environ = create_environ() 69 | response.response = 'What the...?' 70 | self.assert_raises(Warning, lambda: list(response.iter_encoded())) 71 | self.assert_raises(Warning, lambda: list(response.get_app_iter(environ))) 72 | response.direct_passthrough = True 73 | self.assert_raises(Warning, lambda: list(response.iter_encoded())) 74 | self.assert_raises(Warning, lambda: list(response.get_app_iter(environ))) 75 | resetwarnings() 76 | 77 | 78 | def suite(): 79 | suite = unittest.TestSuite() 80 | suite.addTest(unittest.makeSuite(InternalTestCase)) 81 | return suite 82 | -------------------------------------------------------------------------------- /docs/datastructures.rst: -------------------------------------------------------------------------------- 1 | =============== 2 | Data Structures 3 | =============== 4 | 5 | .. module:: werkzeug.datastructures 6 | 7 | Werkzeug provides some subclasses of common Python objects to extend them 8 | with additional features. Some of them are used to make them immutable, others 9 | are used to change some semantics to better work with HTTP. 10 | 11 | General Purpose 12 | =============== 13 | 14 | .. versionchanged:: 0.6 15 | The general purpose classes are now pickleable in each protocol as long 16 | as the contained objects are pickleable. This means that the 17 | :class:`FileMultiDict` won't be pickleable as soon as it contains a 18 | file. 19 | 20 | .. autoclass:: TypeConversionDict 21 | :members: 22 | 23 | .. autoclass:: ImmutableTypeConversionDict 24 | :members: copy 25 | 26 | .. autoclass:: MultiDict 27 | :members: 28 | :inherited-members: 29 | 30 | .. autoclass:: OrderedMultiDict 31 | 32 | .. autoclass:: ImmutableMultiDict 33 | :members: copy 34 | 35 | .. autoclass:: ImmutableOrderedMultiDict 36 | :members: copy 37 | 38 | .. autoclass:: CombinedMultiDict 39 | 40 | .. autoclass:: ImmutableDict 41 | :members: copy 42 | 43 | .. autoclass:: ImmutableList 44 | 45 | .. autoclass:: FileMultiDict 46 | :members: 47 | 48 | .. _http-datastructures: 49 | 50 | HTTP Related 51 | ============ 52 | 53 | .. autoclass:: Headers([defaults]) 54 | :members: 55 | 56 | .. autoclass:: EnvironHeaders 57 | 58 | .. autoclass:: HeaderSet 59 | :members: 60 | 61 | .. autoclass:: Accept 62 | :members: 63 | 64 | .. autoclass:: MIMEAccept 65 | :members: accept_html, accept_xhtml, accept_json 66 | 67 | .. autoclass:: CharsetAccept 68 | 69 | .. autoclass:: LanguageAccept 70 | 71 | .. autoclass:: RequestCacheControl 72 | :members: 73 | 74 | .. autoattribute:: no_cache 75 | 76 | .. autoattribute:: no_store 77 | 78 | .. autoattribute:: max_age 79 | 80 | .. autoattribute:: no_transform 81 | 82 | .. autoclass:: ResponseCacheControl 83 | :members: 84 | 85 | .. autoattribute:: no_cache 86 | 87 | .. autoattribute:: no_store 88 | 89 | .. autoattribute:: max_age 90 | 91 | .. autoattribute:: no_transform 92 | 93 | .. autoclass:: ETags 94 | :members: 95 | 96 | .. autoclass:: Authorization 97 | :members: 98 | 99 | .. autoclass:: WWWAuthenticate 100 | :members: 101 | 102 | .. autoclass:: IfRange 103 | :members: 104 | 105 | .. autoclass:: Range 106 | :members: 107 | 108 | .. autoclass:: ContentRange 109 | :members: 110 | 111 | 112 | Others 113 | ====== 114 | 115 | .. autoclass:: FileStorage 116 | :members: 117 | 118 | .. attribute:: stream 119 | 120 | The input stream for the uploaded file. This usually points to an 121 | open temporary file. 122 | 123 | .. attribute:: filename 124 | 125 | The filename of the file on the client. 126 | 127 | .. attribute:: name 128 | 129 | The name of the form field. 130 | 131 | .. attribute:: headers 132 | 133 | The multipart headers as :class:`Headers` object. This usually contains 134 | irrelevant information but in combination with custom multipart requests 135 | the raw headers might be interesting. 136 | 137 | .. versionadded:: 0.6 138 | -------------------------------------------------------------------------------- /examples/README: -------------------------------------------------------------------------------- 1 | ================= 2 | Werkzeug Examples 3 | ================= 4 | 5 | This directory contains various example applications and example code of 6 | Werkzeug powered applications. 7 | 8 | Beside the proof of concept applications and code snippets in the partial 9 | folder they all have external depencencies for template engines or database 10 | adapters (SQLAlchemy only so far). 11 | 12 | 13 | Full Example Applications 14 | ========================= 15 | 16 | The following example applications are application types you would actually 17 | find in real life :-) 18 | 19 | 20 | `simplewiki` 21 | A simple Wiki implementation. 22 | 23 | Requirements: 24 | - SQLAlchemy 25 | - Creoleparser >= 0.7 26 | - genshi 27 | 28 | You can obtain all packages in the Cheeseshop via easy_install. You have 29 | to have at least version 0.7 of Creoleparser. 30 | 31 | Usage:: 32 | 33 | ./manage-simplewiki.py initdb 34 | ./manage-simplewiki.py runserver 35 | 36 | Or of course you can just use the application object 37 | (`simplewiki.SimpleWiki`) and hook that into your favourite WSGI gateway. 38 | The constructor of the application object takes a single argument which is 39 | the SQLAlchemy URI for the database. 40 | 41 | The management script for the devserver looks up the an environment var 42 | called `SIMPLEWIKI_DATABASE_URI` and uses that for the database URI. If 43 | no such variable is provided "sqlite:////tmp/simplewiki.db" is assumed. 44 | 45 | `plnt` 46 | A planet called plnt, pronounce plant. 47 | 48 | Requirements: 49 | - SQLAlchemy 50 | - Jinja 51 | - feedparser 52 | 53 | You can obtain all packages in the Cheeseshop via easy_install. 54 | 55 | Usage:: 56 | 57 | ./manage-plnt.py initdb 58 | ./manage-plnt.py sync 59 | ./manage-plnt.py runserver 60 | 61 | The WSGI application is called `plnt.Plnt` which, like the simple wiki, 62 | accepts a database URI as first argument. The environment variable for 63 | the database key is called `PLNT_DATABASE_URI` and the default is 64 | "sqlite:////tmp/plnt.db". 65 | 66 | Per default a few python related blogs are added to the database, you 67 | can add more in a python shell by playing with the `Blog` model. 68 | 69 | `shorty` 70 | A tinyurl clone for the Werkzeug tutorial. 71 | 72 | Requirements: 73 | - SQLAlchemy 74 | - Jinja2 75 | 76 | You can obtain all packages in the Cheeseshop via easy_install. 77 | 78 | Usage:: 79 | 80 | ./manage-shorty.py initdb 81 | ./manage-shorty.py runserver 82 | 83 | The WSGI application is called `shorty.application.Shorty` which, like the 84 | simple wiki, accepts a database URI as first argument. 85 | 86 | The source code of the application is explained in detail in the Werkzeug 87 | tutorial. 88 | 89 | `couchy` 90 | Like shorty, but implemented using CouchDB. 91 | 92 | Requirements : 93 | - werkzeug : http://werkzeug.pocoo.org 94 | - jinja : http://jinja.pocoo.org 95 | - couchdb 0.72 & above : http://www.couchdb.org 96 | 97 | `cupoftee` 98 | A `Teeworlds `_ server browser. This application 99 | works best in a non forking environment and won't work for CGI. 100 | 101 | Usage:: 102 | 103 | ./manage-cupoftee.py runserver 104 | -------------------------------------------------------------------------------- /docs/local.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Context Locals 3 | ============== 4 | 5 | .. module:: werkzeug.local 6 | 7 | Sooner or later you have some things you want to have in every single view 8 | or helper function or whatever. In PHP the way to go are global 9 | variables. However, that isn't possible in WSGI applications without a 10 | major drawback: As soon as you operate on the global namespace your 11 | application isn't thread-safe any longer. 12 | 13 | The Python standard library comes with a utility called "thread locals". 14 | A thread local is a global object in which you can put stuff in and get back 15 | later in a thread-safe way. That means whenever you set or get an object 16 | on a thread local object, the thread local object checks in which 17 | thread you are and retrieves the correct value. 18 | 19 | This, however, has a few disadvantages. For example, besides threads there 20 | are other ways to handle concurrency in Python. A very popular approach 21 | is greenlets. Also, whether every request gets its own thread is not 22 | guaranteed in WSGI. It could be that a request is reusing a thread from 23 | before, and hence data is left in the thread local object. 24 | 25 | Here's a simple example of how one could use werkzeug.local:: 26 | 27 | from werkzeug.local import Local, LocalManager 28 | 29 | local = Local() 30 | local_manager = LocalManager([local]) 31 | 32 | def application(environ, start_response): 33 | local.request = request = Request(environ) 34 | ... 35 | 36 | application = local_manager.make_middleware(application) 37 | 38 | This binds the request to `local.request`. Every other piece of code executed 39 | after this assignment in the same context can safely access local.request and 40 | will get the same request object. The `make_middleware` method on the local 41 | manager ensures that all references to the local objects are cleared up after 42 | the request. 43 | 44 | The same context means the same greenlet (if you're using greenlets) in 45 | the same thread and same process. 46 | 47 | If a request object is not yet set on the local object and you try to 48 | access it, you will get an `AttributeError`. You can use `getattr` to avoid 49 | that:: 50 | 51 | def get_request(): 52 | return getattr(local, 'request', None) 53 | 54 | This will try to get the request or return `None` if the request is not 55 | (yet?) available. 56 | 57 | Note that local objects cannot manage themselves, for that you need a local 58 | manager. You can pass a local manager multiple locals or add additionals 59 | later by appending them to `manager.locals` and everytime the manager 60 | cleans up it will clean up all the data left in the locals for this 61 | context. 62 | 63 | .. autofunction:: release_local 64 | 65 | .. autoclass:: LocalManager 66 | :members: cleanup, make_middleware, middleware, get_ident 67 | 68 | .. autoclass:: LocalStack 69 | :members: push, pop, top 70 | 71 | .. autoclass:: LocalProxy 72 | :members: _get_current_object 73 | 74 | Keep in mind that ``repr()`` is also forwarded, so if you want to find 75 | out if you are dealing with a proxy you can do an ``isinstance()`` check: 76 | 77 | .. sourcecode:: pycon 78 | 79 | >>> from werkzeug.local import LocalProxy 80 | >>> isinstance(request, LocalProxy) 81 | True 82 | 83 | You can also create proxy objects by hand: 84 | 85 | .. sourcecode:: python 86 | 87 | from werkzeug.local import Local, LocalProxy 88 | local = Local() 89 | request = LocalProxy(local, 'request') 90 | -------------------------------------------------------------------------------- /examples/coolmagic/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | coolmagic.utils 4 | ~~~~~~~~~~~~~~~ 5 | 6 | This module contains the subclasses of the base request and response 7 | objects provided by werkzeug. The subclasses know about their charset 8 | and implement some additional functionallity like the ability to link 9 | to view functions. 10 | 11 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 12 | :license: BSD, see LICENSE for more details. 13 | """ 14 | from os.path import dirname, join 15 | from jinja import Environment, FileSystemLoader 16 | from werkzeug.local import Local, LocalManager 17 | from werkzeug.utils import redirect 18 | from werkzeug.wrappers import BaseRequest, BaseResponse 19 | 20 | 21 | local = Local() 22 | local_manager = LocalManager([local]) 23 | template_env = Environment( 24 | loader=FileSystemLoader(join(dirname(__file__), 'templates'), 25 | use_memcache=False) 26 | ) 27 | exported_views = {} 28 | 29 | 30 | def export(string, template=None, **extra): 31 | """ 32 | Decorator for registering view functions and adding 33 | templates to it. 34 | """ 35 | def wrapped(f): 36 | endpoint = (f.__module__ + '.' + f.__name__)[16:] 37 | if template is not None: 38 | old_f = f 39 | def f(**kwargs): 40 | rv = old_f(**kwargs) 41 | if not isinstance(rv, Response): 42 | rv = TemplateResponse(template, **(rv or {})) 43 | return rv 44 | f.__name__ = old_f.__name__ 45 | f.__doc__ = old_f.__doc__ 46 | exported_views[endpoint] = (f, string, extra) 47 | return f 48 | return wrapped 49 | 50 | 51 | def url_for(endpoint, **values): 52 | """ 53 | Build a URL 54 | """ 55 | return local.request.url_adapter.build(endpoint, values) 56 | 57 | 58 | class Request(BaseRequest): 59 | """ 60 | The concrete request object used in the WSGI application. 61 | It has some helper functions that can be used to build URLs. 62 | """ 63 | charset = 'utf-8' 64 | 65 | def __init__(self, environ, url_adapter): 66 | BaseRequest.__init__(self, environ) 67 | self.url_adapter = url_adapter 68 | local.request = self 69 | 70 | 71 | class ThreadedRequest(object): 72 | """ 73 | A pseudo request object that always poins to the current 74 | context active request. 75 | """ 76 | 77 | def __getattr__(self, name): 78 | if name == '__members__': 79 | return [x for x in dir(local.request) if not 80 | x.startswith('_')] 81 | return getattr(local.request, name) 82 | 83 | def __setattr__(self, name, value): 84 | return setattr(local.request, name, value) 85 | 86 | 87 | class Response(BaseResponse): 88 | """ 89 | The concrete response object for the WSGI application. 90 | """ 91 | charset = 'utf-8' 92 | default_mimetype = 'text/html' 93 | 94 | 95 | class TemplateResponse(Response): 96 | """ 97 | Render a template to a response. 98 | """ 99 | 100 | def __init__(self, template_name, **values): 101 | from coolmagic import helpers 102 | values.update( 103 | request=local.request, 104 | h=helpers 105 | ) 106 | template = template_env.get_template(template_name) 107 | Response.__init__(self, template.render(values)) 108 | -------------------------------------------------------------------------------- /examples/cookieauth.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Cookie Based Auth 5 | ~~~~~~~~~~~~~~~~~ 6 | 7 | This is a very simple application that uses a secure cookie to do the 8 | user authentification. 9 | 10 | :copyright: Copyright 2009 by the Werkzeug Team, see AUTHORS for more details. 11 | :license: BSD, see LICENSE for more details. 12 | """ 13 | from werkzeug.serving import run_simple 14 | from werkzeug.utils import cached_property, escape, redirect 15 | from werkzeug.wrappers import Request, Response 16 | from werkzeug.contrib.securecookie import SecureCookie 17 | 18 | 19 | # don't use this key but a different one; you could just use 20 | # os.unrandom(20) to get something random. Changing this key 21 | # invalidates all sessions at once. 22 | SECRET_KEY = '\xfa\xdd\xb8z\xae\xe0}4\x8b\xea' 23 | 24 | # the cookie name for the session 25 | COOKIE_NAME = 'session' 26 | 27 | # the users that may access 28 | USERS = { 29 | 'admin': 'default', 30 | 'user1': 'default' 31 | } 32 | 33 | 34 | class AppRequest(Request): 35 | """A request with a secure cookie session.""" 36 | 37 | def logout(self): 38 | """Log the user out.""" 39 | self.session.pop('username', None) 40 | 41 | def login(self, username): 42 | """Log the user in.""" 43 | self.session['username'] = username 44 | 45 | @property 46 | def logged_in(self): 47 | """Is the user logged in?""" 48 | return self.user is not None 49 | 50 | @property 51 | def user(self): 52 | """The user that is logged in.""" 53 | return self.session.get('username') 54 | 55 | @cached_property 56 | def session(self): 57 | data = self.cookies.get(COOKIE_NAME) 58 | if not data: 59 | return SecureCookie(secret_key=SECRET_KEY) 60 | return SecureCookie.unserialize(data, SECRET_KEY) 61 | 62 | 63 | def login_form(request): 64 | error = '' 65 | if request.method == 'POST': 66 | username = request.form.get('username') 67 | password = request.form.get('password') 68 | if password and USERS.get(username) == password: 69 | request.login(username) 70 | return redirect('') 71 | error = '

Invalid credentials' 72 | return Response(''' 73 | Login

Login

74 |

Not logged in. 75 | %s 76 |

77 |

78 | 79 | 80 | 81 | 82 |

''' % error, mimetype='text/html') 83 | 84 | 85 | def index(request): 86 | return Response(''' 87 | Logged in 88 |

Logged in

89 |

Logged in as %s 90 |

Logout 91 | ''' % escape(request.user), mimetype='text/html') 92 | 93 | 94 | @AppRequest.application 95 | def application(request): 96 | if request.args.get('do') == 'logout': 97 | request.logout() 98 | response = redirect('.') 99 | elif request.logged_in: 100 | response = index(request) 101 | else: 102 | response = login_form(request) 103 | request.session.save_cookie(response) 104 | return response 105 | 106 | 107 | if __name__ == '__main__': 108 | run_simple('localhost', 4000, application) 109 | -------------------------------------------------------------------------------- /werkzeug/testsuite/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.testsuite.exceptions 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | The tests for the exception classes. 7 | 8 | TODO: 9 | 10 | - This is undertested. HTML is never checked 11 | 12 | :copyright: (c) 2013 by Armin Ronacher. 13 | :license: BSD, see LICENSE for more details. 14 | """ 15 | import unittest 16 | 17 | from werkzeug.testsuite import WerkzeugTestCase 18 | 19 | from werkzeug import exceptions 20 | from werkzeug.wrappers import Response 21 | from werkzeug._compat import text_type 22 | 23 | 24 | class ExceptionsTestCase(WerkzeugTestCase): 25 | 26 | def test_proxy_exception(self): 27 | orig_resp = Response('Hello World') 28 | try: 29 | exceptions.abort(orig_resp) 30 | except exceptions.HTTPException as e: 31 | resp = e.get_response({}) 32 | else: 33 | self.fail('exception not raised') 34 | self.assert_true(resp is orig_resp) 35 | self.assert_equal(resp.get_data(), b'Hello World') 36 | 37 | def test_aborter(self): 38 | abort = exceptions.abort 39 | self.assert_raises(exceptions.BadRequest, abort, 400) 40 | self.assert_raises(exceptions.Unauthorized, abort, 401) 41 | self.assert_raises(exceptions.Forbidden, abort, 403) 42 | self.assert_raises(exceptions.NotFound, abort, 404) 43 | self.assert_raises(exceptions.MethodNotAllowed, abort, 405, ['GET', 'HEAD']) 44 | self.assert_raises(exceptions.NotAcceptable, abort, 406) 45 | self.assert_raises(exceptions.RequestTimeout, abort, 408) 46 | self.assert_raises(exceptions.Gone, abort, 410) 47 | self.assert_raises(exceptions.LengthRequired, abort, 411) 48 | self.assert_raises(exceptions.PreconditionFailed, abort, 412) 49 | self.assert_raises(exceptions.RequestEntityTooLarge, abort, 413) 50 | self.assert_raises(exceptions.RequestURITooLarge, abort, 414) 51 | self.assert_raises(exceptions.UnsupportedMediaType, abort, 415) 52 | self.assert_raises(exceptions.UnprocessableEntity, abort, 422) 53 | self.assert_raises(exceptions.InternalServerError, abort, 500) 54 | self.assert_raises(exceptions.NotImplemented, abort, 501) 55 | self.assert_raises(exceptions.BadGateway, abort, 502) 56 | self.assert_raises(exceptions.ServiceUnavailable, abort, 503) 57 | 58 | myabort = exceptions.Aborter({1: exceptions.NotFound}) 59 | self.assert_raises(LookupError, myabort, 404) 60 | self.assert_raises(exceptions.NotFound, myabort, 1) 61 | 62 | myabort = exceptions.Aborter(extra={1: exceptions.NotFound}) 63 | self.assert_raises(exceptions.NotFound, myabort, 404) 64 | self.assert_raises(exceptions.NotFound, myabort, 1) 65 | 66 | def test_exception_repr(self): 67 | exc = exceptions.NotFound() 68 | self.assert_equal(text_type(exc), '404: Not Found') 69 | self.assert_equal(repr(exc), "") 70 | 71 | exc = exceptions.NotFound('Not There') 72 | self.assert_equal(text_type(exc), '404: Not Found') 73 | self.assert_equal(repr(exc), "") 74 | 75 | def test_special_exceptions(self): 76 | exc = exceptions.MethodNotAllowed(['GET', 'HEAD', 'POST']) 77 | h = dict(exc.get_headers({})) 78 | self.assert_equal(h['Allow'], 'GET, HEAD, POST') 79 | self.assert_true('The method is not allowed' in exc.get_description()) 80 | 81 | 82 | def suite(): 83 | suite = unittest.TestSuite() 84 | suite.addTest(unittest.makeSuite(ExceptionsTestCase)) 85 | return suite 86 | -------------------------------------------------------------------------------- /werkzeug/testsuite/contrib/wrappers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.testsuite.contrib.wrappers 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Added tests for the sessions. 7 | 8 | :copyright: (c) 2013 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | 12 | from __future__ import with_statement 13 | 14 | import unittest 15 | 16 | from werkzeug.testsuite import WerkzeugTestCase 17 | 18 | from werkzeug.contrib import wrappers 19 | from werkzeug import routing 20 | from werkzeug.wrappers import Request, Response 21 | 22 | 23 | class WrappersTestCase(WerkzeugTestCase): 24 | 25 | def test_reverse_slash_behavior(self): 26 | class MyRequest(wrappers.ReverseSlashBehaviorRequestMixin, Request): 27 | pass 28 | req = MyRequest.from_values('/foo/bar', 'http://example.com/test') 29 | assert req.url == 'http://example.com/test/foo/bar' 30 | assert req.path == 'foo/bar' 31 | assert req.script_root == '/test/' 32 | 33 | # make sure the routing system works with the slashes in 34 | # reverse order as well. 35 | map = routing.Map([routing.Rule('/foo/bar', endpoint='foo')]) 36 | adapter = map.bind_to_environ(req.environ) 37 | assert adapter.match() == ('foo', {}) 38 | adapter = map.bind(req.host, req.script_root) 39 | assert adapter.match(req.path) == ('foo', {}) 40 | 41 | def test_dynamic_charset_request_mixin(self): 42 | class MyRequest(wrappers.DynamicCharsetRequestMixin, Request): 43 | pass 44 | env = {'CONTENT_TYPE': 'text/html'} 45 | req = MyRequest(env) 46 | assert req.charset == 'latin1' 47 | 48 | env = {'CONTENT_TYPE': 'text/html; charset=utf-8'} 49 | req = MyRequest(env) 50 | assert req.charset == 'utf-8' 51 | 52 | env = {'CONTENT_TYPE': 'application/octet-stream'} 53 | req = MyRequest(env) 54 | assert req.charset == 'latin1' 55 | assert req.url_charset == 'latin1' 56 | 57 | MyRequest.url_charset = 'utf-8' 58 | env = {'CONTENT_TYPE': 'application/octet-stream'} 59 | req = MyRequest(env) 60 | assert req.charset == 'latin1' 61 | assert req.url_charset == 'utf-8' 62 | 63 | def return_ascii(x): 64 | return "ascii" 65 | env = {'CONTENT_TYPE': 'text/plain; charset=x-weird-charset'} 66 | req = MyRequest(env) 67 | req.unknown_charset = return_ascii 68 | assert req.charset == 'ascii' 69 | assert req.url_charset == 'utf-8' 70 | 71 | def test_dynamic_charset_response_mixin(self): 72 | class MyResponse(wrappers.DynamicCharsetResponseMixin, Response): 73 | default_charset = 'utf-7' 74 | resp = MyResponse(mimetype='text/html') 75 | assert resp.charset == 'utf-7' 76 | resp.charset = 'utf-8' 77 | assert resp.charset == 'utf-8' 78 | assert resp.mimetype == 'text/html' 79 | assert resp.mimetype_params == {'charset': 'utf-8'} 80 | resp.mimetype_params['charset'] = 'iso-8859-15' 81 | assert resp.charset == 'iso-8859-15' 82 | resp.set_data(u'Hällo Wörld') 83 | assert b''.join(resp.iter_encoded()) == \ 84 | u'Hällo Wörld'.encode('iso-8859-15') 85 | del resp.headers['content-type'] 86 | try: 87 | resp.charset = 'utf-8' 88 | except TypeError as e: 89 | pass 90 | else: 91 | assert False, 'expected type error on charset setting without ct' 92 | 93 | 94 | def suite(): 95 | suite = unittest.TestSuite() 96 | suite.addTest(unittest.makeSuite(WrappersTestCase)) 97 | return suite 98 | -------------------------------------------------------------------------------- /docs/werkzeugstyle.sty: -------------------------------------------------------------------------------- 1 | \definecolor{TitleColor}{rgb}{0,0,0} 2 | \definecolor{InnerLinkColor}{rgb}{0,0,0} 3 | \definecolor{OuterLinkColor}{rgb}{1.0,0.5,0.0} 4 | 5 | \renewcommand{\maketitle}{% 6 | \begin{titlepage}% 7 | \let\footnotesize\small 8 | \let\footnoterule\relax 9 | \ifsphinxpdfoutput 10 | \begingroup 11 | % This \def is required to deal with multi-line authors; it 12 | % changes \\ to ', ' (comma-space), making it pass muster for 13 | % generating document info in the PDF file. 14 | \def\\{, } 15 | \pdfinfo{ 16 | /Author (\@author) 17 | /Title (\@title) 18 | } 19 | \endgroup 20 | \fi 21 | \begin{flushright}% 22 | %\sphinxlogo% 23 | {\center 24 | \vspace*{3cm} 25 | \includegraphics{logo.pdf} 26 | \vspace{3cm} 27 | \par 28 | {\rm\Huge \@title \par}% 29 | {\em\LARGE \py@release\releaseinfo \par} 30 | {\large 31 | \@date \par 32 | \py@authoraddress \par 33 | }}% 34 | \end{flushright}%\par 35 | \@thanks 36 | \end{titlepage}% 37 | \cleardoublepage% 38 | \setcounter{footnote}{0}% 39 | \let\thanks\relax\let\maketitle\relax 40 | %\gdef\@thanks{}\gdef\@author{}\gdef\@title{} 41 | } 42 | 43 | \fancypagestyle{normal}{ 44 | \fancyhf{} 45 | \fancyfoot[LE,RO]{{\thepage}} 46 | \fancyfoot[LO]{{\nouppercase{\rightmark}}} 47 | \fancyfoot[RE]{{\nouppercase{\leftmark}}} 48 | \fancyhead[LE,RO]{{ \@title, \py@release}} 49 | \renewcommand{\headrulewidth}{0.4pt} 50 | \renewcommand{\footrulewidth}{0.4pt} 51 | } 52 | 53 | \fancypagestyle{plain}{ 54 | \fancyhf{} 55 | \fancyfoot[LE,RO]{{\thepage}} 56 | \renewcommand{\headrulewidth}{0pt} 57 | \renewcommand{\footrulewidth}{0.4pt} 58 | } 59 | 60 | \titleformat{\section}{\Large}% 61 | {\py@TitleColor\thesection}{0.5em}{\py@TitleColor}{\py@NormalColor} 62 | \titleformat{\subsection}{\large}% 63 | {\py@TitleColor\thesubsection}{0.5em}{\py@TitleColor}{\py@NormalColor} 64 | \titleformat{\subsubsection}{}% 65 | {\py@TitleColor\thesubsubsection}{0.5em}{\py@TitleColor}{\py@NormalColor} 66 | \titleformat{\paragraph}{\large}% 67 | {\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor} 68 | 69 | \ChNameVar{\raggedleft\normalsize} 70 | \ChNumVar{\raggedleft \bfseries\Large} 71 | \ChTitleVar{\raggedleft \rm\Huge} 72 | 73 | \renewcommand\thepart{\@Roman\c@part} 74 | \renewcommand\part{% 75 | \pagestyle{plain} 76 | \if@noskipsec \leavevmode \fi 77 | \cleardoublepage 78 | \vspace*{6cm}% 79 | \@afterindentfalse 80 | \secdef\@part\@spart} 81 | 82 | \def\@part[#1]#2{% 83 | \ifnum \c@secnumdepth >\m@ne 84 | \refstepcounter{part}% 85 | \addcontentsline{toc}{part}{\thepart\hspace{1em}#1}% 86 | \else 87 | \addcontentsline{toc}{part}{#1}% 88 | \fi 89 | {\parindent \z@ %\center 90 | \interlinepenalty \@M 91 | \normalfont 92 | \ifnum \c@secnumdepth >\m@ne 93 | \rm\Large \partname~\thepart 94 | \par\nobreak 95 | \fi 96 | \MakeUppercase{\rm\Huge #2}% 97 | \markboth{}{}\par}% 98 | \nobreak 99 | \vskip 8ex 100 | \@afterheading} 101 | \def\@spart#1{% 102 | {\parindent \z@ %\center 103 | \interlinepenalty \@M 104 | \normalfont 105 | \huge \bfseries #1\par}% 106 | \nobreak 107 | \vskip 3ex 108 | \@afterheading} 109 | 110 | % use inconsolata font 111 | \usepackage{inconsolata} 112 | 113 | % fix single quotes, for inconsolata. (does not work) 114 | %%\usepackage{textcomp} 115 | %%\begingroup 116 | %% \catcode`'=\active 117 | %% \g@addto@macro\@noligs{\let'\textsinglequote} 118 | %% \endgroup 119 | %%\endinput 120 | -------------------------------------------------------------------------------- /werkzeug/testsuite/serving.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | werkzeug.testsuite.serving 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Added serving tests. 7 | 8 | :copyright: (c) 2013 by Armin Ronacher. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import sys 12 | import time 13 | try: 14 | import httplib 15 | except ImportError: 16 | from http import client as httplib 17 | try: 18 | from urllib2 import urlopen, HTTPError 19 | except ImportError: # pragma: no cover 20 | from urllib.request import urlopen 21 | from urllib.error import HTTPError 22 | 23 | import unittest 24 | from functools import update_wrapper 25 | 26 | from werkzeug.testsuite import WerkzeugTestCase 27 | 28 | from werkzeug import __version__ as version, serving 29 | from werkzeug.testapp import test_app 30 | from werkzeug._compat import StringIO 31 | from threading import Thread 32 | 33 | 34 | 35 | real_make_server = serving.make_server 36 | 37 | 38 | def silencestderr(f): 39 | def new_func(*args, **kwargs): 40 | old_stderr = sys.stderr 41 | sys.stderr = StringIO() 42 | try: 43 | return f(*args, **kwargs) 44 | finally: 45 | sys.stderr = old_stderr 46 | return update_wrapper(new_func, f) 47 | 48 | 49 | def run_dev_server(application): 50 | servers = [] 51 | 52 | def tracking_make_server(*args, **kwargs): 53 | srv = real_make_server(*args, **kwargs) 54 | servers.append(srv) 55 | return srv 56 | serving.make_server = tracking_make_server 57 | try: 58 | t = Thread(target=serving.run_simple, 59 | args=('localhost', 0, application)) 60 | t.setDaemon(True) 61 | t.start() 62 | time.sleep(0.25) 63 | finally: 64 | serving.make_server = real_make_server 65 | if not servers: 66 | return None, None 67 | server, = servers 68 | ip, port = server.socket.getsockname()[:2] 69 | if ':' in ip: 70 | ip = '[%s]' % ip 71 | return server, '%s:%d' % (ip, port) 72 | 73 | 74 | class ServingTestCase(WerkzeugTestCase): 75 | 76 | @silencestderr 77 | def test_serving(self): 78 | server, addr = run_dev_server(test_app) 79 | rv = urlopen('http://%s/?foo=bar&baz=blah' % addr).read() 80 | self.assert_in(b'WSGI Information', rv) 81 | self.assert_in(b'foo=bar&baz=blah', rv) 82 | self.assert_in(b'Werkzeug/' + version.encode('ascii'), rv) 83 | 84 | @silencestderr 85 | def test_broken_app(self): 86 | def broken_app(environ, start_response): 87 | 1 // 0 88 | server, addr = run_dev_server(broken_app) 89 | try: 90 | urlopen('http://%s/?foo=bar&baz=blah' % addr).read() 91 | except HTTPError as e: 92 | # In Python3 a 500 response causes an exception 93 | rv = e.read() 94 | assert b'Internal Server Error' in rv 95 | else: 96 | assert False, 'expected internal server error' 97 | 98 | @silencestderr 99 | def test_absolute_requests(self): 100 | def asserting_app(environ, start_response): 101 | assert environ['HTTP_HOST'] == 'surelynotexisting.example.com:1337' 102 | assert environ['PATH_INFO'] == '/index.htm' 103 | assert environ['SERVER_PORT'] == addr.split(':')[1] 104 | start_response('200 OK', [('Content-Type', 'text/html')]) 105 | return [b'YES'] 106 | 107 | server, addr = run_dev_server(asserting_app) 108 | conn = httplib.HTTPConnection(addr) 109 | conn.request('GET', 'http://surelynotexisting.example.com:1337/index.htm') 110 | res = conn.getresponse() 111 | assert res.read() == b'YES' 112 | 113 | 114 | def suite(): 115 | suite = unittest.TestSuite() 116 | suite.addTest(unittest.makeSuite(ServingTestCase)) 117 | return suite 118 | -------------------------------------------------------------------------------- /examples/cupoftee/application.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | cupoftee.application 4 | ~~~~~~~~~~~~~~~~~~~~ 5 | 6 | The WSGI appliction for the cup of tee browser. 7 | 8 | :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details. 9 | :license: BSD, see LICENSE for more details. 10 | """ 11 | import time 12 | from os import path 13 | from threading import Thread 14 | from cupoftee.db import Database 15 | from cupoftee.network import ServerBrowser 16 | from werkzeug.templates import Template 17 | from werkzeug.wrappers import Request, Response 18 | from werkzeug.wsgi import SharedDataMiddleware 19 | from werkzeug.exceptions import HTTPException, NotFound 20 | from werkzeug.routing import Map, Rule 21 | 22 | 23 | templates = path.join(path.dirname(__file__), 'templates') 24 | pages = {} 25 | url_map = Map([Rule('/shared/', endpoint='shared')]) 26 | 27 | 28 | def make_app(database, interval=60): 29 | return SharedDataMiddleware(Cup(database), { 30 | '/shared': path.join(path.dirname(__file__), 'shared') 31 | }) 32 | 33 | 34 | class PageMeta(type): 35 | 36 | def __init__(cls, name, bases, d): 37 | type.__init__(cls, name, bases, d) 38 | if d.get('url_rule') is not None: 39 | pages[cls.identifier] = cls 40 | url_map.add(Rule(cls.url_rule, endpoint=cls.identifier, 41 | **cls.url_arguments)) 42 | 43 | identifier = property(lambda x: x.__name__.lower()) 44 | 45 | 46 | class Page(object): 47 | __metaclass__ = PageMeta 48 | url_arguments = {} 49 | 50 | def __init__(self, cup, request, url_adapter): 51 | self.cup = cup 52 | self.request = request 53 | self.url_adapter = url_adapter 54 | 55 | def url_for(self, endpoint, **values): 56 | return self.url_adapter.build(endpoint, values) 57 | 58 | def process(self): 59 | pass 60 | 61 | def render_template(self, template=None): 62 | if template is None: 63 | template = self.__class__.identifier + '.html' 64 | context = dict(self.__dict__) 65 | context.update(url_for=self.url_for, self=self) 66 | body_tmpl = Template.from_file(path.join(templates, template)) 67 | layout_tmpl = Template.from_file(path.join(templates, 'layout.html')) 68 | context['body'] = body_tmpl.render(context) 69 | return layout_tmpl.render(context) 70 | 71 | def get_response(self): 72 | return Response(self.render_template(), mimetype='text/html') 73 | 74 | 75 | class Cup(object): 76 | 77 | def __init__(self, database, interval=120): 78 | self.interval = interval 79 | self.db = Database(database) 80 | self.master = ServerBrowser(self) 81 | self.updater = Thread(None, self.update_master) 82 | self.updater.setDaemon(True) 83 | self.updater.start() 84 | 85 | def update_master(self): 86 | wait = self.interval 87 | while 1: 88 | if self.master.sync(): 89 | wait = self.interval 90 | else: 91 | wait = self.interval // 2 92 | time.sleep(wait) 93 | 94 | def dispatch_request(self, request): 95 | url_adapter = url_map.bind_to_environ(request.environ) 96 | try: 97 | endpoint, values = url_adapter.match() 98 | page = pages[endpoint](self, request, url_adapter) 99 | response = page.process(**values) 100 | except NotFound, e: 101 | page = MissingPage(self, request, url_adapter) 102 | response = page.process() 103 | except HTTPException, e: 104 | return e 105 | return response or page.get_response() 106 | 107 | def __call__(self, environ, start_response): 108 | request = Request(environ) 109 | return self.dispatch_request(request)(environ, start_response) 110 | 111 | 112 | from cupoftee.pages import MissingPage 113 | --------------------------------------------------------------------------------