python package builds moved from awips2-builds to awips2-rpm

This commit is contained in:
Michael James 2017-10-30 16:18:55 -04:00
parent 4366ab886f
commit f6a269a9f2
1297 changed files with 22 additions and 157766 deletions

View file

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>pythonPackages</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.python.pydev.PyDevBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.python.pydev.pythonNature</nature>
</natures>
</projectDescription>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?>
<pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
</pydev_project>

View file

@ -1,3 +0,0 @@
#Sun Mar 20 15:17:07 CDT 2011
eclipse.preferences.version=1
encoding//werkzeug/examples/plnt/__init__.py=utf-8

View file

@ -1,6 +0,0 @@
The python packages dir exists solely for pure python packages.
NO JAVA/JEP CODE ALLOWED.
Each dir under this directory should be able to be copied to an installed python's
site-packages dir and function correctly, being able to be imported and used
as needed.

View file

@ -1,23 +0,0 @@
This file contains a listing of the versions of every applicable package.
This file SHOULD be updated whenever a newer version of a particular package is checked
in.
cherrpy = 3.1.2 [3.2.2]
dynamicserialize = RAYTHEON-OWNED (AWIPS II)
h5py = 1.3.0 [2.1.0]
matplotlib = 0.99.1.1 [1.2.0]
nose = 0.11.1 [1.2.1]
numpy = 1.5.0b1 [1.6.2]
pil = 1.1.6 [1.1.7]
pmw = 1.3.2 [2.0.0]
pupynere = 1.0.13 [1.0.15]
qpid = 0.5 [0.6]
scientific = 2.8 [2.8]
scipy = 0.8.0 [0.11.0]
tables = 2.1.2 [2.4.0]
thrift = 20080411p1 [0.9.0]
tpg = 3.1.2 [3.2.1]
ufpy = RAYTHEON-OWNED (AWIPS II)
werkzeug = 0.6.2 [0.8.3]
shapely = 1.2.16 [1.2.16]
msaslaps = RAYTHEON-OWNED (AWIPS II)

View file

@ -1,60 +0,0 @@
Werkzeug is written and maintained by the Werkzeug Team and various
contributors:
Project Leader / Developer:
- Armin Ronacher <armin.ronacher@active-4.com>
- Georg Brandl
- Leif K-Brooks <eurleif@gmail.com>
- Thomas Johansson
- Marian Sigler
- Ronny Pfannschmidt
- Noah Slater <nslater@tumbolia.org>
- Alec Thomas
- Shannon Behrens
- Christoph Rauch
- Clemens Hermann
- Jason Kirtland
- Ali Afshar
- Christopher Grebs <cg@webshox.org>
- Sean Cazzell <seancazzell@gmail.com>
- Florent Xicluna
- Kyle Dawkins
- Pedro Algarvio
- Zahari Petkov
- Ludvig Ericson
- Kenneth Reitz
- Daniel Neuhäuser
- Markus Unterwaditzer
- Joe Esposito <joe@joeyespo.com>
- Abhinav Upadhyay <er.abhinav.upadhyay@gmail.com>
- immerrr <immerrr@gmail.com>
- Cédric Krier
- Phil Jones
- Michael Hunsinger
- Lars Holm Nielsen
- Joël Charles
- Benjamin Dopplinger
Contributors of code for werkzeug/examples are:
- Itay Neeman <itay@neeman.net>
The SSL related parts of the Werkzeug development server are partially
taken from Paste. Same thing is true for the range support which comes
from WebOb which is a Paste project. The original code is MIT licensed which
is largely compatible with the modfied BSD license. The following copyrights
apply:
- (c) 2005 Ian Bicking and contributors
- (c) 2005 Clark C. Evans
The rename() function from the posixemulation was taken almost unmodified
from the Trac project's utility module. The original code is BSD licensed
with the following copyrights from that module:
- (c) 2003-2009 Edgewall Software
- (c) 2003-2006 Jonas Borgström <jonas@edgewall.com>
- (c) 2006 Matthew Good <trac@matt-good.net>
- (c) 2005-2006 Christian Boos <cboos@neuf.fr>

File diff suppressed because it is too large Load diff

View file

@ -1,29 +0,0 @@
Copyright (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,10 +0,0 @@
include Makefile CHANGES LICENSE AUTHORS
recursive-include werkzeug/debug/shared *
recursive-include tests *
recursive-include docs *
recursive-include artwork *
recursive-include examples *
prune docs/_build
prune docs/_themes
global-exclude *.py[cdo] __pycache__ *.so *.pyd

View file

@ -1,35 +0,0 @@
#
# Werkzeug Makefile
# ~~~~~~~~~~~~~~~~~
#
# Shortcuts for various tasks.
#
# :copyright: (c) 2008 by the Werkzeug Team, see AUTHORS for more details.
# :license: BSD, see LICENSE for more details.
#
documentation:
@(cd docs; make html)
release:
python scripts/make-release.py
test:
py.test --tb=native
tox-test:
tox
coverage:
@(coverage run --source=werkzeug --module py.test $(TEST_OPTIONS) $(TESTS))
doctest:
@(cd docs; sphinx-build -b doctest . _build/doctest)
upload-docs:
$(MAKE) -C docs html dirhtml latex
$(MAKE) -C docs/_build/latex all-pdf
cd docs/_build/; mv html werkzeug-docs; zip -r werkzeug-docs.zip werkzeug-docs; mv werkzeug-docs html
rsync -a docs/_build/dirhtml/ flow.srv.pocoo.org:/srv/websites/werkzeug.pocoo.org/docs/
rsync -a docs/_build/latex/Werkzeug.pdf flow.srv.pocoo.org:/srv/websites/werkzeug.pocoo.org/docs/
rsync -a docs/_build/werkzeug-docs.zip flow.srv.pocoo.org:/srv/websites/werkzeug.pocoo.org/docs/werkzeug-docs.zip

View file

@ -1,78 +0,0 @@
Metadata-Version: 1.1
Name: Werkzeug
Version: 0.12.1
Summary: The Swiss Army knife of Python web development
Home-page: http://werkzeug.pocoo.org/
Author: Armin Ronacher
Author-email: armin.ronacher@active-4.com
License: BSD
Description:
Werkzeug
========
Werkzeug started as simple collection of various utilities for WSGI
applications and has become one of the most advanced WSGI utility
modules. It includes a powerful debugger, full featured request and
response objects, HTTP utilities to handle entity tags, cache control
headers, HTTP dates, cookie handling, file uploads, a powerful URL
routing system and a bunch of community contributed addon modules.
Werkzeug is unicode aware and doesn't enforce a specific template
engine, database adapter or anything else. It doesn't even enforce
a specific way of handling requests and leaves all that up to the
developer. It's most useful for end user applications which should work
on as many server environments as possible (such as blogs, wikis,
bulletin boards, etc.).
Details and example applications are available on the
`Werkzeug website <http://werkzeug.pocoo.org/>`_.
Features
--------
- unicode awareness
- request and response objects
- various utility functions for dealing with HTTP headers such as
`Accept` and `Cache-Control` headers.
- thread local objects with proper cleanup at request end
- an interactive debugger
- A simple WSGI server with support for threading and forking
with an automatic reloader.
- a flexible URL routing system with REST support.
- fully WSGI compatible
Development Version
-------------------
The Werkzeug development version can be installed by cloning the git
repository from `github`_::
git clone git@github.com:pallets/werkzeug.git
.. _github: http://github.com/pallets/werkzeug
Platform: any
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules

View file

@ -1,40 +0,0 @@
Werkzeug
========
Werkzeug started as simple collection of various utilities for WSGI
applications and has become one of the most advanced WSGI utility
modules. It includes a powerful debugger, full-featured request and
response objects, HTTP utilities to handle entity tags, cache control
headers, HTTP dates, cookie handling, file uploads, a powerful URL
routing system and a bunch of community-contributed addon modules.
Werkzeug is unicode aware and doesn't enforce a specific template
engine, database adapter or anything else. It doesn't even enforce
a specific way of handling requests and leaves all that up to the
developer. It's most useful for end user applications which should work
on as many server environments as possible (such as blogs, wikis,
bulletin boards, etc.).
Details and example applications are available on the
`Werkzeug website <http://werkzeug.pocoo.org/>`_.
Branches
--------
+----------------------+-------------------------------------------------------------------------------+
| ``master`` | .. image:: https://travis-ci.org/pallets/werkzeug.svg?branch=master |
| | :target: https://travis-ci.org/pallets/werkzeug |
+----------------------+-------------------------------------------------------------------------------+
| ``0.12-maintenance`` | .. image:: https://travis-ci.org/pallets/werkzeug.svg?branch=0.12-maintenance |
| | :target: https://travis-ci.org/pallets/werkzeug |
+----------------------+-------------------------------------------------------------------------------+
| ``0.11-maintenance`` | .. image:: https://travis-ci.org/pallets/werkzeug.svg?branch=0.11-maintenance |
| | :target: https://travis-ci.org/pallets/werkzeug |
+----------------------+-------------------------------------------------------------------------------+
| ``0.10-maintenance`` | .. image:: https://travis-ci.org/pallets/werkzeug.svg?branch=0.10-maintenance |
| | :target: https://travis-ci.org/pallets/werkzeug |
+----------------------+-------------------------------------------------------------------------------+
| ``0.9-maintenance`` | .. image:: https://travis-ci.org/pallets/werkzeug.svg?branch=0.9-maintenance |
| | :target: https://travis-ci.org/pallets/werkzeug |
+----------------------+-------------------------------------------------------------------------------+

View file

@ -1,78 +0,0 @@
Metadata-Version: 1.1
Name: Werkzeug
Version: 0.12.1
Summary: The Swiss Army knife of Python web development
Home-page: http://werkzeug.pocoo.org/
Author: Armin Ronacher
Author-email: armin.ronacher@active-4.com
License: BSD
Description:
Werkzeug
========
Werkzeug started as simple collection of various utilities for WSGI
applications and has become one of the most advanced WSGI utility
modules. It includes a powerful debugger, full featured request and
response objects, HTTP utilities to handle entity tags, cache control
headers, HTTP dates, cookie handling, file uploads, a powerful URL
routing system and a bunch of community contributed addon modules.
Werkzeug is unicode aware and doesn't enforce a specific template
engine, database adapter or anything else. It doesn't even enforce
a specific way of handling requests and leaves all that up to the
developer. It's most useful for end user applications which should work
on as many server environments as possible (such as blogs, wikis,
bulletin boards, etc.).
Details and example applications are available on the
`Werkzeug website <http://werkzeug.pocoo.org/>`_.
Features
--------
- unicode awareness
- request and response objects
- various utility functions for dealing with HTTP headers such as
`Accept` and `Cache-Control` headers.
- thread local objects with proper cleanup at request end
- an interactive debugger
- A simple WSGI server with support for threading and forking
with an automatic reloader.
- a flexible URL routing system with REST support.
- fully WSGI compatible
Development Version
-------------------
The Werkzeug development version can be installed by cloning the git
repository from `github`_::
git clone git@github.com:pallets/werkzeug.git
.. _github: http://github.com/pallets/werkzeug
Platform: any
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules

View file

@ -1,292 +0,0 @@
AUTHORS
CHANGES
LICENSE
MANIFEST.in
Makefile
README.rst
setup.cfg
setup.py
Werkzeug.egg-info/PKG-INFO
Werkzeug.egg-info/SOURCES.txt
Werkzeug.egg-info/dependency_links.txt
Werkzeug.egg-info/not-zip-safe
Werkzeug.egg-info/requires.txt
Werkzeug.egg-info/top_level.txt
artwork/logo.png
artwork/logo.svg
docs/Makefile
docs/changes.rst
docs/conf.py
docs/contents.rst.inc
docs/datastructures.rst
docs/debug.rst
docs/exceptions.rst
docs/filesystem.rst
docs/http.rst
docs/index.rst
docs/installation.rst
docs/latexindex.rst
docs/levels.rst
docs/local.rst
docs/logo.pdf
docs/make.bat
docs/makearchive.py
docs/middlewares.rst
docs/python3.rst
docs/quickstart.rst
docs/request_data.rst
docs/routing.rst
docs/serving.rst
docs/terms.rst
docs/test.rst
docs/transition.rst
docs/tutorial.rst
docs/unicode.rst
docs/urls.rst
docs/utils.rst
docs/werkzeugext.py
docs/werkzeugstyle.sty
docs/wrappers.rst
docs/wsgi.rst
docs/_static/background.png
docs/_static/codebackground.png
docs/_static/contents.png
docs/_static/debug-screenshot.png
docs/_static/favicon.ico
docs/_static/header.png
docs/_static/navigation.png
docs/_static/navigation_active.png
docs/_static/shortly.png
docs/_static/shorty-screenshot.png
docs/_static/style.css
docs/_static/werkzeug.js
docs/_static/werkzeug.png
docs/_templates/sidebarintro.html
docs/_templates/sidebarlogo.html
docs/contrib/atom.rst
docs/contrib/cache.rst
docs/contrib/fixers.rst
docs/contrib/index.rst
docs/contrib/iterio.rst
docs/contrib/lint.rst
docs/contrib/profiler.rst
docs/contrib/securecookie.rst
docs/contrib/sessions.rst
docs/contrib/wrappers.rst
docs/deployment/cgi.rst
docs/deployment/fastcgi.rst
docs/deployment/index.rst
docs/deployment/mod_wsgi.rst
docs/deployment/proxying.rst
examples/README
examples/cookieauth.py
examples/httpbasicauth.py
examples/manage-coolmagic.py
examples/manage-couchy.py
examples/manage-cupoftee.py
examples/manage-i18nurls.py
examples/manage-plnt.py
examples/manage-shorty.py
examples/manage-simplewiki.py
examples/manage-webpylike.py
examples/upload.py
examples/contrib/README
examples/contrib/securecookie.py
examples/contrib/sessions.py
examples/coolmagic/__init__.py
examples/coolmagic/application.py
examples/coolmagic/helpers.py
examples/coolmagic/utils.py
examples/coolmagic/public/style.css
examples/coolmagic/templates/layout.html
examples/coolmagic/templates/static/about.html
examples/coolmagic/templates/static/index.html
examples/coolmagic/templates/static/not_found.html
examples/coolmagic/views/__init__.py
examples/coolmagic/views/static.py
examples/couchy/README
examples/couchy/__init__.py
examples/couchy/application.py
examples/couchy/models.py
examples/couchy/utils.py
examples/couchy/views.py
examples/couchy/static/style.css
examples/couchy/templates/display.html
examples/couchy/templates/layout.html
examples/couchy/templates/list.html
examples/couchy/templates/new.html
examples/couchy/templates/not_found.html
examples/cupoftee/__init__.py
examples/cupoftee/application.py
examples/cupoftee/db.py
examples/cupoftee/network.py
examples/cupoftee/pages.py
examples/cupoftee/utils.py
examples/cupoftee/shared/content.png
examples/cupoftee/shared/down.png
examples/cupoftee/shared/favicon.ico
examples/cupoftee/shared/header.png
examples/cupoftee/shared/logo.png
examples/cupoftee/shared/style.css
examples/cupoftee/shared/up.png
examples/cupoftee/templates/layout.html
examples/cupoftee/templates/missingpage.html
examples/cupoftee/templates/search.html
examples/cupoftee/templates/server.html
examples/cupoftee/templates/serverlist.html
examples/i18nurls/__init__.py
examples/i18nurls/application.py
examples/i18nurls/urls.py
examples/i18nurls/views.py
examples/i18nurls/templates/about.html
examples/i18nurls/templates/blog.html
examples/i18nurls/templates/index.html
examples/i18nurls/templates/layout.html
examples/partial/README
examples/partial/complex_routing.py
examples/plnt/__init__.py
examples/plnt/database.py
examples/plnt/sync.py
examples/plnt/utils.py
examples/plnt/views.py
examples/plnt/webapp.py
examples/plnt/shared/style.css
examples/plnt/templates/about.html
examples/plnt/templates/index.html
examples/plnt/templates/layout.html
examples/shortly/shortly.py
examples/shortly/static/style.css
examples/shortly/templates/404.html
examples/shortly/templates/layout.html
examples/shortly/templates/new_url.html
examples/shortly/templates/short_link_details.html
examples/shorty/__init__.py
examples/shorty/application.py
examples/shorty/models.py
examples/shorty/utils.py
examples/shorty/views.py
examples/shorty/static/style.css
examples/shorty/templates/display.html
examples/shorty/templates/layout.html
examples/shorty/templates/list.html
examples/shorty/templates/new.html
examples/shorty/templates/not_found.html
examples/simplewiki/__init__.py
examples/simplewiki/actions.py
examples/simplewiki/application.py
examples/simplewiki/database.py
examples/simplewiki/specialpages.py
examples/simplewiki/utils.py
examples/simplewiki/shared/style.css
examples/simplewiki/templates/action_diff.html
examples/simplewiki/templates/action_edit.html
examples/simplewiki/templates/action_log.html
examples/simplewiki/templates/action_revert.html
examples/simplewiki/templates/action_show.html
examples/simplewiki/templates/layout.html
examples/simplewiki/templates/macros.xml
examples/simplewiki/templates/missing_action.html
examples/simplewiki/templates/page_index.html
examples/simplewiki/templates/page_missing.html
examples/simplewiki/templates/recent_changes.html
examples/webpylike/example.py
examples/webpylike/webpylike.py
tests/__init__.py
tests/conftest.py
tests/test_compat.py
tests/test_datastructures.py
tests/test_debug.py
tests/test_exceptions.py
tests/test_formparser.py
tests/test_http.py
tests/test_internal.py
tests/test_local.py
tests/test_routing.py
tests/test_security.py
tests/test_serving.py
tests/test_test.py
tests/test_urls.py
tests/test_utils.py
tests/test_wrappers.py
tests/test_wsgi.py
tests/contrib/__init__.py
tests/contrib/test_atom.py
tests/contrib/test_cache.py
tests/contrib/test_fixers.py
tests/contrib/test_iterio.py
tests/contrib/test_securecookie.py
tests/contrib/test_sessions.py
tests/contrib/test_wrappers.py
tests/hypothesis/__init__.py
tests/hypothesis/test_urls.py
tests/multipart/ie7_full_path_request.txt
tests/multipart/test_collect.py
tests/multipart/firefox3-2png1txt/file1.png
tests/multipart/firefox3-2png1txt/file2.png
tests/multipart/firefox3-2png1txt/request.txt
tests/multipart/firefox3-2png1txt/text.txt
tests/multipart/firefox3-2pnglongtext/file1.png
tests/multipart/firefox3-2pnglongtext/file2.png
tests/multipart/firefox3-2pnglongtext/request.txt
tests/multipart/firefox3-2pnglongtext/text.txt
tests/multipart/ie6-2png1txt/file1.png
tests/multipart/ie6-2png1txt/file2.png
tests/multipart/ie6-2png1txt/request.txt
tests/multipart/ie6-2png1txt/text.txt
tests/multipart/opera8-2png1txt/file1.png
tests/multipart/opera8-2png1txt/file2.png
tests/multipart/opera8-2png1txt/request.txt
tests/multipart/opera8-2png1txt/text.txt
tests/multipart/webkit3-2png1txt/file1.png
tests/multipart/webkit3-2png1txt/file2.png
tests/multipart/webkit3-2png1txt/request.txt
tests/multipart/webkit3-2png1txt/text.txt
tests/res/test.txt
werkzeug/__init__.py
werkzeug/_compat.py
werkzeug/_internal.py
werkzeug/_reloader.py
werkzeug/datastructures.py
werkzeug/exceptions.py
werkzeug/filesystem.py
werkzeug/formparser.py
werkzeug/http.py
werkzeug/local.py
werkzeug/posixemulation.py
werkzeug/routing.py
werkzeug/script.py
werkzeug/security.py
werkzeug/serving.py
werkzeug/test.py
werkzeug/testapp.py
werkzeug/urls.py
werkzeug/useragents.py
werkzeug/utils.py
werkzeug/wrappers.py
werkzeug/wsgi.py
werkzeug/contrib/__init__.py
werkzeug/contrib/atom.py
werkzeug/contrib/cache.py
werkzeug/contrib/fixers.py
werkzeug/contrib/iterio.py
werkzeug/contrib/jsrouting.py
werkzeug/contrib/limiter.py
werkzeug/contrib/lint.py
werkzeug/contrib/profiler.py
werkzeug/contrib/securecookie.py
werkzeug/contrib/sessions.py
werkzeug/contrib/testtools.py
werkzeug/contrib/wrappers.py
werkzeug/debug/__init__.py
werkzeug/debug/console.py
werkzeug/debug/repr.py
werkzeug/debug/tbtools.py
werkzeug/debug/shared/FONT_LICENSE
werkzeug/debug/shared/console.png
werkzeug/debug/shared/debugger.js
werkzeug/debug/shared/jquery.js
werkzeug/debug/shared/less.png
werkzeug/debug/shared/more.png
werkzeug/debug/shared/source.png
werkzeug/debug/shared/style.css
werkzeug/debug/shared/ubuntu.ttf

View file

@ -1,6 +0,0 @@
[termcolor]
termcolor
[watchdog]
watchdog

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 16 KiB

View file

@ -1,118 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp epub latex changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Flask.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Flask.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) _build/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Flask"
@echo "# ln -s _build/devhelp $$HOME/.local/share/devhelp/Flask"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
latexpdf: latex
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex
@echo "Running LaTeX files through pdflatex..."
make -C _build/latex all-pdf
@echo "pdflatex finished; the PDF files are in _build/latex."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

View file

@ -1,423 +0,0 @@
body {
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif;
font-size: 14px;
letter-spacing: -0.01em;
line-height: 150%;
text-align: center;
background: #AFC1C4 url(background.png);
color: black;
margin: 0;
padding: 0;
}
a {
color: #CA7900;
text-decoration: none;
}
a:hover {
color: #2491CF;
}
pre {
font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
font-size: 0.85em;
letter-spacing: 0.015em;
padding: 0.3em 0.7em;
border: 1px solid #aaa;
border-right-color: #ddd;
border-bottom-color: #ddd;
background: #f8f8f8 url(codebackground.png);
}
cite, code, tt {
font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
font-size: 0.95em;
letter-spacing: 0.01em;
font-style: normal;
}
tt {
background-color: #f2f2f2;
border-bottom: 1px solid #ddd;
color: #333;
}
tt.func-signature {
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif;
font-size: 0.85em;
background-color: transparent;
border-bottom: none;
color: #555;
}
dt {
margin-top: 0.8em;
}
dd p.first {
margin-top: 0;
}
dd p.last {
margin-bottom: 0;
}
pre {
line-height: 150%;
}
pre a {
color: inherit;
text-decoration: underline;
}
div.syntax {
background-color: transparent;
}
div.page {
background: white url(contents.png) 0 130px;
border: 1px solid #aaa;
width: 740px;
margin: 20px auto 20px auto;
text-align: left;
}
div.header {
background-image: url(header.png);
height: 100px;
border-bottom: 1px solid #aaa;
}
div.header h1 {
float: right;
position: absolute;
margin: -43px 0 0 585px;
height: 180px;
width: 180px;
}
div.header h1 a {
display: block;
background-image: url(werkzeug.png);
background-repeat: no-repeat;
height: 180px;
width: 180px;
text-decoration: none;
color: white!important;
}
div.header span {
display: none;
}
div.header p {
background-image: url(header_invert.png);
margin: 0;
padding: 10px;
height: 80px;
color: white;
display: none;
}
ul.navigation {
background-image: url(navigation.png);
height: 2em;
list-style: none;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 0;
padding: 0;
}
ul.navigation li {
margin: 0;
padding: 0;
height: 2em;
line-height: 1.75em;
float: left;
}
ul.navigation li a {
margin: 0;
padding: 0 10px 0 10px;
color: #EE9816;
}
ul.navigation li a:hover {
color: #3CA8E7;
}
ul.navigation li.active {
background-image: url(navigation_active.png);
}
ul.navigation li.active a {
color: black;
}
ul.navigation li.indexlink a {
font-size: 0.9em;
font-weight: bold;
color: #11557C;
}
div.body {
margin: 0 20px 0 20px;
padding: 0.5em 0 20px 0;
}
p {
margin: 0.8em 0 0.5em 0;
}
h1 {
margin: 0;
padding: 0.7em 0 0.3em 0;
font-size: 1.5em;
color: #11557C;
}
h2 {
margin: 1.3em 0 0.2em 0;
font-size: 1.35em;
padding: 0;
}
h3 {
margin: 1em 0 -0.3em 0;
}
h2 a, h3 a, h4 a, h5 a, h6 a {
color: black!important;
}
a.headerlink {
color: #B4B4B4!important;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none!important;
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
a.headerlink:hover {
background-color: #B4B4B4;
color: #F0F0F0!important;
}
table {
border-collapse: collapse;
margin: 0 -0.5em 0 -0.5em;
}
table td, table th {
padding: 0.2em 0.5em 0.2em 0.5em;
}
div.footer {
background-color: #E3EFF1;
color: #86989B;
padding: 3px 8px 3px 0;
clear: both;
font-size: 0.8em;
text-align: right;
}
div.footer a {
color: #86989B;
text-decoration: underline;
}
div.toc {
float: right;
background-color: white;
border: 1px solid #86989B;
padding: 0;
margin: 0 0 1em 1em;
width: 10em;
}
div.toc h4 {
margin: 0;
font-size: 0.9em;
padding: 0.1em 0 0.1em 0.6em;
margin: 0;
color: white;
border-bottom: 1px solid #86989B;
background-color: #AFC1C4;
}
div.toc ul {
margin: 1em 0 1em 0;
padding: 0 0 0 1em;
list-style: none;
}
div.toc ul li {
margin: 0.5em 0 0.5em 0;
font-size: 0.9em;
line-height: 130%;
}
div.toc ul li p {
margin: 0;
padding: 0;
}
div.toc ul ul {
margin: 0.2em 0 0.2em 0;
padding: 0 0 0 1.8em;
}
div.toc ul ul li {
padding: 0;
}
div.admonition, div.warning, div#toc {
font-size: 0.9em;
margin: 1em 0 0 0;
border: 1px solid #86989B;
background-color: #f7f7f7;
}
div.admonition p, div.warning p, div#toc p {
margin: 0.5em 1em 0.5em 1em;
padding: 0;
}
div.admonition pre, div.warning pre, div#toc pre {
margin: 0.4em 1em 0.4em 1em;
}
div.admonition p.admonition-title,
div.warning p.admonition-title,
div#toc h3 {
margin: 0;
padding: 0.1em 0 0.1em 0.5em;
color: white;
border-bottom: 1px solid #86989B;
font-weight: bold;
background-color: #AFC1C4;
}
div.warning {
border: 1px solid #940000;
}
div.warning p.admonition-title {
background-color: #CF0000;
border-bottom-color: #940000;
}
div.admonition ul, div.admonition ol,
div.warning ul, div.warning ol,
div#toc ul, div#toc ol {
margin: 0.1em 0.5em 0.5em 3em;
padding: 0;
}
div#toc div.inner {
border-top: 1px solid #86989B;
padding: 10px;
}
div#toc h3 {
border-bottom: none;
cursor: pointer;
font-size: 13px;
}
div#toc h3:hover {
background-color: #86989B;
}
div#toc ul {
margin: 2px 0 2px 20px;
padding: 0;
}
div#toc ul li {
line-height: 125%;
}
dl.function dt,
dl.class dt,
dl.exception dt,
dl.method dt,
dl.attribute dt {
font-weight: normal;
}
dt .descname {
font-weight: bold;
margin-right: 4px;
}
dt .descname, dt .descclassname {
padding: 0;
background: transparent;
border-bottom: 1px solid #111;
}
dt .descclassname {
margin-left: 2px;
}
dl dt big {
font-size: 100%;
}
dl p {
margin: 0;
}
dl p + p {
margin-top: 10px;
}
span.versionmodified {
color: #4B4A49;
font-weight: bold;
}
span.versionadded {
color: #30691A;
font-weight: bold;
}
table.field-list td.field-body ul.simple {
margin: 0;
padding: 0!important;
list-style: none;
}
table.indextable td {
width: 50%;
vertical-align: top;
}
table.indextable dt {
margin: 0;
}
table.indextable dd dt a {
color: black!important;
font-size: 0.8em;
}
div.jumpbox {
padding: 1em 0 0.4em 0;
border-bottom: 1px solid #ddd;
color: #aaa;
}

View file

@ -1,10 +0,0 @@
(function() {
Werkzeug = {};
$(function() {
$('#toc h3').click(function() {
$(this).next().slideToggle();
$(this).parent().toggleClass('toc-collapsed');
}).next().hide().parent().addClass('toc-collapsed');
});
})();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View file

@ -1,19 +0,0 @@
<h3>About Werkzeug</h3>
<p>
Werkzeug is a WSGI utility library. It can serve as the basis for a
custom framework.
</p>
<h3>Other Formats</h3>
<p>
You can download the documentation in other formats as well:
</p>
<ul>
<li><a href="http://werkzeug.pocoo.org/docs/werkzeug-docs.pdf">as PDF</a>
<li><a href="http://werkzeug.pocoo.org/docs/werkzeug-docs.zip">as zipped HTML</a>
</ul>
<h3>Useful Links</h3>
<ul>
<li><a href="http://werkzeug.pocoo.org/">The Werkzeug Website</a></li>
<li><a href="http://pypi.python.org/pypi/Werkzeug">Werkzeug @ PyPI</a></li>
<li><a href="http://github.com/pallets/werkzeug">Werkzeug @ github</a></li>
</ul>

View file

@ -1,3 +0,0 @@
<p class="logo"><a href="{{ pathto(master_doc) }}">
<img class="logo" src="{{ pathto('_static/werkzeug.png', 1) }}" alt="Logo"/>
</a></p>

View file

@ -1,109 +0,0 @@
==================
Werkzeug Changelog
==================
.. module:: werkzeug
This file lists all major changes in Werkzeug over the versions.
For API breaking changes have a look at :ref:`api-changes`, they
are listed there in detail.
.. include:: ../CHANGES
.. _api-changes:
API Changes
===========
`0.9`
- Soft-deprecated the :attr:`BaseRequest.data` and
:attr:`BaseResponse.data` attributes and introduced new methods
to interact with entity data. This will allows in the future to
make better APIs to deal with request and response entity
bodies. So far there is no deprecation warning but users are
strongly encouraged to update.
- The :class:`Headers` and :class:`EnvironHeaders` datastructures
are now designed to operate on unicode data. This is a backwards
incompatible change and was necessary for the Python 3 support.
- The :class:`Headers` object no longer supports in-place operations
through the old ``linked`` method. This has been removed without
replacement due to changes on the encoding model.
`0.6.2`
- renamed the attribute `implicit_seqence_conversion` attribute of
the request object to `implicit_sequence_conversion`. Because
this is a feature that is typically unused and was only in there
for the 0.6 series we consider this a bug that does not require
backwards compatibility support which would be impossible to
properly implement.
`0.6`
- Old deprecations were removed.
- `cached_property.writeable` was deprecated.
- :meth:`BaseResponse.get_wsgi_headers` replaces the older
`BaseResponse.fix_headers` method. The older method stays
around for backwards compatibility reasons until 0.7.
- `BaseResponse.header_list` was deprecated. You should not
need this function, `get_wsgi_headers` and the `to_list`
method on the regular headers should serve as a replacement.
- Deprecated `BaseResponse.iter_encoded`'s charset parameter.
- :class:`LimitedStream` non-silent usage was deprecated.
- the `__repr__` of HTTP exceptions changed. This might break
doctests.
`0.5`
- Werkzeug switched away from wsgiref as library for the builtin
webserver.
- The `encoding` parameter for :class:`Template`\s is now called
`charset`. The older one will work for another two versions
but warn with a :exc:`DeprecationWarning`.
- The :class:`Client` has cookie support now which is enabled
by default.
- :meth:`BaseResponse._get_file_stream` is now passed more parameters
to make the function more useful. In 0.6 the old way to invoke
the method will no longer work. To support both newer and older
Werkzeug versions you can add all arguments to the signature and
provide default values for each of them.
- :func:`url_decode` no longer supports both `&` and `;` as
separator. This has to be specified explicitly now.
- The request object is now enforced to be read-only for all
attributes. If your code relies on modifications of some values
makes sure to create copies of them using the mutable counterparts!
- Some data structures that were only used on request objects are
now immutable as well. (:class:`Authorization` / :class:`Accept`
and subclasses)
- `CacheControl` was split up into :class:`RequestCacheControl`
and :class:`ResponseCacheControl`, the former being immutable.
The old class will go away in 0.6
- undocumented `werkzeug.test.File` was replaced by
:class:`FileWrapper`.
- it's not longer possible to pass dicts inside the `data` dict
in :class:`Client`. Use tuples instead.
- It's save to modify the return value of :meth:`MultiDict.getlist`
and methods that return lists in the :class:`MultiDict` now. The
class creates copies instead of revealing the internal lists.
However :class:`MultiDict.setlistdefault` still (and intentionally)
returns the internal list for modifications.
`0.3`
- Werkzeug 0.3 will be the last release with Python 2.3 compatibility.
- The `environ_property` is now read-only by default. This decision was
made because the request in general should be considered read-only.
`0.2`
- The `BaseReporterStream` is now part of the contrib module, the
new module is `werkzeug.contrib.reporterstream`. Starting with
`0.3`, the old import will not work any longer.
- `RequestRedirect` now uses a 301 status code. Previously a 302
status code was used incorrectly. If you want to continue using
this 302 code, use ``response = redirect(e.new_url, 302)``.
- `lazy_property` is now called `cached_property`. The alias for
the old name will disappear in Werkzeug 0.3.
- `match` can now raise `MethodNotAllowed` if configured for
methods and there was no method for that request.
- The `response_body` attribute on the response object is now called
`data`. With Werkzeug 0.3 the old name will not work any longer.
- The file-like methods on the response object are deprecated. If
you want to use the response object as file like object use the
`Response` class or a subclass of `BaseResponse` and mix the new
`ResponseStreamMixin` class and use `response.stream`.

View file

@ -1,214 +0,0 @@
# -*- coding: utf-8 -*-
#
# Werkzeug documentation build configuration file, created by
# sphinx-quickstart on Fri Jan 16 23:10:43 2009.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# The contents of this file are pickled, so don't put values in the namespace
# that aren't pickleable (module imports are okay, they're removed automatically).
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If your extensions are in another directory, add it here. If the directory
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
sys.path.append(os.path.abspath('.'))
sys.path.append(os.path.abspath('_themes'))
# General configuration
# ---------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
'sphinx.ext.doctest', 'werkzeugext']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Werkzeug'
copyright = u'2011, The Werkzeug Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
import re
try:
import werkzeug
except ImportError:
sys.path.append(os.path.abspath('../'))
from werkzeug import __version__ as release
if 'dev' in release:
release = release[:release.find('dev') + 3]
if release == 'unknown':
version = release
else:
version = re.match(r'\d+\.\d+(?:\.\d+)?', release).group()
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'werkzeug_theme_support.WerkzeugStyle'
# doctest setup code
doctest_global_setup = '''\
from werkzeug import *
'''
# Options for HTML output
# -----------------------
html_theme = 'werkzeug'
html_theme_path = ['_themes']
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
html_sidebars = {
'index': ['sidebarlogo.html', 'sidebarintro.html', 'sourcelink.html',
'searchbox.html'],
'**': ['sidebarlogo.html', 'localtoc.html', 'relations.html',
'sourcelink.html', 'searchbox.html']
}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'Werkzeugdoc'
# Options for LaTeX output
# ------------------------
# The paper size ('letter' or 'a4').
latex_paper_size = 'a4'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, document class [howto/manual]).
latex_documents = [
('latexindex', 'Werkzeug.tex', ur'Werkzeug Documentation',
ur'The Werkzeug Team', 'manual'),
]
# Additional stuff for LaTeX
latex_elements = {
'fontpkg': r'\usepackage{mathpazo}',
'papersize': 'a4paper',
'pointsize': '12pt',
'preamble': r'''
\usepackage{werkzeugstyle}
% i hate you latex, here too
\DeclareUnicodeCharacter{2603}{\\N\{SNOWMAN\}}
'''
}
latex_use_parts = True
latex_additional_files = ['werkzeugstyle.sty', 'logo.pdf']
latex_use_modindex = False
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
'http://docs.python.org/dev': None,
'http://docs.sqlalchemy.org/en/latest/': None
}

View file

@ -1,85 +0,0 @@
Getting Started
---------------
If you are new to Werkzeug or WSGI development in general you
should start here.
.. toctree::
:maxdepth: 2
installation
transition
tutorial
levels
quickstart
python3
Serving and Testing
-------------------
The development server and testing support and management script
utilities are covered here:
.. toctree::
:maxdepth: 2
serving
test
debug
Reference
---------
.. toctree::
:maxdepth: 2
wrappers
routing
wsgi
filesystem
http
datastructures
utils
urls
local
middlewares
exceptions
Deployment
----------
This section covers running your application in production on a web
server such as Apache or lighttpd.
.. toctree::
:maxdepth: 3
deployment/index
Contributed Modules
-------------------
A lot of useful code contributed by the community is shipped with Werkzeug
as part of the `contrib` module:
.. toctree::
:maxdepth: 3
contrib/index
Additional Information
----------------------
.. toctree::
:maxdepth: 2
terms
unicode
request_data
changes
If you cant find the information youre looking for, have a look at the
index or try to find it using the search function:
* :ref:`genindex`
* :ref:`search`

View file

@ -1,10 +0,0 @@
================
Atom Syndication
================
.. automodule:: werkzeug.contrib.atom
.. autoclass:: AtomFeed
:members:
.. autoclass:: FeedEntry

View file

@ -1,36 +0,0 @@
=====
Cache
=====
.. automodule:: werkzeug.contrib.cache
Cache System API
================
.. autoclass:: BaseCache
:members:
Cache Systems
=============
.. autoclass:: NullCache
.. autoclass:: SimpleCache
.. autoclass:: MemcachedCache
.. class:: GAEMemcachedCache
This class is deprecated in favour of :class:`MemcachedCache` which
now supports Google Appengine as well.
.. versionchanged:: 0.8
Deprecated in favour of :class:`MemcachedCache`.
.. autoclass:: RedisCache
.. autoclass:: FileSystemCache
.. autoclass:: UWSGICache

View file

@ -1,16 +0,0 @@
======
Fixers
======
.. automodule:: werkzeug.contrib.fixers
.. autoclass:: CGIRootFix
.. autoclass:: PathInfoFromRequestUriFix
.. autoclass:: ProxyFix
:members:
.. autoclass:: HeaderRewriterFix
.. autoclass:: InternetExplorerFix

View file

@ -1,19 +0,0 @@
===================
Contributed Modules
===================
A lot of useful code contributed by the community is shipped with Werkzeug
as part of the `contrib` module:
.. toctree::
:maxdepth: 2
atom
sessions
securecookie
cache
wrappers
iterio
fixers
profiler
lint

View file

@ -1,8 +0,0 @@
=======
Iter IO
=======
.. automodule:: werkzeug.contrib.iterio
.. autoclass:: IterIO
:members:

View file

@ -1,9 +0,0 @@
==========================
Lint Validation Middleware
==========================
.. currentmodule:: werkzeug.contrib.lint
.. automodule:: werkzeug.contrib.lint
.. autoclass:: LintMiddleware

View file

@ -1,11 +0,0 @@
=========================
WSGI Application Profiler
=========================
.. automodule:: werkzeug.contrib.profiler
.. autoclass:: MergeStream
.. autoclass:: ProfilerMiddleware
.. autofunction:: make_action

View file

@ -1,55 +0,0 @@
=============
Secure Cookie
=============
.. automodule:: werkzeug.contrib.securecookie
Security
========
The default implementation uses Pickle as this is the only module that
used to be available in the standard library when this module was created.
If you have simplejson available it's strongly recommended to create a
subclass and replace the serialization method::
import json
from werkzeug.contrib.securecookie import SecureCookie
class JSONSecureCookie(SecureCookie):
serialization_method = json
The weakness of Pickle is that if someone gains access to the secret key
the attacker can not only modify the session but also execute arbitrary
code on the server.
Reference
=========
.. autoclass:: SecureCookie
:members:
.. attribute:: new
`True` if the cookie was newly created, otherwise `False`
.. attribute:: modified
Whenever an item on the cookie is set, this attribute is set to `True`.
However this does not track modifications inside mutable objects
in the cookie:
>>> c = SecureCookie()
>>> c["foo"] = [1, 2, 3]
>>> c.modified
True
>>> c.modified = False
>>> c["foo"].append(4)
>>> c.modified
False
In that situation it has to be set to `modified` by hand so that
:attr:`should_save` can pick it up.
.. autoexception:: UnquoteError

View file

@ -1,50 +0,0 @@
========
Sessions
========
.. automodule:: werkzeug.contrib.sessions
.. testsetup::
from werkzeug.contrib.sessions import *
Reference
=========
.. autoclass:: Session
.. attribute:: sid
The session ID as string.
.. attribute:: new
`True` is the cookie was newly created, otherwise `False`
.. attribute:: modified
Whenever an item on the cookie is set, this attribute is set to `True`.
However this does not track modifications inside mutable objects
in the session:
>>> c = Session({}, sid='deadbeefbabe2c00ffee')
>>> c["foo"] = [1, 2, 3]
>>> c.modified
True
>>> c.modified = False
>>> c["foo"].append(4)
>>> c.modified
False
In that situation it has to be set to `modified` by hand so that
:attr:`should_save` can pick it up.
.. autoattribute:: should_save
.. autoclass:: SessionStore
:members:
.. autoclass:: FilesystemSessionStore
:members: list
.. autoclass:: SessionMiddleware

View file

@ -1,23 +0,0 @@
==============
Extra Wrappers
==============
.. automodule:: werkzeug.contrib.wrappers
.. autoclass:: JSONRequestMixin
:members:
.. autoclass:: ProtobufRequestMixin
:members:
.. autoclass:: RoutingArgsRequestMixin
:members:
.. autoclass:: ReverseSlashBehaviorRequestMixin
:members:
.. autoclass:: DynamicCharsetRequestMixin
:members:
.. autoclass:: DynamicCharsetResponseMixin
:members:

View file

@ -1,137 +0,0 @@
===============
Data Structures
===============
.. module:: werkzeug.datastructures
Werkzeug provides some subclasses of common Python objects to extend them
with additional features. Some of them are used to make them immutable, others
are used to change some semantics to better work with HTTP.
General Purpose
===============
.. versionchanged:: 0.6
The general purpose classes are now pickleable in each protocol as long
as the contained objects are pickleable. This means that the
:class:`FileMultiDict` won't be pickleable as soon as it contains a
file.
.. autoclass:: TypeConversionDict
:members:
.. autoclass:: ImmutableTypeConversionDict
:members: copy
.. autoclass:: MultiDict
:members:
:inherited-members:
.. autoclass:: OrderedMultiDict
.. autoclass:: ImmutableMultiDict
:members: copy
.. autoclass:: ImmutableOrderedMultiDict
:members: copy
.. autoclass:: CombinedMultiDict
.. autoclass:: ImmutableDict
:members: copy
.. autoclass:: ImmutableList
.. autoclass:: FileMultiDict
:members:
.. _http-datastructures:
HTTP Related
============
.. autoclass:: Headers([defaults])
:members:
.. autoclass:: EnvironHeaders
.. autoclass:: HeaderSet
:members:
.. autoclass:: Accept
:members:
.. autoclass:: MIMEAccept
:members: accept_html, accept_xhtml, accept_json
.. autoclass:: CharsetAccept
.. autoclass:: LanguageAccept
.. autoclass:: RequestCacheControl
:members:
.. autoattribute:: no_cache
.. autoattribute:: no_store
.. autoattribute:: max_age
.. autoattribute:: no_transform
.. autoclass:: ResponseCacheControl
:members:
.. autoattribute:: no_cache
.. autoattribute:: no_store
.. autoattribute:: max_age
.. autoattribute:: no_transform
.. autoclass:: ETags
:members:
.. autoclass:: Authorization
:members:
.. autoclass:: WWWAuthenticate
:members:
.. autoclass:: IfRange
:members:
.. autoclass:: Range
:members:
.. autoclass:: ContentRange
:members:
Others
======
.. autoclass:: FileStorage
:members:
.. attribute:: stream
The input stream for the uploaded file. This usually points to an
open temporary file.
.. attribute:: filename
The filename of the file on the client.
.. attribute:: name
The name of the form field.
.. attribute:: headers
The multipart headers as :class:`Headers` object. This usually contains
irrelevant information but in combination with custom multipart requests
the raw headers might be interesting.
.. versionadded:: 0.6

View file

@ -1,89 +0,0 @@
======================
Debugging Applications
======================
.. module:: werkzeug.debug
Depending on the WSGI gateway/server, exceptions are handled differently.
But most of the time, exceptions go to stderr or the error log.
Since this is not the best debugging environment, Werkzeug provides a
WSGI middleware that renders nice debugging tracebacks, optionally with an
AJAX based debugger (which allows to execute code in the context of the
traceback's frames).
The interactive debugger however does not work in forking environments
which makes it nearly impossible to use on production servers. Also the
debugger allows the execution of arbitrary code which makes it a major
security risk and **must never be used on production machines** because of
that. **We cannot stress this enough. Do not enable this in
production.**
Enabling the Debugger
=====================
You can enable the debugger by wrapping the application in a
:class:`DebuggedApplication` middleware. Additionally there are
parameters to the :func:`run_simple` function to enable it because this
is a common task during development.
.. autoclass:: DebuggedApplication
Using the Debugger
==================
Once enabled and an error happens during a request you will see a detailed
traceback instead of a general "internal server error". If you have the
`evalex` feature enabled you can also get a traceback for every frame in
the traceback by clicking on the console icon.
Once clicked a console opens where you can execute Python code in:
.. image:: _static/debug-screenshot.png
:alt: a screenshot of the interactive debugger
:align: center
Inside the interactive consoles you can execute any kind of Python code.
Unlike regular Python consoles the output of the object reprs is colored
and stripped to a reasonable size by default. If the output is longer
than what the console decides to display a small plus sign is added to
the repr and a click will expand the repr.
To display all variables that are defined in the current frame you can
use the `dump()` function. You can call it without arguments to get a
detailed list of all variables and their values, or with an object as
argument to get a detailed list of all the attributes it has.
Debugger PIN
============
Starting with Werkzeug 0.11 the debugger is additionally protected by a
PIN. This is a security helper to make it less likely for the debugger to
be exploited in production as it has happened to people to keep the
debugger active. The PIN based authentication is enabled by default.
When the debugger comes up, on first usage it will prompt for a PIN that
is printed to the command line. The PIN is generated in a stable way that
is specific to the project. In some situations it might be not possible
to generate a stable PIN between restarts in which case an explicit PIN
can be provided through the environment variable ``WERKZEUG_DEBUG_PIN``.
This can be set to a number and will become the PIN. This variable can
also be set to the value ``off`` to disable the PIN check entirely.
If the PIN is entered too many times incorrectly the server needs to be
restarted.
**This feature is not supposed to entirely secure the debugger. It's
intended to make it harder for an attacker to exploit the debugger. Never
enable the debugger in production.**
Pasting Errors
==============
If you click on the `Traceback` title, the traceback switches over to a text
based one. The text based one can be pasted to `gist.github.com <https://gist.github.com>`_ with one
click.
.. _paste.pocoo.org: https://gist.github.com

View file

@ -1,44 +0,0 @@
===
CGI
===
If all other deployment methods do not work, CGI will work for sure. CGI
is supported by all major servers but usually has a less-than-optimal
performance.
This is also the way you can use a Werkzeug application on Google's
`AppEngine`_, there however the execution does happen in a CGI-like
environment. The application's performance is unaffected because of that.
.. _AppEngine: http://code.google.com/appengine/
Creating a `.cgi` file
======================
First you need to create the CGI application file. Let's call it
`yourapplication.cgi`::
#!/usr/bin/python
from wsgiref.handlers import CGIHandler
from yourapplication import make_app
application = make_app()
CGIHandler().run(application)
If you're running Python 2.4 you will need the :mod:`wsgiref` package. Python
2.5 and higher ship this as part of the standard library.
Server Setup
============
Usually there are two ways to configure the server. Either just copy the
`.cgi` into a `cgi-bin` (and use `mod_rerwite` or something similar to
rewrite the URL) or let the server point to the file directly.
In Apache for example you can put a like like this into the config:
.. sourcecode:: apache
ScriptAlias /app /path/to/the/application.cgi
For more information consult the documentation of your webserver.

View file

@ -1,142 +0,0 @@
=======
FastCGI
=======
A very popular deployment setup on servers like `lighttpd`_ and `nginx`_
is FastCGI. To use your WSGI application with any of them you will need
a FastCGI server first.
The most popular one is `flup`_ which we will use for this guide. Make
sure to have it installed.
Creating a `.fcgi` file
=======================
First you need to create the FastCGI server file. Let's call it
`yourapplication.fcgi`::
#!/usr/bin/python
from flup.server.fcgi import WSGIServer
from yourapplication import make_app
if __name__ == '__main__':
application = make_app()
WSGIServer(application).run()
This is enough for Apache to work, however ngingx and older versions of
lighttpd need a socket to be explicitly passed to communicate with the FastCGI
server. For that to work you need to pass the path to the socket to the
:class:`~flup.server.fcgi.WSGIServer`::
WSGIServer(application, bindAddress='/path/to/fcgi.sock').run()
The path has to be the exact same path you define in the server
config.
Save the `yourapplication.fcgi` file somewhere you will find it again.
It makes sense to have that in `/var/www/yourapplication` or something
similar.
Make sure to set the executable bit on that file so that the servers
can execute it::
# chmod +x /var/www/yourapplication/yourapplication.fcgi
Configuring lighttpd
====================
A basic FastCGI configuration for lighttpd looks like this::
fastcgi.server = ("/yourapplication.fcgi" =>
((
"socket" => "/tmp/yourapplication-fcgi.sock",
"bin-path" => "/var/www/yourapplication/yourapplication.fcgi",
"check-local" => "disable",
"max-procs" -> 1
))
)
alias.url = (
"/static/" => "/path/to/your/static"
)
url.rewrite-once = (
"^(/static.*)$" => "$1",
"^(/.*)$" => "/yourapplication.fcgi$1"
Remember to enable the FastCGI, alias and rewrite modules. This configuration
binds the application to `/yourapplication`. If you want the application to
work in the URL root you have to work around a lighttpd bug with the
:class:`~werkzeug.contrib.fixers.LighttpdCGIRootFix` middleware.
Make sure to apply it only if you are mounting the application the URL
root. Also, see the Lighty docs for more information on `FastCGI and Python
<http://redmine.lighttpd.net/wiki/lighttpd/Docs:ModFastCGI>`_ (note that
explicitly passing a socket to run() is no longer necessary).
Configuring nginx
=================
Installing FastCGI applications on nginx is a bit tricky because by default
some FastCGI parameters are not properly forwarded.
A basic FastCGI configuration for nginx looks like this::
location /yourapplication/ {
include fastcgi_params;
if ($uri ~ ^/yourapplication/(.*)?) {
set $path_url $1;
}
fastcgi_param PATH_INFO $path_url;
fastcgi_param SCRIPT_NAME /yourapplication;
fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}
This configuration binds the application to `/yourapplication`. If you want
to have it in the URL root it's a bit easier because you don't have to figure
out how to calculate `PATH_INFO` and `SCRIPT_NAME`::
location /yourapplication/ {
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_param SCRIPT_NAME "";
fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}
Since Nginx doesn't load FastCGI apps, you have to do it by yourself. You
can either write an `init.d` script for that or execute it inside a screen
session::
$ screen
$ /var/www/yourapplication/yourapplication.fcgi
Debugging
=========
FastCGI deployments tend to be hard to debug on most webservers. Very often the
only thing the server log tells you is something along the lines of "premature
end of headers". In order to debug the application the only thing that can
really give you ideas why it breaks is switching to the correct user and
executing the application by hand.
This example assumes your application is called `application.fcgi` and that your
webserver user is `www-data`::
$ su www-data
$ cd /var/www/yourapplication
$ python application.fcgi
Traceback (most recent call last):
File "yourapplication.fcg", line 4, in <module>
ImportError: No module named yourapplication
In this case the error seems to be "yourapplication" not being on the python
path. Common problems are:
- relative paths being used. Don't rely on the current working directory
- the code depending on environment variables that are not set by the
web server.
- different python interpreters being used.
.. _lighttpd: http://www.lighttpd.net/
.. _nginx: http://nginx.net/
.. _flup: http://trac.saddi.com/flup

View file

@ -1,16 +0,0 @@
.. _deployment:
======================
Application Deployment
======================
This section covers running your application in production on a web
server such as Apache or lighttpd.
.. toctree::
:maxdepth: 2
cgi
mod_wsgi
fastcgi
proxying

View file

@ -1,82 +0,0 @@
===================
`mod_wsgi` (Apache)
===================
If you are using the `Apache`_ webserver you should consider using `mod_wsgi`_.
.. _Apache: http://httpd.apache.org/
Installing `mod_wsgi`
=====================
If you don't have `mod_wsgi` installed yet you have to either install it using
a package manager or compile it yourself.
The mod_wsgi `installation instructions`_ cover installation instructions for
source installations on UNIX systems.
If you are using ubuntu / debian you can apt-get it and activate it as follows::
# apt-get install libapache2-mod-wsgi
On FreeBSD install `mod_wsgi` by compiling the `www/mod_wsgi` port or by using
pkg_add::
# pkg_add -r mod_wsgi
If you are using pkgsrc you can install `mod_wsgi` by compiling the
`www/ap2-wsgi` package.
If you encounter segfaulting child processes after the first apache reload you
can safely ignore them. Just restart the server.
Creating a `.wsgi` file
=======================
To run your application you need a `yourapplication.wsgi` file. This file
contains the code `mod_wsgi` is executing on startup to get the application
object. The object called `application` in that file is then used as
application.
For most applications the following file should be sufficient::
from yourapplication import make_app
application = make_app()
If you don't have a factory function for application creation but a singleton
instance you can directly import that one as `application`.
Store that file somewhere where you will find it again (eg:
`/var/www/yourapplication`) and make sure that `yourapplication` and all
the libraries that are in use are on the python load path. If you don't
want to install it system wide consider using a `virtual python`_ instance.
Configuring Apache
==================
The last thing you have to do is to create an Apache configuration file for
your application. In this example we are telling `mod_wsgi` to execute the
application under a different user for security reasons:
.. sourcecode:: apache
<VirtualHost *>
ServerName example.com
WSGIDaemonProcess yourapplication user=user1 group=group1 processes=2 threads=5
WSGIScriptAlias / /var/www/yourapplication/yourapplication.wsgi
<Directory /var/www/yourapplication>
WSGIProcessGroup yourapplication
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
For more information consult the `mod_wsgi wiki`_.
.. _mod_wsgi: http://code.google.com/p/modwsgi/
.. _installation instructions: http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide
.. _virtual python: http://pypi.python.org/pypi/virtualenv
.. _mod_wsgi wiki: http://code.google.com/p/modwsgi/wiki/

View file

@ -1,54 +0,0 @@
=============
HTTP Proxying
=============
Many people prefer using a standalone Python HTTP server and proxying that
server via nginx, Apache etc.
A very stable Python server is CherryPy. This part of the documentation
shows you how to combine your WSGI application with the CherryPy WSGI
server and how to configure the webserver for proxying.
Creating a `.py` server
=======================
To run your application you need a `start-server.py` file that starts up
the WSGI Server.
It looks something along these lines::
from cherrypy import wsgiserver
from yourapplication import make_app
server = wsgiserver.CherryPyWSGIServer(('localhost', 8080), make_app())
try:
server.start()
except KeyboardInterrupt:
server.stop()
If you now start the file the server will listen on `localhost:8080`. Keep
in mind that WSGI applications behave slightly different for proxied setups.
If you have not developed your application for proxying in mind, you can
apply the :class:`~werkzeug.contrib.fixers.ProxyFix` middleware.
Configuring nginx
=================
As an example we show here how to configure nginx to proxy to the server.
The basic nginx configuration looks like this::
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
proxy_redirect default;
}
Since Nginx doesn't start your server for you, you have to do it by yourself. You
can either write an `init.d` script for that or execute it inside a screen
session::
$ screen
$ python start-server.py

View file

@ -1,147 +0,0 @@
===============
HTTP Exceptions
===============
.. automodule:: werkzeug.exceptions
Error Classes
=============
The following error classes exist in Werkzeug:
.. autoexception:: BadRequest
.. autoexception:: Unauthorized
.. autoexception:: Forbidden
.. autoexception:: NotFound
.. autoexception:: MethodNotAllowed
.. autoexception:: NotAcceptable
.. autoexception:: RequestTimeout
.. autoexception:: Conflict
.. autoexception:: Gone
.. autoexception:: LengthRequired
.. autoexception:: PreconditionFailed
.. autoexception:: RequestEntityTooLarge
.. autoexception:: RequestURITooLarge
.. autoexception:: UnsupportedMediaType
.. autoexception:: RequestedRangeNotSatisfiable
.. autoexception:: ExpectationFailed
.. autoexception:: ImATeapot
.. autoexception:: PreconditionRequired
.. autoexception:: TooManyRequests
.. autoexception:: RequestHeaderFieldsTooLarge
.. autoexception:: InternalServerError
.. autoexception:: NotImplemented
.. autoexception:: BadGateway
.. autoexception:: ServiceUnavailable
.. exception:: HTTPUnicodeError
This exception is used to signal unicode decode errors of request
data. For more information see the :ref:`unicode` chapter.
.. autoexception:: ClientDisconnected
.. autoexception:: SecurityError
Baseclass
=========
All the exceptions implement this common interface:
.. autoexception:: HTTPException
:members: get_response, __call__
Special HTTP Exceptions
=======================
Starting with Werkzeug 0.3 some of the builtin classes raise exceptions that
look like regular python exceptions (eg :exc:`KeyError`) but are
:exc:`BadRequest` HTTP exceptions at the same time. This decision was made
to simplify a common pattern where you want to abort if the client tampered
with the submitted form data in a way that the application can't recover
properly and should abort with ``400 BAD REQUEST``.
Assuming the application catches all HTTP exceptions and reacts to them
properly a view function could do the following safely and doesn't have to
check if the keys exist::
def new_post(request):
post = Post(title=request.form['title'], body=request.form['body'])
post.save()
return redirect(post.url)
If `title` or `body` are missing in the form, a special key error will be
raised which behaves like a :exc:`KeyError` but also a :exc:`BadRequest`
exception.
Simple Aborting
===============
Sometimes it's convenient to just raise an exception by the error code,
without importing the exception and looking up the name etc. For this
purpose there is the :func:`abort` function.
.. autofunction:: abort
If you want to use this functionality with custom exceptions you can
create an instance of the aborter class:
.. autoclass:: Aborter
Custom Errors
=============
As you can see from the list above not all status codes are available as
errors. Especially redirects and other non 200 status codes that do not
represent errors are missing. For redirects you can use the :func:`redirect`
function from the utilities.
If you want to add an error yourself you can subclass :exc:`HTTPException`::
from werkzeug.exceptions import HTTPException
class PaymentRequired(HTTPException):
code = 402
description = '<p>Payment required.</p>'
This is the minimal code you need for your own exception. If you want to
add more logic to the errors you can override the
:meth:`~HTTPException.get_description`, :meth:`~HTTPException.get_body`,
:meth:`~HTTPException.get_headers` and :meth:`~HTTPException.get_response`
methods. In any case you should have a look at the sourcecode of the
exceptions module.
You can override the default description in the constructor with the
`description` parameter (it's the first argument for all exceptions
except of the :exc:`MethodNotAllowed` which accepts a list of allowed methods
as first argument)::
raise BadRequest('Request failed because X was not present')

View file

@ -1,11 +0,0 @@
====================
Filesystem Utilities
====================
Various utilities for the local filesystem.
.. module:: werkzeug.filesystem
.. autoclass:: BrokenFilesystemWarning
.. autofunction:: get_filesystem_encoding

View file

@ -1,156 +0,0 @@
==============
HTTP Utilities
==============
.. module:: werkzeug.http
Werkzeug provides a couple of functions to parse and generate HTTP headers
that are useful when implementing WSGI middlewares or whenever you are
operating on a lower level layer. All this functionality is also exposed
from request and response objects.
Date Functions
==============
The following functions simplify working with times in an HTTP context.
Werkzeug uses offset-naive :class:`~datetime.datetime` objects internally
that store the time in UTC. If you're working with timezones in your
application make sure to replace the tzinfo attribute with a UTC timezone
information before processing the values.
.. autofunction:: cookie_date
.. autofunction:: http_date
.. autofunction:: parse_date
Header Parsing
==============
The following functions can be used to parse incoming HTTP headers.
Because Python does not provide data structures with the semantics required
by :rfc:`2616`, Werkzeug implements some custom data structures that are
:ref:`documented separately <http-datastructures>`.
.. autofunction:: parse_options_header
.. autofunction:: parse_set_header
.. autofunction:: parse_list_header
.. autofunction:: parse_dict_header
.. autofunction:: parse_accept_header(value, [class])
.. autofunction:: parse_cache_control_header
.. autofunction:: parse_authorization_header
.. autofunction:: parse_www_authenticate_header
.. autofunction:: parse_if_range_header
.. autofunction:: parse_range_header
.. autofunction:: parse_content_range_header
Header Utilities
================
The following utilities operate on HTTP headers well but do not parse
them. They are useful if you're dealing with conditional responses or if
you want to proxy arbitrary requests but want to remove WSGI-unsupported
hop-by-hop headers. Also there is a function to create HTTP header
strings from the parsed data.
.. autofunction:: is_entity_header
.. autofunction:: is_hop_by_hop_header
.. autofunction:: remove_entity_headers
.. autofunction:: remove_hop_by_hop_headers
.. autofunction:: is_byte_range_valid
.. autofunction:: quote_header_value
.. autofunction:: unquote_header_value
.. autofunction:: dump_header
Cookies
=======
.. autofunction:: parse_cookie
.. autofunction:: dump_cookie
Conditional Response Helpers
============================
For conditional responses the following functions might be useful:
.. autofunction:: parse_etags
.. autofunction:: quote_etag
.. autofunction:: unquote_etag
.. autofunction:: generate_etag
.. autofunction:: is_resource_modified
Constants
=========
.. data:: HTTP_STATUS_CODES
A dict of status code -> default status message pairs. This is used
by the wrappers and other places where an integer status code is expanded
to a string throughout Werkzeug.
Form Data Parsing
=================
.. module:: werkzeug.formparser
Werkzeug provides the form parsing functions separately from the request
object so that you can access form data from a plain WSGI environment.
The following formats are currently supported by the form data parser:
- `application/x-www-form-urlencoded`
- `multipart/form-data`
Nested multipart is not currently supported (Werkzeug 0.9), but it isn't used
by any of the modern web browsers.
Usage example:
>>> from cStringIO import StringIO
>>> data = '--foo\r\nContent-Disposition: form-data; name="test"\r\n' \
... '\r\nHello World!\r\n--foo--'
>>> environ = {'wsgi.input': StringIO(data), 'CONTENT_LENGTH': str(len(data)),
... 'CONTENT_TYPE': 'multipart/form-data; boundary=foo',
... 'REQUEST_METHOD': 'POST'}
>>> stream, form, files = parse_form_data(environ)
>>> stream.read()
''
>>> form['test']
u'Hello World!'
>>> not files
True
Normally the WSGI environment is provided by the WSGI gateway with the
incoming data as part of it. If you want to generate such fake-WSGI
environments for unittesting you might want to use the
:func:`create_environ` function or the :class:`EnvironBuilder` instead.
.. autoclass:: FormDataParser
.. autofunction:: parse_form_data
.. autofunction:: parse_multipart_headers

View file

@ -1,7 +0,0 @@
======================
Documentation Overview
======================
Welcome to the Werkzeug |version| documentation.
.. include:: contents.rst.inc

View file

@ -1,133 +0,0 @@
============
Installation
============
Werkzeug requires at least Python 2.6 to work correctly. If you do need
to support an older version you can download an older version of Werkzeug
though we strongly recommend against that. Werkzeug currently has
experimental support for Python 3. For more information about the
Python 3 support see :ref:`python3`.
Installing a released version
=============================
As a Python egg (via easy_install or pip)
-----------------------------------------
You can install the most recent Werkzeug version using `easy_install`_::
easy_install Werkzeug
Alternatively you can also use pip::
pip install Werkzeug
Either way we strongly recommend using these tools in combination with
:ref:`virtualenv`.
This will install a Werkzeug egg in your Python installation's `site-packages`
directory.
From the tarball release
-------------------------
1. Download the most recent tarball from the `download page`_.
2. Unpack the tarball.
3. ``python setup.py install``
Note that the last command will automatically download and install
`setuptools`_ if you don't already have it installed. This requires a working
Internet connection.
This will install Werkzeug into your Python installation's `site-packages`
directory.
Installing the development version
==================================
1. Install `Git`_
2. ``git clone git://github.com/pallets/werkzeug.git``
3. ``cd werkzeug``
4. ``pip install --editable .``
.. _virtualenv:
virtualenv
==========
Virtualenv is probably what you want to use during development, and in
production too if you have shell access there.
What problem does virtualenv solve? If you like Python as I do,
chances are you want to use it for other projects besides Werkzeug-based
web applications. But the more projects you have, the more likely it is
that you will be working with different versions of Python itself, or at
least different versions of Python libraries. Let's face it; quite often
libraries break backwards compatibility, and it's unlikely that any serious
application will have zero dependencies. So what do you do if two or more
of your projects have conflicting dependencies?
Virtualenv to the rescue! It basically enables multiple side-by-side
installations of Python, one for each project. It doesn't actually
install separate copies of Python, but it does provide a clever way
to keep different project environments isolated.
So let's see how virtualenv works!
If you are on Mac OS X or Linux, chances are that one of the following two
commands will work for you::
$ sudo easy_install virtualenv
or even better::
$ sudo pip install virtualenv
One of these will probably install virtualenv on your system. Maybe it's
even in your package manager. If you use Ubuntu, try::
$ sudo apt-get install python-virtualenv
If you are on Windows and don't have the `easy_install` command, you must
install it first. Once you have it installed, run the same commands as
above, but without the `sudo` prefix.
Once you have virtualenv installed, just fire up a shell and create
your own environment. I usually create a project folder and an `env`
folder within::
$ mkdir myproject
$ cd myproject
$ virtualenv env
New python executable in env/bin/python
Installing setuptools............done.
Now, whenever you want to work on a project, you only have to activate
the corresponding environment. On OS X and Linux, do the following::
$ . env/bin/activate
(Note the space between the dot and the script name. The dot means that
this script should run in the context of the current shell. If this command
does not work in your shell, try replacing the dot with ``source``)
If you are a Windows user, the following command is for you::
$ env\scripts\activate
Either way, you should now be using your virtualenv (see how the prompt of
your shell has changed to show the virtualenv).
Now you can just enter the following command to get Werkzeug activated in
your virtualenv::
$ pip install Werkzeug
A few seconds later you are good to go.
.. _download page: https://pypi.python.org/pypi/Werkzeug
.. _setuptools: http://peak.telecommunity.com/DevCenter/setuptools
.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall
.. _Git: http://git-scm.org/

View file

@ -1,6 +0,0 @@
:orphan:
Werkzeug Documentation
======================
.. include:: contents.rst.inc

View file

@ -1,70 +0,0 @@
==========
API Levels
==========
.. module:: werkzeug
Werkzeug is intended to be a utility rather than a framework. Because of that
the user-friendly API is separated from the lower-level API so that Werkzeug
can easily be used to extend another system.
All the functionality the :class:`Request` and :class:`Response` objects (aka
the "wrappers") provide is also available in small utility functions.
Example
=======
This example implements a small `Hello World` application that greets the
user with the name entered::
from werkzeug.utils import escape
from werkzeug.wrappers import Request, Response
@Request.application
def hello_world(request):
result = ['<title>Greeter</title>']
if request.method == 'POST':
result.append('<h1>Hello %s!</h1>' % escape(request.form['name']))
result.append('''
<form action="" method="post">
<p>Name: <input type="text" name="name" size="20">
<input type="submit" value="Greet me">
</form>
''')
return Response(''.join(result), mimetype='text/html')
Alternatively the same application could be used without request and response
objects but by taking advantage of the parsing functions werkzeug provides::
from werkzeug.formparser import parse_form_data
from werkzeug.utils import escape
def hello_world(environ, start_response):
result = ['<title>Greeter</title>']
if environ['REQUEST_METHOD'] == 'POST':
form = parse_form_data(environ)[1]
result.append('<h1>Hello %s!</h1>' % escape(form['name']))
result.append('''
<form action="" method="post">
<p>Name: <input type="text" name="name" size="20">
<input type="submit" value="Greet me">
</form>
''')
start_response('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
return [''.join(result)]
High or Low?
============
Usually you want to use the high-level layer (the request and response
objects). But there are situations where this might not be what you want.
For example you might be maintaining code for an application written in
Django or another framework and you have to parse HTTP headers. You can
utilize Werkzeug for that by accessing the lower-level HTTP header parsing
functions.
Another situation where the low level parsing functions can be useful are
custom WSGI frameworks, unit-testing or modernizing an old CGI/mod_python
application to WSGI as well as WSGI middlewares where you want to keep the
overhead low.

View file

@ -1,94 +0,0 @@
==============
Context Locals
==============
.. module:: werkzeug.local
Sooner or later you have some things you want to have in every single view
or helper function or whatever. In PHP the way to go are global
variables. However, that isn't possible in WSGI applications without a
major drawback: As soon as you operate on the global namespace your
application isn't thread-safe any longer.
The Python standard library has a concept called "thread locals" (or thread-local
data). A thread local is a global object in which you can put stuff in and get back
later in a thread-safe and thread-specific way. That means that whenever you set
or get a value on a thread local object, the thread local object checks in which
thread you are and retrieves the value corresponding to your thread (if one exists).
So, you won't accidentally get another thread's data.
This approach, however, has a few disadvantages. For example, besides threads,
there are other types of concurrency in Python. A very popular one
is greenlets. Also, whether every request gets its own thread is not
guaranteed in WSGI. It could be that a request is reusing a thread from
a previous request, and hence data is left over in the thread local object.
Werkzeug provides its own implementation of local data storage called `werkzeug.local`.
This approach provides a similar functionality to thread locals but also works with
greenlets.
Here's a simple example of how one could use werkzeug.local::
from werkzeug.local import Local, LocalManager
local = Local()
local_manager = LocalManager([local])
def application(environ, start_response):
local.request = request = Request(environ)
...
application = local_manager.make_middleware(application)
This binds the request to `local.request`. Every other piece of code executed
after this assignment in the same context can safely access local.request and
will get the same request object. The `make_middleware` method on the local
manager ensures that all references to the local objects are cleared up after
the request.
The same context means the same greenlet (if you're using greenlets) in
the same thread and same process.
If a request object is not yet set on the local object and you try to
access it, you will get an `AttributeError`. You can use `getattr` to avoid
that::
def get_request():
return getattr(local, 'request', None)
This will try to get the request or return `None` if the request is not
(yet?) available.
Note that local objects cannot manage themselves, for that you need a local
manager. You can pass a local manager multiple locals or add additionals
later by appending them to `manager.locals` and every time the manager
cleans up it will clean up all the data left in the locals for this
context.
.. autofunction:: release_local
.. autoclass:: LocalManager
:members: cleanup, make_middleware, middleware, get_ident
.. autoclass:: LocalStack
:members: push, pop, top
.. autoclass:: LocalProxy
:members: _get_current_object
Keep in mind that ``repr()`` is also forwarded, so if you want to find
out if you are dealing with a proxy you can do an ``isinstance()`` check:
.. sourcecode:: pycon
>>> from werkzeug.local import LocalProxy
>>> isinstance(request, LocalProxy)
True
You can also create proxy objects by hand:
.. sourcecode:: python
from werkzeug.local import Local, LocalProxy
local = Local()
request = LocalProxy(local, 'request')

View file

@ -1,95 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
set SPHINXBUILD=sphinx-build
set ALLSPHINXOPTS=-d _build/doctrees %SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
goto end
)
if "%1" == "clean" (
for /d %%i in (_build\*) do rmdir /q /s %%i
del /q /s _build\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% _build/html
echo.
echo.Build finished. The HTML pages are in _build/html.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% _build/pickle
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% _build/json
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% _build/htmlhelp
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in _build/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% _build/qthelp
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in _build/qthelp, like this:
echo.^> qcollectiongenerator _build\qthelp\Werkzeug.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile _build\qthelp\Werkzeug.ghc
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% _build/latex
echo.
echo.Build finished; the LaTeX files are in _build/latex.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% _build/changes
echo.
echo.The overview file is in _build/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% _build/linkcheck
echo.
echo.Link check complete; look for any errors in the above output ^
or in _build/linkcheck/output.txt.
goto end
)
:end

View file

@ -1,7 +0,0 @@
import os
import conf
name = "werkzeug-docs-" + conf.version
os.chdir("_build")
os.rename("html", name)
os.system("tar czf %s.tar.gz %s" % (name, name))
os.rename(name, "html")

View file

@ -1,19 +0,0 @@
===========
Middlewares
===========
.. module:: werkzeug.wsgi
Middlewares wrap applications to dispatch between them or provide
additional request handling. Additionally to the middlewares documented
here, there is also the :class:`DebuggedApplication` class that is
implemented as a WSGI middleware.
.. autoclass:: SharedDataMiddleware
:members: is_allowed
.. autoclass:: DispatcherMiddleware
Also there's the …
.. autofunction:: werkzeug._internal._easteregg

View file

@ -1,73 +0,0 @@
.. _python3:
==============
Python 3 Notes
==============
Since version 0.9, Werkzeug supports Python 3.3+ in addition to versions 2.6
and 2.7. Older Python 3 versions such as 3.2 or 3.1 are not supported.
This part of the documentation outlines special information required to
use Werkzeug and WSGI on Python 3.
.. warning::
Python 3 support in Werkzeug is currently highly experimental. Please
give feedback on it and help us improve it.
WSGI Environment
================
The WSGI environment on Python 3 works slightly different than it does on
Python 2. For the most part Werkzeug hides the differences from you if
you work on the higher level APIs. The main difference between Python 2
and Python 3 is that on Python 2 the WSGI environment contains bytes
whereas the environment on Python 3 contains a range of differently
encoded strings.
There are two different kinds of strings in the WSGI environ on Python 3:
- unicode strings restricted to latin1 values. These are used for
HTTP headers and a few other things.
- unicode strings carrying binary payload, roundtripped through latin1
values. This is usually referred as “WSGI encoding dance” throughout
Werkzeug.
Werkzeug provides you with functionality to deal with these automatically
so that you don't need to be aware of the inner workings. The following
functions and classes should be used to read information out of the
WSGI environment:
- :func:`~werkzeug.wsgi.get_current_url`
- :func:`~werkzeug.wsgi.get_host`
- :func:`~werkzeug.wsgi.get_script_name`
- :func:`~werkzeug.wsgi.get_path_info`
- :func:`~werkzeug.wsgi.get_query_string`
- :func:`~werkzeug.datastructures.EnvironHeaders`
Applications are strongly discouraged to create and modify a WSGI
environment themselves on Python 3 unless they take care of the proper
decoding step. All high level interfaces in Werkzeug will apply the
correct encoding and decoding steps as necessary.
URLs
====
URLs in Werkzeug attempt to represent themselves as unicode strings on
Python 3. All the parsing functions generally also provide functionality
that allow operations on bytes. In some cases functions that deal with
URLs allow passing in `None` as charset to change the return value to byte
objects. Internally Werkzeug will now unify URIs and IRIs as much as
possible.
Request Cleanup
===============
Request objects on Python 3 and PyPy require explicit closing when file
uploads are involved. This is required to properly close temporary file
objects created by the multipart parser. For that purpose the ``close()``
method was introduced.
In addition to that request objects now also act as context managers that
automatically close.

View file

@ -1,323 +0,0 @@
==========
Quickstart
==========
.. module:: werkzeug
This part of the documentation shows how to use the most important parts of
Werkzeug. It's intended as a starting point for developers with basic
understanding of :pep:`333` (WSGI) and :rfc:`2616` (HTTP).
.. warning::
Make sure to import all objects from the places the documentation
suggests. It is theoretically possible in some situations to import
objects from different locations but this is not supported.
For example :class:`MultiDict` is a member of the `werkzeug` module
but internally implemented in a different one.
WSGI Environment
================
The WSGI environment contains all the information the user request transmits
to the application. It is passed to the WSGI application but you can also
create a WSGI environ dict using the :func:`create_environ` helper:
>>> from werkzeug.test import create_environ
>>> environ = create_environ('/foo', 'http://localhost:8080/')
Now we have an environment to play around:
>>> environ['PATH_INFO']
'/foo'
>>> environ['SCRIPT_NAME']
''
>>> environ['SERVER_NAME']
'localhost'
Usually nobody wants to work with the environ directly because it is limited
to bytestrings and does not provide any way to access the form data besides
parsing that data by hand.
Enter Request
=============
For access to the request data the :class:`Request` object is much more fun.
It wraps the `environ` and provides a read-only access to the data from
there:
>>> from werkzeug.wrappers import Request
>>> request = Request(environ)
Now you can access the important variables and Werkzeug will parse them
for you and decode them where it makes sense. The default charset for
requests is set to `utf-8` but you can change that by subclassing
:class:`Request`.
>>> request.path
u'/foo'
>>> request.script_root
u''
>>> request.host
'localhost:8080'
>>> request.url
'http://localhost:8080/foo'
We can also find out which HTTP method was used for the request:
>>> request.method
'GET'
This way we can also access URL arguments (the query string) and data that
was transmitted in a POST/PUT request.
For testing purposes we can create a request object from supplied data
using the :meth:`~BaseRequest.from_values` method:
>>> from cStringIO import StringIO
>>> data = "name=this+is+encoded+form+data&another_key=another+one"
>>> request = Request.from_values(query_string='foo=bar&blah=blafasel',
... content_length=len(data), input_stream=StringIO(data),
... content_type='application/x-www-form-urlencoded',
... method='POST')
...
>>> request.method
'POST'
Now we can access the URL parameters easily:
>>> request.args.keys()
['blah', 'foo']
>>> request.args['blah']
u'blafasel'
Same for the supplied form data:
>>> request.form['name']
u'this is encoded form data'
Handling for uploaded files is not much harder as you can see from this
example::
def store_file(request):
file = request.files.get('my_file')
if file:
file.save('/where/to/store/the/file.txt')
else:
handle_the_error()
The files are represented as :class:`FileStorage` objects which provide
some common operations to work with them.
Request headers can be accessed by using the :class:`~BaseRequest.headers`
attribute:
>>> request.headers['Content-Length']
'54'
>>> request.headers['Content-Type']
'application/x-www-form-urlencoded'
The keys for the headers are of course case insensitive.
Header Parsing
==============
There is more. Werkzeug provides convenient access to often used HTTP headers
and other request data.
Let's create a request object with all the data a typical web browser transmits
so that we can play with it:
>>> environ = create_environ()
>>> environ.update(
... HTTP_USER_AGENT='Mozilla/5.0 (Macintosh; U; Mac OS X 10.5; en-US; ) Firefox/3.1',
... HTTP_ACCEPT='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
... HTTP_ACCEPT_LANGUAGE='de-at,en-us;q=0.8,en;q=0.5',
... HTTP_ACCEPT_ENCODING='gzip,deflate',
... HTTP_ACCEPT_CHARSET='ISO-8859-1,utf-8;q=0.7,*;q=0.7',
... HTTP_IF_MODIFIED_SINCE='Fri, 20 Feb 2009 10:10:25 GMT',
... HTTP_IF_NONE_MATCH='"e51c9-1e5d-46356dc86c640"',
... HTTP_CACHE_CONTROL='max-age=0'
... )
...
>>> request = Request(environ)
Let's start with the most useless header: the user agent:
>>> request.user_agent.browser
'firefox'
>>> request.user_agent.platform
'macos'
>>> request.user_agent.version
'3.1'
>>> request.user_agent.language
'en-US'
A more useful header is the accept header. With this header the browser
informs the web application what mimetypes it can handle and how well. All
accept headers are sorted by the quality, the best item being the first:
>>> request.accept_mimetypes.best
'text/html'
>>> 'application/xhtml+xml' in request.accept_mimetypes
True
>>> print request.accept_mimetypes["application/json"]
0.8
The same works for languages:
>>> request.accept_languages.best
'de-at'
>>> request.accept_languages.values()
['de-at', 'en-us', 'en']
And of course encodings and charsets:
>>> 'gzip' in request.accept_encodings
True
>>> request.accept_charsets.best
'ISO-8859-1'
>>> 'utf-8' in request.accept_charsets
True
Normalization is available, so you can safely use alternative forms to perform
containment checking:
>>> 'UTF8' in request.accept_charsets
True
>>> 'de_AT' in request.accept_languages
True
E-tags and other conditional headers are available in parsed form as well:
>>> request.if_modified_since
datetime.datetime(2009, 2, 20, 10, 10, 25)
>>> request.if_none_match
<ETags '"e51c9-1e5d-46356dc86c640"'>
>>> request.cache_control
<RequestCacheControl 'max-age=0'>
>>> request.cache_control.max_age
0
>>> 'e51c9-1e5d-46356dc86c640' in request.if_none_match
True
Responses
=========
Response objects are the opposite of request objects. They are used to send
data back to the client. In reality, response objects are nothing more than
glorified WSGI applications.
So what you are doing is not *returning* the response objects from your WSGI
application but *calling* it as WSGI application inside your WSGI application
and returning the return value of that call.
So imagine your standard WSGI "Hello World" application::
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello World!']
With response objects it would look like this::
from werkzeug.wrappers import Response
def application(environ, start_response):
response = Response('Hello World!')
return response(environ, start_response)
Also, unlike request objects, response objects are designed to be modified.
So here is what you can do with them:
>>> from werkzeug.wrappers import Response
>>> response = Response("Hello World!")
>>> response.headers['content-type']
'text/plain; charset=utf-8'
>>> response.data
'Hello World!'
>>> response.headers['content-length'] = len(response.data)
You can modify the status of the response in the same way. Either just the
code or provide a message as well:
>>> response.status
'200 OK'
>>> response.status = '404 Not Found'
>>> response.status_code
404
>>> response.status_code = 400
>>> response.status
'400 BAD REQUEST'
As you can see attributes work in both directions. So you can set both
:attr:`~BaseResponse.status` and :attr:`~BaseResponse.status_code` and the
change will be reflected to the other.
Also common headers are exposed as attributes or with methods to set /
retrieve them:
>>> response.content_length
12
>>> from datetime import datetime
>>> response.date = datetime(2009, 2, 20, 17, 42, 51)
>>> response.headers['Date']
'Fri, 20 Feb 2009 17:42:51 GMT'
Because etags can be weak or strong there are methods to set them:
>>> response.set_etag("12345-abcd")
>>> response.headers['etag']
'"12345-abcd"'
>>> response.get_etag()
('12345-abcd', False)
>>> response.set_etag("12345-abcd", weak=True)
>>> response.get_etag()
('12345-abcd', True)
Some headers are available as mutable structures. For example most
of the `Content-` headers are sets of values:
>>> response.content_language.add('en-us')
>>> response.content_language.add('en')
>>> response.headers['Content-Language']
'en-us, en'
Also here this works in both directions:
>>> response.headers['Content-Language'] = 'de-AT, de'
>>> response.content_language
HeaderSet(['de-AT', 'de'])
Authentication headers can be set that way as well:
>>> response.www_authenticate.set_basic("My protected resource")
>>> response.headers['www-authenticate']
'Basic realm="My protected resource"'
Cookies can be set as well:
>>> response.set_cookie('name', 'value')
>>> response.headers['Set-Cookie']
'name=value; Path=/'
>>> response.set_cookie('name2', 'value2')
If headers appear multiple times you can use the :meth:`~Headers.getlist`
method to get all values for a header:
>>> response.headers.getlist('Set-Cookie')
['name=value; Path=/', 'name2=value2; Path=/']
Finally if you have set all the conditional values, you can make the
response conditional against a request. Which means that if the request
can assure that it has the information already, no data besides the headers
is sent over the network which saves traffic. For that you should set at
least an etag (which is used for comparison) and the date header and then
call :class:`~BaseRequest.make_conditional` with the request object.
The response is modified accordingly (status code changed, response body
removed, entity headers removed etc.)

View file

@ -1,116 +0,0 @@
.. _dealing-with-request-data:
Dealing with Request Data
=========================
.. module:: werkzeug
The most important rule about web development is "Do not trust the user".
This is especially true for incoming request data on the input stream.
With WSGI this is actually a bit harder than you would expect. Because
of that Werkzeug wraps the request stream for you to save you from the
most prominent problems with it.
Missing EOF Marker on Input Stream
----------------------------------
The input stream has no end-of-file marker. If you would call the
:meth:`~file.read` method on the `wsgi.input` stream you would cause your
application to hang on conforming servers. This is actually intentional
however painful. Werkzeug solves that problem by wrapping the input
stream in a special :class:`LimitedStream`. The input stream is exposed
on the request objects as :attr:`~BaseRequest.stream`. This one is either
an empty stream (if the form data was parsed) or a limited stream with
the contents of the input stream.
When does Werkzeug Parse?
-------------------------
Werkzeug parses the incoming data under the following situations:
- you access either :attr:`~BaseRequest.form`, :attr:`~BaseRequest.files`,
or :attr:`~BaseRequest.stream` and the request method was
`POST` or `PUT`.
- if you call :func:`parse_form_data`.
These calls are not interchangeable. If you invoke :func:`parse_form_data`
you must not use the request object or at least not the attributes that
trigger the parsing process.
This is also true if you read from the `wsgi.input` stream before the
parsing.
**General rule:** Leave the WSGI input stream alone. Especially in
WSGI middlewares. Use either the parsing functions or the request
object. Do not mix multiple WSGI utility libraries for form data
parsing or anything else that works on the input stream.
How does it Parse?
------------------
The standard Werkzeug parsing behavior handles three cases:
- input content type was `multipart/form-data`. In this situation the
:class:`~BaseRequest.stream` will be empty and
:class:`~BaseRequest.form` will contain the regular `POST` / `PUT`
data, :class:`~BaseRequest.files` will contain the uploaded
files as :class:`FileStorage` objects.
- input content type was `application/x-www-form-urlencoded`. Then the
:class:`~BaseRequest.stream` will be empty and
:class:`~BaseRequest.form` will contain the regular `POST` / `PUT`
data and :class:`~BaseRequest.files` will be empty.
- the input content type was neither of them, :class:`~BaseRequest.stream`
points to a :class:`LimitedStream` with the input data for further
processing.
Special note on the :attr:`~BaseRequest.get_data` method: Calling this
loads the full request data into memory. This is only safe to do if the
:attr:`~BaseRequest.max_content_length` is set. Also you can *either*
read the stream *or* call :meth:`~BaseRequest.get_data`.
Limiting Request Data
---------------------
To avoid being the victim of a DDOS attack you can set the maximum
accepted content length and request field sizes. The :class:`BaseRequest`
class has two attributes for that: :attr:`~BaseRequest.max_content_length`
and :attr:`~BaseRequest.max_form_memory_size`.
The first one can be used to limit the total content length. For example
by setting it to ``1024 * 1024 * 16`` the request won't accept more than
16MB of transmitted data.
Because certain data can't be moved to the hard disk (regular post data)
whereas temporary files can, there is a second limit you can set. The
:attr:`~BaseRequest.max_form_memory_size` limits the size of `POST`
transmitted form data. By setting it to ``1024 * 1024 * 2`` you can make
sure that all in memory-stored fields are not more than 2MB in size.
This however does *not* affect in-memory stored files if the
`stream_factory` used returns a in-memory file.
How to extend Parsing?
----------------------
Modern web applications transmit a lot more than multipart form data or
url encoded data. Extending the parsing capabilities by subclassing
the :class:`BaseRequest` is simple. The following example implements
parsing for incoming JSON data::
from werkzeug.utils import cached_property
from werkzeug.wrappers import Request
from simplejson import loads
class JSONRequest(Request):
# accept up to 4MB of transmitted data.
max_content_length = 1024 * 1024 * 4
@cached_property
def json(self):
if self.headers.get('content-type') == 'application/json':
return loads(self.data)

View file

@ -1,205 +0,0 @@
.. _routing:
===========
URL Routing
===========
.. module:: werkzeug.routing
.. testsetup::
from werkzeug.routing import *
When it comes to combining multiple controller or view functions (however
you want to call them), you need a dispatcher. A simple way would be
applying regular expression tests on ``PATH_INFO`` and call registered
callback functions that return the value.
Werkzeug provides a much more powerful system, similar to `Routes`_. All the
objects mentioned on this page must be imported from :mod:`werkzeug.routing`, not
from :mod:`werkzeug`!
.. _Routes: http://routes.groovie.org/
Quickstart
==========
Here is a simple example which could be the URL definition for a blog::
from werkzeug.routing import Map, Rule, NotFound, RequestRedirect
url_map = Map([
Rule('/', endpoint='blog/index'),
Rule('/<int:year>/', endpoint='blog/archive'),
Rule('/<int:year>/<int:month>/', endpoint='blog/archive'),
Rule('/<int:year>/<int:month>/<int:day>/', endpoint='blog/archive'),
Rule('/<int:year>/<int:month>/<int:day>/<slug>',
endpoint='blog/show_post'),
Rule('/about', endpoint='blog/about_me'),
Rule('/feeds/', endpoint='blog/feeds'),
Rule('/feeds/<feed_name>.rss', endpoint='blog/show_feed')
])
def application(environ, start_response):
urls = url_map.bind_to_environ(environ)
try:
endpoint, args = urls.match()
except HTTPException, e:
return e(environ, start_response)
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Rule points to %r with arguments %r' % (endpoint, args)]
So what does that do? First of all we create a new :class:`Map` which stores
a bunch of URL rules. Then we pass it a list of :class:`Rule` objects.
Each :class:`Rule` object is instantiated with a string that represents a rule
and an endpoint which will be the alias for what view the rule represents.
Multiple rules can have the same endpoint, but should have different arguments
to allow URL construction.
The format for the URL rules is straightforward, but explained in detail below.
Inside the WSGI application we bind the url_map to the current request which will
return a new :class:`MapAdapter`. This url_map adapter can then be used to match
or build domains for the current request.
The :meth:`MapAdapter.match` method can then either return a tuple in the form
``(endpoint, args)`` or raise one of the three exceptions
:exc:`~werkzeug.exceptions.NotFound`, :exc:`~werkzeug.exceptions.MethodNotAllowed`,
or :exc:`~werkzeug.exceptions.RequestRedirect`. For more details about those
exceptions have a look at the documentation of the :meth:`MapAdapter.match` method.
Rule Format
===========
Rule strings basically are just normal URL paths with placeholders in the
format ``<converter(arguments):name>``, where converter and the arguments
are optional. If no converter is defined, the `default` converter is used
(which means `string` in the normal configuration).
URL rules that end with a slash are branch URLs, others are leaves. If you
have `strict_slashes` enabled (which is the default), all branch URLs that are
visited without a trailing slash will trigger a redirect to the same URL with
that slash appended.
The list of converters can be extended, the default converters are explained
below.
Builtin Converters
==================
Here a list of converters that come with Werkzeug:
.. autoclass:: UnicodeConverter
.. autoclass:: PathConverter
.. autoclass:: AnyConverter
.. autoclass:: IntegerConverter
.. autoclass:: FloatConverter
.. autoclass:: UUIDConverter
Maps, Rules and Adapters
========================
.. autoclass:: Map
:members:
.. attribute:: converters
The dictionary of converters. This can be modified after the class
was created, but will only affect rules added after the
modification. If the rules are defined with the list passed to the
class, the `converters` parameter to the constructor has to be used
instead.
.. autoclass:: MapAdapter
:members:
.. autoclass:: Rule
:members: empty
Rule Factories
==============
.. autoclass:: RuleFactory
:members: get_rules
.. autoclass:: Subdomain
.. autoclass:: Submount
.. autoclass:: EndpointPrefix
Rule Templates
==============
.. autoclass:: RuleTemplate
Custom Converters
=================
You can easily add custom converters. The only thing you have to do is to
subclass :class:`BaseConverter` and pass that new converter to the url_map.
A converter has to provide two public methods: `to_python` and `to_url`,
as well as a member that represents a regular expression. Here is a small
example::
from random import randrange
from werkzeug.routing import Rule, Map, BaseConverter, ValidationError
class BooleanConverter(BaseConverter):
def __init__(self, url_map, randomify=False):
super(BooleanConverter, self).__init__(url_map)
self.randomify = randomify
self.regex = '(?:yes|no|maybe)'
def to_python(self, value):
if value == 'maybe':
if self.randomify:
return not randrange(2)
raise ValidationError()
return value == 'yes'
def to_url(self, value):
return value and 'yes' or 'no'
url_map = Map([
Rule('/vote/<bool:werkzeug_rocks>', endpoint='vote'),
Rule('/vote/<bool(randomify=True):foo>', endpoint='foo')
], converters={'bool': BooleanConverter})
If you want that converter to be the default converter, name it ``'default'``.
Host Matching
=============
.. versionadded:: 0.7
Starting with Werkzeug 0.7 it's also possible to do matching on the whole
host names instead of just the subdomain. To enable this feature you need
to pass ``host_matching=True`` to the :class:`Map` constructor and provide
the `host` argument to all routes::
url_map = Map([
Rule('/', endpoint='www_index', host='www.example.com'),
Rule('/', endpoint='help_index', host='help.example.com')
], host_matching=True)
Variable parts are of course also possible in the host section::
url_map = Map([
Rule('/', endpoint='www_index', host='www.example.com'),
Rule('/', endpoint='user_index', host='<user>.example.com')
], host_matching=True)

View file

@ -1,227 +0,0 @@
=========================
Serving WSGI Applications
=========================
.. module:: werkzeug.serving
There are many ways to serve a WSGI application. While you're developing it,
you usually don't want to have a full-blown webserver like Apache up and
running, but instead a simple standalone one. Because of that Werkzeug comes
with a builtin development server.
The easiest way is creating a small ``start-myproject.py`` file that runs the
application using the builtin server::
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from werkzeug.serving import run_simple
from myproject import make_app
app = make_app(...)
run_simple('localhost', 8080, app, use_reloader=True)
You can also pass it the `extra_files` keyword argument with a list of
additional files (like configuration files) you want to observe.
.. autofunction:: run_simple
.. autofunction:: is_running_from_reloader
.. autofunction:: make_ssl_devcert
.. admonition:: Information
The development server is not intended to be used on production systems.
It was designed especially for development purposes and performs poorly
under high load. For deployment setups have a look at the
:ref:`deployment` pages.
.. _reloader:
Reloader
--------
.. versionchanged:: 0.10
The Werkzeug reloader constantly monitors modules and paths of your web
application, and restarts the server if any of the observed files change.
Since version 0.10, there are two backends the reloader supports: ``stat`` and
``watchdog``.
- The default ``stat`` backend simply checks the ``mtime`` of all files in a
regular interval. This is sufficient for most cases, however, it is known to
drain a laptop's battery.
- The ``watchdog`` backend uses filesystem events, and is much faster than
``stat``. It requires the `watchdog <https://pypi.python.org/pypi/watchdog>`_
module to be installed. The recommended way to achieve this is to add
``Werkzeug[watchdog]`` to your requirements file.
If ``watchdog`` is installed and available it will automatically be used
instead of the builtin ``stat`` reloader.
To switch between the backends you can use the `reloader_type` parameter of the
:func:`run_simple` function. ``'stat'`` sets it to the default stat based
polling and ``'watchdog'`` forces it to the watchdog backend.
.. note::
Some edge cases, like modules that failed to import correctly, are not
handled by the stat reloader for performance reasons. The watchdog reloader
monitors such files too.
Colored Logging
---------------
Werkzeug is able to color the output of request logs when ran from a terminal, just install the `termcolor
<https://pypi.python.org/pypi/termcolor>`_ package. Windows users need to install `colorama
<https://pypi.python.org/pypi/colorama>`_ in addition to termcolor for this to work.
Virtual Hosts
-------------
Many web applications utilize multiple subdomains. This can be a bit tricky
to simulate locally. Fortunately there is the `hosts file`_ that can be used
to assign the local computer multiple names.
This allows you to call your local computer `yourapplication.local` and
`api.yourapplication.local` (or anything else) in addition to `localhost`.
You can find the hosts file on the following location:
=============== ==============================================
Windows ``%SystemRoot%\system32\drivers\etc\hosts``
Linux / OS X ``/etc/hosts``
=============== ==============================================
You can open the file with your favorite text editor and add a new name after
`localhost`::
127.0.0.1 localhost yourapplication.local api.yourapplication.local
Save the changes and after a while you should be able to access the
development server on these host names as well. You can use the
:ref:`routing` system to dispatch between different hosts or parse
:attr:`request.host` yourself.
Shutting Down The Server
------------------------
.. versionadded:: 0.7
Starting with Werkzeug 0.7 the development server provides a way to shut
down the server after a request. This currently only works with Python
2.6 and later and will only work with the development server. To initiate
the shutdown you have to call a function named
``'werkzeug.server.shutdown'`` in the WSGI environment::
def shutdown_server(environ):
if not 'werkzeug.server.shutdown' in environ:
raise RuntimeError('Not running the development server')
environ['werkzeug.server.shutdown']()
Troubleshooting
---------------
On operating systems that support ipv6 and have it configured such as modern
Linux systems, OS X 10.4 or higher as well as Windows Vista some browsers can
be painfully slow if accessing your local server. The reason for this is that
sometimes "localhost" is configured to be available on both ipv4 and ipv6 sockets
and some browsers will try to access ipv6 first and then ipv4.
At the current time the integrated webserver does not support ipv6 and ipv4 at
the same time and for better portability ipv4 is the default.
If you notice that the web browser takes ages to load the page there are two ways
around this issue. If you don't need ipv6 support you can disable the ipv6 entry
in the `hosts file`_ by removing this line::
::1 localhost
Alternatively you can also disable ipv6 support in your browser. For example
if Firefox shows this behavior you can disable it by going to ``about:config``
and disabling the `network.dns.disableIPv6` key. This however is not
recommended as of Werkzeug 0.6.1!
Starting with Werkzeug 0.6.1, the server will now switch between ipv4 and
ipv6 based on your operating system's configuration. This means if that
you disabled ipv6 support in your browser but your operating system is
preferring ipv6, you will be unable to connect to your server. In that
situation, you can either remove the localhost entry for ``::1`` or
explicitly bind the hostname to an ipv4 address (`127.0.0.1`)
.. _hosts file: http://en.wikipedia.org/wiki/Hosts_file
SSL
---
.. versionadded:: 0.6
The builtin server supports SSL for testing purposes. If an SSL context is
provided it will be used. That means a server can either run in HTTP or HTTPS
mode, but not both.
Quickstart
``````````
The easiest way to do SSL based development with Werkzeug is by using it
to generate an SSL certificate and private key and storing that somewhere
and to then put it there. For the certificate you need to provide the
name of your server on generation or a `CN`.
1. Generate an SSL key and store it somewhere:
>>> from werkzeug.serving import make_ssl_devcert
>>> make_ssl_devcert('/path/to/the/key', host='localhost')
('/path/to/the/key.crt', '/path/to/the/key.key')
2. Now this tuple can be passed as ``ssl_context`` to the
:func:`run_simple` method::
run_simple('localhost', 4000, application,
ssl_context=('/path/to/the/key.crt',
'/path/to/the/key.key'))
You will have to acknowledge the certificate in your browser once then.
Loading Contexts by Hand
````````````````````````
In Python 2.7.9 and 3+ you also have the option to use a ``ssl.SSLContext``
object instead of a simple tuple. This way you have better control over the SSL
behavior of Werkzeug's builtin server::
import ssl
ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ctx.load_cert_chain('ssl.cert', 'ssl.key')
run_simple('localhost', 4000, application, ssl_context=ctx)
.. versionchanged 0.10:: ``OpenSSL`` contexts are not supported anymore.
Generating Certificates
```````````````````````
A key and certificate can be created in advance using the openssl tool
instead of the :func:`make_ssl_devcert`. This requires that you have
the `openssl` command installed on your system::
$ openssl genrsa 1024 > ssl.key
$ openssl req -new -x509 -nodes -sha1 -days 365 -key ssl.key > ssl.cert
Adhoc Certificates
``````````````````
The easiest way to enable SSL is to start the server in adhoc-mode. In
that case Werkzeug will generate an SSL certificate for you::
run_simple('localhost', 4000, application,
ssl_context='adhoc')
The downside of this of course is that you will have to acknowledge the
certificate each time the server is reloaded. Adhoc certificates are
discouraged because modern browsers do a bad job at supporting them for
security reasons.
This feature requires the pyOpenSSL library to be installed.

View file

@ -1,44 +0,0 @@
===============
Important Terms
===============
.. module:: werkzeug
This page covers important terms used in the documentation and Werkzeug
itself.
WSGI
----
WSGI a specification for Python web applications Werkzeug follows. It was
specified in the :pep:`333` and is widely supported. Unlike previous solutions
it guarantees that web applications, servers and utilities can work together.
Response Object
---------------
For Werkzeug, a response object is an object that works like a WSGI
application but does not do any request processing. Usually you have a view
function or controller method that processes the request and assembles a
response object.
A response object is *not* necessarily the :class:`BaseResponse` object or a
subclass thereof.
For example Pylons/webob provide a very similar response class that can
be used as well (:class:`webob.Response`).
View Function
-------------
Often people speak of MVC (Model, View, Controller) when developing web
applications. However, the Django framework coined MTV (Model, Template,
View) which basically means the same but reduces the concept to the data
model, a function that processes data from the request and the database and
renders a template.
Werkzeug itself does not tell you how you should develop applications, but the
documentation often speaks of view functions that work roughly the same. The
idea of a view function is that it's called with a request object (and
optionally some parameters from an URL rule) and returns a response object.

View file

@ -1,172 +0,0 @@
==============
Test Utilities
==============
.. module:: werkzeug.test
Quite often you want to unittest your application or just check the output
from an interactive python session. In theory that is pretty simple because
you can fake a WSGI environment and call the application with a dummy
`start_response` and iterate over the application iterator but there are
argumentably better ways to interact with an application.
Diving In
=========
Werkzeug provides a `Client` object which you can pass a WSGI application (and
optionally a response wrapper) which you can use to send virtual requests to
the application.
A response wrapper is a callable that takes three arguments: the application
iterator, the status and finally a list of headers. The default response
wrapper returns a tuple. Because response objects have the same signature,
you can use them as response wrapper, ideally by subclassing them and hooking
in test functionality.
>>> from werkzeug.test import Client
>>> from werkzeug.testapp import test_app
>>> from werkzeug.wrappers import BaseResponse
>>> c = Client(test_app, BaseResponse)
>>> resp = c.get('/')
>>> resp.status_code
200
>>> resp.headers
Headers([('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '8339')])
>>> resp.data.splitlines()[0]
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"'
Or without a wrapper defined:
>>> c = Client(test_app)
>>> app_iter, status, headers = c.get('/')
>>> status
'200 OK'
>>> headers
[('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '8339')]
>>> ''.join(app_iter).splitlines()[0]
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"'
Environment Building
====================
.. versionadded:: 0.5
The easiest way to interactively test applications is using the
:class:`EnvironBuilder`. It can create both standard WSGI environments
and request objects.
The following example creates a WSGI environment with one uploaded file
and a form field:
>>> from werkzeug.test import EnvironBuilder
>>> from StringIO import StringIO
>>> builder = EnvironBuilder(method='POST', data={'foo': 'this is some text',
... 'file': (StringIO('my file contents'), 'test.txt')})
>>> env = builder.get_environ()
The resulting environment is a regular WSGI environment that can be used for
further processing:
>>> from werkzeug.wrappers import Request
>>> req = Request(env)
>>> req.form['foo']
u'this is some text'
>>> req.files['file']
<FileStorage: u'test.txt' ('text/plain')>
>>> req.files['file'].read()
'my file contents'
The :class:`EnvironBuilder` figures out the content type automatically if you
pass a dict to the constructor as `data`. If you provide a string or an
input stream you have to do that yourself.
By default it will try to use ``application/x-www-form-urlencoded`` and only
use ``multipart/form-data`` if files are uploaded:
>>> builder = EnvironBuilder(method='POST', data={'foo': 'bar'})
>>> builder.content_type
'application/x-www-form-urlencoded'
>>> builder.files['foo'] = StringIO('contents')
>>> builder.content_type
'multipart/form-data'
If a string is provided as data (or an input stream) you have to specify
the content type yourself:
>>> builder = EnvironBuilder(method='POST', data='{"json": "this is"}')
>>> builder.content_type
>>> builder.content_type = 'application/json'
Testing API
===========
.. autoclass:: EnvironBuilder
:members:
.. attribute:: path
The path of the application. (aka `PATH_INFO`)
.. attribute:: charset
The charset used to encode unicode data.
.. attribute:: headers
A :class:`Headers` object with the request headers.
.. attribute:: errors_stream
The error stream used for the `wsgi.errors` stream.
.. attribute:: multithread
The value of `wsgi.multithread`
.. attribute:: multiprocess
The value of `wsgi.multiprocess`
.. attribute:: environ_base
The dict used as base for the newly create environ.
.. attribute:: environ_overrides
A dict with values that are used to override the generated environ.
.. attribute:: input_stream
The optional input stream. This and :attr:`form` / :attr:`files`
is mutually exclusive. Also do not provide this stream if the
request method is not `POST` / `PUT` or something comparable.
.. autoclass:: Client
.. automethod:: open
Shortcut methods are available for many HTTP methods:
.. automethod:: get
.. automethod:: patch
.. automethod:: post
.. automethod:: head
.. automethod:: put
.. automethod:: delete
.. automethod:: options
.. automethod:: trace
.. autofunction:: create_environ([options])
.. autofunction:: run_wsgi_app

View file

@ -1,73 +0,0 @@
Transition to Werkzeug 1.0
==========================
Werkzeug originally had a magical import system hook that enabled
everything to be imported from one module and still loading the actual
implementations lazily as necessary. Unfortunately this turned out to be
slow and also unreliable on alternative Python implementations and
Google's App Engine.
Starting with 0.7 we recommend against the short imports and strongly
encourage starting importing from the actual implementation module.
Werkzeug 1.0 will disable the magical import hook completely.
Because finding out where the actual functions are imported and rewriting
them by hand is a painful and boring process we wrote a tool that aids in
making this transition.
Automatically Rewriting Imports
-------------------------------
For instance, with Werkzeug < 0.7 the recommended way to use the escape function
was this::
from werkzeug import escape
With Werkzeug 0.7, the recommended way to import this function is
directly from the utils module (and with 1.0 this will become mandatory).
To automatically rewrite all imports one can use the
`werkzeug-import-rewrite <http://bit.ly/import-rewrite>`_ script.
You can use it by executing it with Python and with a list of folders with
Werkzeug based code. It will then spit out a hg/git compatible patch
file. Example patch file creation::
$ python werkzeug-import-rewrite.py . > new-imports.udiff
To apply the patch one of the following methods work:
hg:
::
hg import new-imports.udiff
git:
::
git apply new-imports.udiff
patch:
::
patch -p1 < new-imports.udiff
Stop Using Deprecated Things
----------------------------
A few things in Werkzeug will stop being supported and for others, we're
suggesting alternatives even if they will stick around for a longer time.
Do not use:
- `werkzeug.script`, replace it with custom scripts written with
`argparse` or something similar.
- `werkzeug.template`, replace with a proper template engine.
- `werkzeug.contrib.jsrouting`, stop using URL generation for
JavaScript, it does not scale well with many public routing.
- `werkzeug.contrib.kickstart`, replace with hand written code, the
Werkzeug API became better in general that this is no longer
necessary.
- `werkzeug.contrib.testtools`, not useful really.

View file

@ -1,475 +0,0 @@
=================
Werkzeug Tutorial
=================
.. module:: werkzeug
Welcome to the Werkzeug tutorial in which we will create a `TinyURL`_ clone
that stores URLs in a redis instance. The libraries we will use for this
applications are `Jinja`_ 2 for the templates, `redis`_ for the database
layer and, of course, Werkzeug for the WSGI layer.
You can use `pip` to install the required libraries::
pip install Jinja2 redis Werkzeug
Also make sure to have a redis server running on your local machine. If
you are on OS X, you can use `brew` to install it::
brew install redis
If you are on Ubuntu or Debian, you can use apt-get::
sudo apt-get install redis-server
Redis was developed for UNIX systems and was never really designed to
work on Windows. For development purposes, the unofficial ports however
work well enough. You can get them from `github
<https://github.com/dmajkic/redis/downloads>`_.
Introducing Shortly
-------------------
In this tutorial, we will together create a simple URL shortener service
with Werkzeug. Please keep in mind that Werkzeug is not a framework, it's
a library with utilities to create your own framework or application and
as such is very flexible. The approach we use here is just one of many you
can use.
As data store, we will use `redis`_ here instead of a relational database
to keep this simple and because that's the kind of job that `redis`_
excels at.
The final result will look something like this:
.. image:: _static/shortly.png
:alt: a screenshot of shortly
.. _TinyURL: http://tinyurl.com/
.. _Jinja: http://jinja.pocoo.org/
.. _redis: http://redis.io/
Step 0: A Basic WSGI Introduction
---------------------------------
Werkzeug is a utility library for WSGI. WSGI itself is a protocol or
convention that ensures that your web application can speak with the
webserver and more importantly that web applications work nicely together.
A basic “Hello World” application in WSGI without the help of Werkzeug
looks like this::
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello World!']
A WSGI application is something you can call and pass an environ dict
and a ``start_response`` callable. The environ contains all incoming
information, the ``start_response`` function can be used to indicate the
start of the response. With Werkzeug you don't have to deal directly with
either as request and response objects are provided to work with them.
The request data takes the environ object and allows you to access the
data from that environ in a nice manner. The response object is a WSGI
application in itself and provides a much nicer way to create responses.
Here is how you would write that application with response objects::
from werkzeug.wrappers import Response
def application(environ, start_response):
response = Response('Hello World!', mimetype='text/plain')
return response(environ, start_response)
And here an expanded version that looks at the query string in the URL
(more importantly at the `name` parameter in the URL to substitute “World”
against another word)::
from werkzeug.wrappers import Request, Response
def application(environ, start_response):
request = Request(environ)
text = 'Hello %s!' % request.args.get('name', 'World')
response = Response(text, mimetype='text/plain')
return response(environ, start_response)
And that's all you need to know about WSGI.
Step 1: Creating the Folders
----------------------------
Before we get started, lets create the folders needed for this application::
/shortly
/static
/templates
The shortly folder is not a python package, but just something where we
drop our files. Directly into this folder we will then put our main
module in the following steps. The files inside the static folder are
available to users of the application via HTTP. This is the place where
CSS and JavaScript files go. Inside the templates folder we will make
Jinja2 look for templates. The templates you create later in the tutorial
will go in this directory.
Step 2: The Base Structure
--------------------------
Now let's get right into it and create a module for our application. Let's
create a file called `shortly.py` in the `shortly` folder. At first we
will need a bunch of imports. I will pull in all the imports here, even
if they are not used right away, to keep it from being confusing::
import os
import redis
import urlparse
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, NotFound
from werkzeug.wsgi import SharedDataMiddleware
from werkzeug.utils import redirect
from jinja2 import Environment, FileSystemLoader
Then we can create the basic structure for our application and a function
to create a new instance of it, optionally with a piece of WSGI middleware
that exports all the files on the `static` folder on the web::
class Shortly(object):
def __init__(self, config):
self.redis = redis.Redis(config['redis_host'], config['redis_port'])
def dispatch_request(self, request):
return Response('Hello World!')
def wsgi_app(self, environ, start_response):
request = Request(environ)
response = self.dispatch_request(request)
return response(environ, start_response)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def create_app(redis_host='localhost', redis_port=6379, with_static=True):
app = Shortly({
'redis_host': redis_host,
'redis_port': redis_port
})
if with_static:
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
'/static': os.path.join(os.path.dirname(__file__), 'static')
})
return app
Lastly we can add a piece of code that will start a local development
server with automatic code reloading and a debugger::
if __name__ == '__main__':
from werkzeug.serving import run_simple
app = create_app()
run_simple('127.0.0.1', 5000, app, use_debugger=True, use_reloader=True)
The basic idea here is that our ``Shortly`` class is an actual WSGI
application. The ``__call__`` method directly dispatches to ``wsgi_app``.
This is done so that we can wrap ``wsgi_app`` to apply middlewares like we
do in the ``create_app`` function. The actual ``wsgi_app`` method then
creates a :class:`Request` object and calls the ``dispatch_request``
method which then has to return a :class:`Response` object which is then
evaluated as WSGI application again. As you can see: turtles all the way
down. Both the ``Shortly`` class we create, as well as any request object
in Werkzeug implements the WSGI interface. As a result of that you could
even return another WSGI application from the ``dispatch_request`` method.
The ``create_app`` factory function can be used to create a new instance
of our application. Not only will it pass some parameters as
configuration to the application but also optionally add a WSGI middleware
that exports static files. This way we have access to the files from the
static folder even when we are not configuring our server to provide them
which is very helpful for development.
Intermezzo: Running the Application
-----------------------------------
Now you should be able to execute the file with `python` and see a server
on your local machine::
$ python shortly.py
* Running on http://127.0.0.1:5000/
* Restarting with reloader: stat() polling
It also tells you that the reloader is active. It will use various
techniques to figure out if any file changed on the disk and then
automatically restart.
Just go to the URL and you should see “Hello World!”.
Step 3: The Environment
-----------------------
Now that we have the basic application class, we can make the constructor
do something useful and provide a few helpers on there that can come in
handy. We will need to be able to render templates and connect to redis,
so let's extend the class a bit::
def __init__(self, config):
self.redis = redis.Redis(config['redis_host'], config['redis_port'])
template_path = os.path.join(os.path.dirname(__file__), 'templates')
self.jinja_env = Environment(loader=FileSystemLoader(template_path),
autoescape=True)
def render_template(self, template_name, **context):
t = self.jinja_env.get_template(template_name)
return Response(t.render(context), mimetype='text/html')
Step 4: The Routing
-------------------
Next up is routing. Routing is the process of matching and parsing the URL to
something we can use. Werkzeug provides a flexible integrated routing
system which we can use for that. The way it works is that you create a
:class:`~werkzeug.routing.Map` instance and add a bunch of
:class:`~werkzeug.routing.Rule` objects. Each rule has a pattern it will
try to match the URL against and an “endpoint”. The endpoint is typically
a string and can be used to uniquely identify the URL. We could also use
this to automatically reverse the URL, but that's not what we will do in this
tutorial.
Just put this into the constructor::
self.url_map = Map([
Rule('/', endpoint='new_url'),
Rule('/<short_id>', endpoint='follow_short_link'),
Rule('/<short_id>+', endpoint='short_link_details')
])
Here we create a URL map with three rules. ``/`` for the root of the URL
space where we will just dispatch to a function that implements the logic
to create a new URL. And then one that follows the short link to the
target URL and another one with the same rule but a plus (``+``) at the
end to show the link details.
So how do we find our way from the endpoint to a function? That's up to you.
The way we will do it in this tutorial is by calling the method ``on_``
+ endpoint on the class itself. Here is how this works::
def dispatch_request(self, request):
adapter = self.url_map.bind_to_environ(request.environ)
try:
endpoint, values = adapter.match()
return getattr(self, 'on_' + endpoint)(request, **values)
except HTTPException, e:
return e
We bind the URL map to the current environment and get back a
:class:`~werkzeug.routing.URLAdapter`. The adapter can be used to match
the request but also to reverse URLs. The match method will return the
endpoint and a dictionary of values in the URL. For instance the rule for
``follow_short_link`` has a variable part called ``short_id``. When we go
to ``http://localhost:5000/foo`` we will get the following values back::
endpoint = 'follow_short_link'
values = {'short_id': u'foo'}
If it does not match anything, it will raise a
:exc:`~werkzeug.exceptions.NotFound` exception, which is an
:exc:`~werkzeug.exceptions.HTTPException`. All HTTP exceptions are also
WSGI applications by themselves which render a default error page. So we
just catch all of them down and return the error itself.
If all works well, we call the function ``on_`` + endpoint and pass it the
request as argument as well as all the URL arguments as keyword arguments
and return the response object that method returns.
Step 5: The First View
----------------------
Let's start with the first view: the one for new URLs::
def on_new_url(self, request):
error = None
url = ''
if request.method == 'POST':
url = request.form['url']
if not is_valid_url(url):
error = 'Please enter a valid URL'
else:
short_id = self.insert_url(url)
return redirect('/%s+' % short_id)
return self.render_template('new_url.html', error=error, url=url)
This logic should be easy to understand. Basically we are checking that
the request method is POST, in which case we validate the URL and add a
new entry to the database, then redirect to the detail page. This means
we need to write a function and a helper method. For URL validation this
is good enough::
def is_valid_url(url):
parts = urlparse.urlparse(url)
return parts.scheme in ('http', 'https')
For inserting the URL, all we need is this little method on our class::
def insert_url(self, url):
short_id = self.redis.get('reverse-url:' + url)
if short_id is not None:
return short_id
url_num = self.redis.incr('last-url-id')
short_id = base36_encode(url_num)
self.redis.set('url-target:' + short_id, url)
self.redis.set('reverse-url:' + url, short_id)
return short_id
``reverse-url:`` + the URL will store the short id. If the URL was
already submitted this won't be None and we can just return that value
which will be the short ID. Otherwise we increment the ``last-url-id``
key and convert it to base36. Then we store the link and the reverse
entry in redis. And here the function to convert to base 36::
def base36_encode(number):
assert number >= 0, 'positive integer required'
if number == 0:
return '0'
base36 = []
while number != 0:
number, i = divmod(number, 36)
base36.append('0123456789abcdefghijklmnopqrstuvwxyz'[i])
return ''.join(reversed(base36))
So what is missing for this view to work is the template. We will create
this later, let's first also write the other views and then do the
templates in one go.
Step 6: Redirect View
---------------------
The redirect view is easy. All it has to do is to look for the link in
redis and redirect to it. Additionally we will also increment a counter
so that we know how often a link was clicked::
def on_follow_short_link(self, request, short_id):
link_target = self.redis.get('url-target:' + short_id)
if link_target is None:
raise NotFound()
self.redis.incr('click-count:' + short_id)
return redirect(link_target)
In this case we will raise a :exc:`~werkzeug.exceptions.NotFound` exception
by hand if the URL does not exist, which will bubble up to the
``dispatch_request`` function and be converted into a default 404
response.
Step 7: Detail View
-------------------
The link detail view is very similar, we just render a template
again. In addition to looking up the target, we also ask redis for the
number of times the link was clicked and let it default to zero if such
a key does not yet exist::
def on_short_link_details(self, request, short_id):
link_target = self.redis.get('url-target:' + short_id)
if link_target is None:
raise NotFound()
click_count = int(self.redis.get('click-count:' + short_id) or 0)
return self.render_template('short_link_details.html',
link_target=link_target,
short_id=short_id,
click_count=click_count
)
Please be aware that redis always works with strings, so you have to convert
the click count to :class:`int` by hand.
Step 8: Templates
-----------------
And here are all the templates. Just drop them into the `templates`
folder. Jinja2 supports template inheritance, so the first thing we will
do is create a layout template with blocks that act as placeholders. We
also set up Jinja2 so that it automatically escapes strings with HTML
rules, so we don't have to spend time on that ourselves. This prevents
XSS attacks and rendering errors.
*layout.html*:
.. sourcecode:: html+jinja
<!doctype html>
<title>{% block title %}{% endblock %} | shortly</title>
<link rel=stylesheet href=/static/style.css type=text/css>
<div class=box>
<h1><a href=/>shortly</a></h1>
<p class=tagline>Shortly is a URL shortener written with Werkzeug
{% block body %}{% endblock %}
</div>
*new_url.html*:
.. sourcecode:: html+jinja
{% extends "layout.html" %}
{% block title %}Create New Short URL{% endblock %}
{% block body %}
<h2>Submit URL</h2>
<form action="" method=post>
{% if error %}
<p class=error><strong>Error:</strong> {{ error }}
{% endif %}
<p>URL:
<input type=text name=url value="{{ url }}" class=urlinput>
<input type=submit value="Shorten">
</form>
{% endblock %}
*short_link_details.html*:
.. sourcecode:: html+jinja
{% extends "layout.html" %}
{% block title %}Details about /{{ short_id }}{% endblock %}
{% block body %}
<h2><a href="/{{ short_id }}">/{{ short_id }}</a></h2>
<dl>
<dt>Full link
<dd class=link><div>{{ link_target }}</div>
<dt>Click count:
<dd>{{ click_count }}
</dl>
{% endblock %}
Step 9: The Style
-----------------
For this to look better than ugly black and white, here a simple
stylesheet that goes along:
.. sourcecode:: css
body { background: #E8EFF0; margin: 0; padding: 0; }
body, input { font-family: 'Helvetica Neue', Arial,
sans-serif; font-weight: 300; font-size: 18px; }
.box { width: 500px; margin: 60px auto; padding: 20px;
background: white; box-shadow: 0 1px 4px #BED1D4;
border-radius: 2px; }
a { color: #11557C; }
h1, h2 { margin: 0; color: #11557C; }
h1 a { text-decoration: none; }
h2 { font-weight: normal; font-size: 24px; }
.tagline { color: #888; font-style: italic; margin: 0 0 20px 0; }
.link div { overflow: auto; font-size: 0.8em; white-space: pre;
padding: 4px 10px; margin: 5px 0; background: #E5EAF1; }
dt { font-weight: normal; }
.error { background: #E8EFF0; padding: 3px 8px; color: #11557C;
font-size: 0.9em; border-radius: 2px; }
.urlinput { width: 300px; }
Bonus: Refinements
------------------
Look at the implementation in the example dictionary in the Werkzeug
repository to see a version of this tutorial with some small refinements
such as a custom 404 page.
- `shortly in the example folder <https://github.com/pallets/werkzeug/blob/master/examples/shortly>`_

View file

@ -1,158 +0,0 @@
.. _unicode:
=======
Unicode
=======
.. module:: werkzeug
Since early Python 2 days unicode was part of all default Python builds. It
allows developers to write applications that deal with non-ASCII characters
in a straightforward way. But working with unicode requires a basic knowledge
about that matter, especially when working with libraries that do not support
it.
Werkzeug uses unicode internally everywhere text data is assumed, even if the
HTTP standard is not unicode aware as it. Basically all incoming data is
decoded from the charset specified (per default `utf-8`) so that you don't
operate on bytestrings any more. Outgoing unicode data is then encoded into
the target charset again.
Unicode in Python
=================
In Python 2 there are two basic string types: `str` and `unicode`. `str` may
carry encoded unicode data but it's always represented in bytes whereas the
`unicode` type does not contain bytes but charpoints. What does this mean?
Imagine you have the German Umlaut `ö`. In ASCII you cannot represent that
character, but in the `latin-1` and `utf-8` character sets you can represent
it, but they look differently when encoded:
>>> u'ö'.encode('latin1')
'\xf6'
>>> u'ö'.encode('utf-8')
'\xc3\xb6'
So an `ö` might look totally different depending on the encoding which makes
it hard to work with it. The solution is using the `unicode` type (as we did
above, note the `u` prefix before the string). The unicode type does not
store the bytes for `ö` but the information, that this is a
``LATIN SMALL LETTER O WITH DIAERESIS``.
Doing ``len(u'ö')`` will always give us the expected "1" but ``len('ö')``
might give different results depending on the encoding of ``'ö'``.
Unicode in HTTP
===============
The problem with unicode is that HTTP does not know what unicode is. HTTP
is limited to bytes but this is not a big problem as Werkzeug decodes and
encodes for us automatically all incoming and outgoing data. Basically what
this means is that data sent from the browser to the web application is per
default decoded from an utf-8 bytestring into a `unicode` string. Data sent
from the application back to the browser that is not yet a bytestring is then
encoded back to utf-8.
Usually this "just works" and we don't have to worry about it, but there are
situations where this behavior is problematic. For example the Python 2 IO
layer is not unicode aware. This means that whenever you work with data from
the file system you have to properly decode it. The correct way to load
a text file from the file system looks like this::
f = file('/path/to/the_file.txt', 'r')
try:
text = f.decode('utf-8') # assuming the file is utf-8 encoded
finally:
f.close()
There is also the codecs module which provides an open function that decodes
automatically from the given encoding.
Error Handling
==============
With Werkzeug 0.3 onwards you can further control the way Werkzeug works with
unicode. In the past Werkzeug ignored encoding errors silently on incoming
data. This decision was made to avoid internal server errors if the user
tampered with the submitted data. However there are situations where you
want to abort with a `400 BAD REQUEST` instead of silently ignoring the error.
All the functions that do internal decoding now accept an `errors` keyword
argument that behaves like the `errors` parameter of the builtin string method
`decode`. The following values are possible:
`ignore`
This is the default behavior and tells the codec to ignore characters that
it doesn't understand silently.
`replace`
The codec will replace unknown characters with a replacement character
(`U+FFFD` ``REPLACEMENT CHARACTER``)
`strict`
Raise an exception if decoding fails.
Unlike the regular python decoding Werkzeug does not raise an
:exc:`UnicodeDecodeError` if the decoding failed but an
:exc:`~exceptions.HTTPUnicodeError` which
is a direct subclass of `UnicodeError` and the `BadRequest` HTTP exception.
The reason is that if this exception is not caught by the application but
a catch-all for HTTP exceptions exists a default `400 BAD REQUEST` error
page is displayed.
There is additional error handling available which is a Werkzeug extension
to the regular codec error handling which is called `fallback`. Often you
want to use utf-8 but support latin1 as legacy encoding too if decoding
failed. For this case you can use the `fallback` error handling. For
example you can specify ``'fallback:iso-8859-15'`` to tell Werkzeug it should
try with `iso-8859-15` if `utf-8` failed. If this decoding fails too (which
should not happen for most legacy charsets such as `iso-8859-15`) the error
is silently ignored as if the error handling was `ignore`.
Further details are available as part of the API documentation of the concrete
implementations of the functions or classes working with unicode.
Request and Response Objects
============================
As request and response objects usually are the central entities of Werkzeug
powered applications you can change the default encoding Werkzeug operates on
by subclassing these two classes. For example you can easily set the
application to utf-7 and strict error handling::
from werkzeug.wrappers import BaseRequest, BaseResponse
class Request(BaseRequest):
charset = 'utf-7'
encoding_errors = 'strict'
class Response(BaseResponse):
charset = 'utf-7'
Keep in mind that the error handling is only customizable for all decoding
but not encoding. If Werkzeug encounters an encoding error it will raise a
:exc:`UnicodeEncodeError`. It's your responsibility to not create data that is
not present in the target charset (a non issue with all unicode encodings
such as utf-8).
.. _filesystem-encoding:
The Filesystem
==============
.. versionchanged:: 0.11
Up until version 0.11, Werkzeug used Python's stdlib functionality to detect
the filesystem encoding. However, several bug reports against Werkzeug have
shown that the value of :py:func:`sys.getfilesystemencoding` cannot be
trusted under traditional UNIX systems. The usual problems come from
misconfigured systems, where ``LANG`` and similar environment variables are not
set. In such cases, Python would default to ASCII as filesystem encoding, a
very conservative default that is usually wrong and causes more problems than
it avoids.
Therefore Werkzeug will force the filesystem encoding to ``UTF-8`` and issue a
warning whenever it detects that it is running under BSD or Linux, and
:py:func:`sys.getfilesystemencoding` is returning an ASCII encoding.
See also :py:mod:`werkzeug.filesystem`.

View file

@ -1,6 +0,0 @@
===========
URL Helpers
===========
.. automodule:: werkzeug.urls
:members:

View file

@ -1,80 +0,0 @@
=========
Utilities
=========
Various utility functions shipped with Werkzeug.
HTML Helpers
============
.. module:: werkzeug.utils
.. autoclass:: HTMLBuilder
.. autofunction:: escape
.. autofunction:: unescape
General Helpers
===============
.. autoclass:: cached_property
:members:
.. autoclass:: environ_property
.. autoclass:: header_property
.. autofunction:: parse_cookie
.. autofunction:: dump_cookie
.. autofunction:: redirect
.. autofunction:: append_slash_redirect
.. autofunction:: import_string
.. autofunction:: find_modules
.. autofunction:: validate_arguments
.. autofunction:: secure_filename
.. autofunction:: bind_arguments
URL Helpers
===========
Please refer to :doc:`urls`.
UserAgent Parsing
=================
.. module:: werkzeug.useragents
.. autoclass:: UserAgent
:members:
Security Helpers
================
.. module:: werkzeug.security
.. versionadded:: 0.6.1
.. autofunction:: generate_password_hash
.. autofunction:: check_password_hash
.. autofunction:: safe_str_cmp
.. autofunction:: safe_join
.. autofunction:: pbkdf2_hex
.. autofunction:: pbkdf2_bin

View file

@ -1,15 +0,0 @@
# -*- coding: utf-8 -*-
"""
Werkzeug Sphinx Extensions
~~~~~~~~~~~~~~~~~~~~~~~~~~
Provides some more helpers for the werkzeug docs.
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from sphinx.ext.autodoc import cut_lines
def setup(app):
app.connect('autodoc-process-docstring', cut_lines(3, 3, what=['module']))

View file

@ -1,119 +0,0 @@
\definecolor{TitleColor}{rgb}{0,0,0}
\definecolor{InnerLinkColor}{rgb}{0,0,0}
\definecolor{OuterLinkColor}{rgb}{1.0,0.5,0.0}
\renewcommand{\maketitle}{%
\begin{titlepage}%
\let\footnotesize\small
\let\footnoterule\relax
\ifsphinxpdfoutput
\begingroup
% This \def is required to deal with multi-line authors; it
% changes \\ to ', ' (comma-space), making it pass muster for
% generating document info in the PDF file.
\def\\{, }
\pdfinfo{
/Author (\@author)
/Title (\@title)
}
\endgroup
\fi
\begin{flushright}%
%\sphinxlogo%
{\center
\vspace*{3cm}
\includegraphics{logo.pdf}
\vspace{3cm}
\par
{\rm\Huge \@title \par}%
{\em\LARGE \py@release\releaseinfo \par}
{\large
\@date \par
\py@authoraddress \par
}}%
\end{flushright}%\par
\@thanks
\end{titlepage}%
\cleardoublepage%
\setcounter{footnote}{0}%
\let\thanks\relax\let\maketitle\relax
%\gdef\@thanks{}\gdef\@author{}\gdef\@title{}
}
\fancypagestyle{normal}{
\fancyhf{}
\fancyfoot[LE,RO]{{\thepage}}
\fancyfoot[LO]{{\nouppercase{\rightmark}}}
\fancyfoot[RE]{{\nouppercase{\leftmark}}}
\fancyhead[LE,RO]{{ \@title, \py@release}}
\renewcommand{\headrulewidth}{0.4pt}
\renewcommand{\footrulewidth}{0.4pt}
}
\fancypagestyle{plain}{
\fancyhf{}
\fancyfoot[LE,RO]{{\thepage}}
\renewcommand{\headrulewidth}{0pt}
\renewcommand{\footrulewidth}{0.4pt}
}
\titleformat{\section}{\Large}%
{\py@TitleColor\thesection}{0.5em}{\py@TitleColor}{\py@NormalColor}
\titleformat{\subsection}{\large}%
{\py@TitleColor\thesubsection}{0.5em}{\py@TitleColor}{\py@NormalColor}
\titleformat{\subsubsection}{}%
{\py@TitleColor\thesubsubsection}{0.5em}{\py@TitleColor}{\py@NormalColor}
\titleformat{\paragraph}{\large}%
{\py@TitleColor}{0em}{\py@TitleColor}{\py@NormalColor}
\ChNameVar{\raggedleft\normalsize}
\ChNumVar{\raggedleft \bfseries\Large}
\ChTitleVar{\raggedleft \rm\Huge}
\renewcommand\thepart{\@Roman\c@part}
\renewcommand\part{%
\pagestyle{plain}
\if@noskipsec \leavevmode \fi
\cleardoublepage
\vspace*{6cm}%
\@afterindentfalse
\secdef\@part\@spart}
\def\@part[#1]#2{%
\ifnum \c@secnumdepth >\m@ne
\refstepcounter{part}%
\addcontentsline{toc}{part}{\thepart\hspace{1em}#1}%
\else
\addcontentsline{toc}{part}{#1}%
\fi
{\parindent \z@ %\center
\interlinepenalty \@M
\normalfont
\ifnum \c@secnumdepth >\m@ne
\rm\Large \partname~\thepart
\par\nobreak
\fi
\MakeUppercase{\rm\Huge #2}%
\markboth{}{}\par}%
\nobreak
\vskip 8ex
\@afterheading}
\def\@spart#1{%
{\parindent \z@ %\center
\interlinepenalty \@M
\normalfont
\huge \bfseries #1\par}%
\nobreak
\vskip 3ex
\@afterheading}
% use inconsolata font
\usepackage{inconsolata}
% fix single quotes, for inconsolata. (does not work)
%%\usepackage{textcomp}
%%\begingroup
%% \catcode`'=\active
%% \g@addto@macro\@noligs{\let'\textsinglequote}
%% \endgroup
%%\endinput

View file

@ -1,178 +0,0 @@
.. _wrappers:
==========================
Request / Response Objects
==========================
.. module:: werkzeug.wrappers
The request and response objects wrap the WSGI environment or the return
value from a WSGI application so that it is another WSGI application
(wraps a whole application).
How they Work
=============
Your WSGI application is always passed two arguments. The WSGI "environment"
and the WSGI `start_response` function that is used to start the response
phase. The :class:`Request` class wraps the `environ` for easier access to
request variables (form data, request headers etc.).
The :class:`Response` on the other hand is a standard WSGI application that
you can create. The simple hello world in Werkzeug looks like this::
from werkzeug.wrappers import Response
application = Response('Hello World!')
To make it more useful you can replace it with a function and do some
processing::
from werkzeug.wrappers import Request, Response
def application(environ, start_response):
request = Request(environ)
response = Response("Hello %s!" % request.args.get('name', 'World!'))
return response(environ, start_response)
Because this is a very common task the :class:`~Request` object provides
a helper for that. The above code can be rewritten like this::
from werkzeug.wrappers import Request, Response
@Request.application
def application(request):
return Response("Hello %s!" % request.args.get('name', 'World!'))
The `application` is still a valid WSGI application that accepts the
environment and `start_response` callable.
Mutability and Reusability of Wrappers
======================================
The implementation of the Werkzeug request and response objects are trying
to guard you from common pitfalls by disallowing certain things as much as
possible. This serves two purposes: high performance and avoiding of
pitfalls.
For the request object the following rules apply:
1. The request object is immutable. Modifications are not supported by
default, you may however replace the immutable attributes with mutable
attributes if you need to modify it.
2. The request object may be shared in the same thread, but is not thread
safe itself. If you need to access it from multiple threads, use
locks around calls.
3. It's not possible to pickle the request object.
For the response object the following rules apply:
1. The response object is mutable
2. The response object can be pickled or copied after `freeze()` was
called.
3. Since Werkzeug 0.6 it's safe to use the same response object for
multiple WSGI responses.
4. It's possible to create copies using `copy.deepcopy`.
Base Wrappers
=============
These objects implement a common set of operations. They are missing fancy
addon functionality like user agent parsing or etag handling. These features
are available by mixing in various mixin classes or using :class:`Request` and
:class:`Response`.
.. autoclass:: BaseRequest
:members:
.. attribute:: environ
The WSGI environment that the request object uses for data retrival.
.. attribute:: shallow
`True` if this request object is shallow (does not modify :attr:`environ`),
`False` otherwise.
.. automethod:: _get_file_stream
.. autoclass:: BaseResponse
:members:
.. attribute:: response
The application iterator. If constructed from a string this will be a
list, otherwise the object provided as application iterator. (The first
argument passed to :class:`BaseResponse`)
.. attribute:: headers
A :class:`Headers` object representing the response headers.
.. attribute:: status_code
The response status as integer.
.. attribute:: direct_passthrough
If ``direct_passthrough=True`` was passed to the response object or if
this attribute was set to `True` before using the response object as
WSGI application, the wrapped iterator is returned unchanged. This
makes it possible to pass a special `wsgi.file_wrapper` to the response
object. See :func:`wrap_file` for more details.
.. automethod:: __call__
.. automethod:: _ensure_sequence
Mixin Classes
=============
Werkzeug also provides helper mixins for various HTTP related functionality
such as etags, cache control, user agents etc. When subclassing you can
mix those classes in to extend the functionality of the :class:`BaseRequest`
or :class:`BaseResponse` object. Here a small example for a request object
that parses accept headers::
from werkzeug.wrappers import AcceptMixin, BaseRequest
class Request(BaseRequest, AcceptMixin):
pass
The :class:`Request` and :class:`Response` classes subclass the :class:`BaseRequest`
and :class:`BaseResponse` classes and implement all the mixins Werkzeug provides:
.. autoclass:: Request
.. autoclass:: Response
.. autoclass:: AcceptMixin
:members:
.. autoclass:: AuthorizationMixin
:members:
.. autoclass:: ETagRequestMixin
:members:
.. autoclass:: ETagResponseMixin
:members:
.. autoclass:: ResponseStreamMixin
:members:
.. autoclass:: CommonRequestDescriptorsMixin
:members:
.. autoclass:: CommonResponseDescriptorsMixin
:members:
.. autoclass:: WWWAuthenticateMixin
:members:
.. autoclass:: UserAgentMixin
:members:

View file

@ -1,66 +0,0 @@
============
WSGI Helpers
============
.. module:: werkzeug.wsgi
The following classes and functions are designed to make working with
the WSGI specification easier or operate on the WSGI layer. All the
functionality from this module is available on the high-level
:ref:`Request/Response classes <wrappers>`.
Iterator / Stream Helpers
=========================
These classes and functions simplify working with the WSGI application
iterator and the input stream.
.. autoclass:: ClosingIterator
.. autoclass:: FileWrapper
.. autoclass:: LimitedStream
:members:
.. autofunction:: make_line_iter
.. autofunction:: make_chunk_iter
.. autofunction:: wrap_file
Environ Helpers
===============
These functions operate on the WSGI environment. They extract useful
information or perform common manipulations:
.. autofunction:: get_host
.. autofunction:: get_content_length
.. autofunction:: get_input_stream
.. autofunction:: get_current_url
.. autofunction:: get_query_string
.. autofunction:: get_script_name
.. autofunction:: get_path_info
.. autofunction:: pop_path_info
.. autofunction:: peek_path_info
.. autofunction:: extract_path_info
.. autofunction:: host_is_trusted
Convenience Helpers
===================
.. autofunction:: responder
.. autofunction:: werkzeug.testapp.test_app

View file

@ -1,103 +0,0 @@
=================
Werkzeug Examples
=================
This directory contains various example applications and example code of
Werkzeug powered applications.
Beside the proof of concept applications and code snippets in the partial
folder they all have external depencencies for template engines or database
adapters (SQLAlchemy only so far).
Full Example Applications
=========================
The following example applications are application types you would actually
find in real life :-)
`simplewiki`
A simple Wiki implementation.
Requirements:
- SQLAlchemy
- Creoleparser >= 0.7
- genshi
You can obtain all packages in the Cheeseshop via easy_install. You have
to have at least version 0.7 of Creoleparser.
Usage::
./manage-simplewiki.py initdb
./manage-simplewiki.py runserver
Or of course you can just use the application object
(`simplewiki.SimpleWiki`) and hook that into your favourite WSGI gateway.
The constructor of the application object takes a single argument which is
the SQLAlchemy URI for the database.
The management script for the devserver looks up the an environment var
called `SIMPLEWIKI_DATABASE_URI` and uses that for the database URI. If
no such variable is provided "sqlite:////tmp/simplewiki.db" is assumed.
`plnt`
A planet called plnt, pronounce plant.
Requirements:
- SQLAlchemy
- Jinja
- feedparser
You can obtain all packages in the Cheeseshop via easy_install.
Usage::
./manage-plnt.py initdb
./manage-plnt.py sync
./manage-plnt.py runserver
The WSGI application is called `plnt.Plnt` which, like the simple wiki,
accepts a database URI as first argument. The environment variable for
the database key is called `PLNT_DATABASE_URI` and the default is
"sqlite:////tmp/plnt.db".
Per default a few python related blogs are added to the database, you
can add more in a python shell by playing with the `Blog` model.
`shorty`
A tinyurl clone for the Werkzeug tutorial.
Requirements:
- SQLAlchemy
- Jinja2
You can obtain all packages in the Cheeseshop via easy_install.
Usage::
./manage-shorty.py initdb
./manage-shorty.py runserver
The WSGI application is called `shorty.application.Shorty` which, like the
simple wiki, accepts a database URI as first argument.
The source code of the application is explained in detail in the Werkzeug
tutorial.
`couchy`
Like shorty, but implemented using CouchDB.
Requirements :
- werkzeug : http://werkzeug.pocoo.org
- jinja : http://jinja.pocoo.org
- couchdb 0.72 & above : http://www.couchdb.org
`cupoftee`
A `Teeworlds <http://www.teeworlds.com/>`_ server browser. This application
works best in a non forking environment and won't work for CGI.
Usage::
./manage-cupoftee.py runserver

View file

@ -1 +0,0 @@
This folder includes example applications for werkzeug.contrib

View file

@ -1,50 +0,0 @@
# -*- coding: utf-8 -*-
"""
Secure Cookie Example
~~~~~~~~~~~~~~~~~~~~~
Stores session on the client.
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD.
"""
from time import asctime
from werkzeug.serving import run_simple
from werkzeug.wrappers import BaseRequest, BaseResponse
from werkzeug.contrib.securecookie import SecureCookie
SECRET_KEY = 'V\x8a$m\xda\xe9\xc3\x0f|f\x88\xbccj>\x8bI^3+'
class Request(BaseRequest):
def __init__(self, environ):
BaseRequest.__init__(self, environ)
self.session = SecureCookie.load_cookie(self, secret_key=SECRET_KEY)
def index(request):
return '<a href="set">Set the Time</a> or <a href="get">Get the time</a>'
def get_time(request):
return 'Time: %s' % request.session.get('time', 'not set')
def set_time(request):
request.session['time'] = time = asctime()
return 'Time set to %s' % time
def application(environ, start_response):
request = Request(environ)
response = BaseResponse({
'get': get_time,
'set': set_time
}.get(request.path.strip('/'), index)(request), mimetype='text/html')
request.session.save_cookie(response)
return response(environ, start_response)
if __name__ == '__main__':
run_simple('localhost', 5000, application)

View file

@ -1,43 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from werkzeug.serving import run_simple
from werkzeug.contrib.sessions import SessionStore, SessionMiddleware
class MemorySessionStore(SessionStore):
def __init__(self, session_class=None):
SessionStore.__init__(self, session_class=None)
self.sessions = {}
def save(self, session):
self.sessions[session.sid] = session
def delete(self, session):
self.sessions.pop(session.id, None)
def get(self, sid):
if not self.is_valid_key(sid) or sid not in self.sessions:
return self.new()
return self.session_class(self.sessions[sid], sid, False)
def application(environ, start_response):
session = environ['werkzeug.session']
session['visit_count'] = session.get('visit_count', 0) + 1
start_response('200 OK', [('Content-Type', 'text/html')])
return ['''
<!doctype html>
<title>Session Example</title>
<h1>Session Example</h1>
<p>You visited this page %d times.</p>
''' % session['visit_count']]
def make_app():
return SessionMiddleware(application, MemorySessionStore())
if __name__ == '__main__':
run_simple('localhost', 5000, make_app())

View file

@ -1,108 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Cookie Based Auth
~~~~~~~~~~~~~~~~~
This is a very simple application that uses a secure cookie to do the
user authentification.
:copyright: Copyright 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from werkzeug.serving import run_simple
from werkzeug.utils import cached_property, escape, redirect
from werkzeug.wrappers import Request, Response
from werkzeug.contrib.securecookie import SecureCookie
# don't use this key but a different one; you could just use
# os.unrandom(20) to get something random. Changing this key
# invalidates all sessions at once.
SECRET_KEY = '\xfa\xdd\xb8z\xae\xe0}4\x8b\xea'
# the cookie name for the session
COOKIE_NAME = 'session'
# the users that may access
USERS = {
'admin': 'default',
'user1': 'default'
}
class AppRequest(Request):
"""A request with a secure cookie session."""
def logout(self):
"""Log the user out."""
self.session.pop('username', None)
def login(self, username):
"""Log the user in."""
self.session['username'] = username
@property
def logged_in(self):
"""Is the user logged in?"""
return self.user is not None
@property
def user(self):
"""The user that is logged in."""
return self.session.get('username')
@cached_property
def session(self):
data = self.cookies.get(COOKIE_NAME)
if not data:
return SecureCookie(secret_key=SECRET_KEY)
return SecureCookie.unserialize(data, SECRET_KEY)
def login_form(request):
error = ''
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if password and USERS.get(username) == password:
request.login(username)
return redirect('')
error = '<p>Invalid credentials'
return Response('''
<title>Login</title><h1>Login</h1>
<p>Not logged in.
%s
<form action="" method="post">
<p>
<input type="hidden" name="do" action="login">
<input type="text" name="username" size=20>
<input type="password" name="password", size=20>
<input type="submit" value="Login">
</form>''' % error, mimetype='text/html')
def index(request):
return Response('''
<title>Logged in</title>
<h1>Logged in</h1>
<p>Logged in as %s
<p><a href="/?do=logout">Logout</a>
''' % escape(request.user), mimetype='text/html')
@AppRequest.application
def application(request):
if request.args.get('do') == 'logout':
request.logout()
response = redirect('.')
elif request.logged_in:
response = index(request)
else:
response = login_form(request)
request.session.save_cookie(response)
return response
if __name__ == '__main__':
run_simple('localhost', 4000, application)

View file

@ -1,11 +0,0 @@
# -*- coding: utf-8 -*-
"""
coolmagic
~~~~~~~~~
Package description goes here.
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from coolmagic.application import make_app

View file

@ -1,78 +0,0 @@
# -*- coding: utf-8 -*-
"""
coolmagic.application
~~~~~~~~~~~~~~~~~~~~~
This module provides the WSGI application.
The WSGI middlewares are applied in the `make_app` factory function
that automatically wraps the application within the require
middlewares. Per default only the `SharedDataMiddleware` is applied.
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from os import path, listdir
from coolmagic.utils import Request, local_manager, redirect
from werkzeug.routing import Map, Rule, RequestRedirect
from werkzeug.exceptions import HTTPException, NotFound
class CoolMagicApplication(object):
"""
The application class. It's passed a directory with configuration values.
"""
def __init__(self, config):
self.config = config
for fn in listdir(path.join(path.dirname(__file__), 'views')):
if fn.endswith('.py') and fn != '__init__.py':
__import__('coolmagic.views.' + fn[:-3])
from coolmagic.utils import exported_views
rules = [
# url for shared data. this will always be unmatched
# because either the middleware or the webserver
# handles that request first.
Rule('/public/<path:file>',
endpoint='shared_data')
]
self.views = {}
for endpoint, (func, rule, extra) in exported_views.iteritems():
if rule is not None:
rules.append(Rule(rule, endpoint=endpoint, **extra))
self.views[endpoint] = func
self.url_map = Map(rules)
def __call__(self, environ, start_response):
urls = self.url_map.bind_to_environ(environ)
req = Request(environ, urls)
try:
endpoint, args = urls.match(req.path)
resp = self.views[endpoint](**args)
except NotFound, e:
resp = self.views['static.not_found']()
except (HTTPException, RequestRedirect), e:
resp = e
return resp(environ, start_response)
def make_app(config=None):
"""
Factory function that creates a new `CoolmagicApplication`
object. Optional WSGI middlewares should be applied here.
"""
config = config or {}
app = CoolMagicApplication(config)
# static stuff
from werkzeug.utils import SharedDataMiddleware
app = SharedDataMiddleware(app, {
'/public': path.join(path.dirname(__file__), 'public')
})
# clean up locals
app = local_manager.make_middleware(app)
return app

View file

@ -1,18 +0,0 @@
# -*- coding: utf-8 -*-
"""
coolmagic.helpers
~~~~~~~~~~~~~~~~~
The star-import module for all views.
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from coolmagic.utils import Response, TemplateResponse, ThreadedRequest, \
export, url_for, redirect
from werkzeug.utils import escape
#: a thread local proxy request object
request = ThreadedRequest()
del ThreadedRequest

View file

@ -1,10 +0,0 @@
body {
margin: 0;
padding: 20px;
font-family: sans-serif;
font-size: 15px;
}
h1, a {
color: #a00;
}

View file

@ -1,13 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>{{ page_title }} &mdash; Cool Magic!</title>
<link rel="stylesheet" href="{{ h.url_for('shared_data', file='style.css') }}" type="text/css">
</head>
<body>
<h1>Cool Magic</h1>
<h2>{{ page_title }}</h2>
{% block page_body %}{% endblock %}
</body>
</html>

View file

@ -1,10 +0,0 @@
{% extends "layout.html" %}
{% set page_title = 'About the Magic' %}
{% block page_body %}
<p>
Nothing to see. It's just magic.
</p>
<p>
<a href="{{ h.url_for('static.index') }}">back to the index</a>
</p>
{% endblock %}

View file

@ -1,13 +0,0 @@
{% extends "layout.html" %}
{% set page_title = 'Welcome to the Magic' %}
{% block page_body %}
<p>
Welcome to the magic! This is a bigger example for the
Werkzeug toolkit. And it contains a lot of magic.
</p>
<p>
<a href="{{ h.url_for('static.about') }}">about the implementation</a> or
click here if you want to see a <a href="{{ h.url_for('static.broken')
}}">broken view</a>.
</p>
{% endblock %}

View file

@ -1,8 +0,0 @@
{% extends "layout.html" %}
{% set page_title = 'Missing Magic' %}
{% block page_body %}
<p>
The requested magic really does not exist. Maybe you want
to look for it on the <a href="{{ h.url_for('static.index') }}">index</a>.
</p>
{% endblock %}

View file

@ -1,107 +0,0 @@
# -*- coding: utf-8 -*-
"""
coolmagic.utils
~~~~~~~~~~~~~~~
This module contains the subclasses of the base request and response
objects provided by werkzeug. The subclasses know about their charset
and implement some additional functionallity like the ability to link
to view functions.
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from os.path import dirname, join
from jinja import Environment, FileSystemLoader
from werkzeug.local import Local, LocalManager
from werkzeug.utils import redirect
from werkzeug.wrappers import BaseRequest, BaseResponse
local = Local()
local_manager = LocalManager([local])
template_env = Environment(
loader=FileSystemLoader(join(dirname(__file__), 'templates'),
use_memcache=False)
)
exported_views = {}
def export(string, template=None, **extra):
"""
Decorator for registering view functions and adding
templates to it.
"""
def wrapped(f):
endpoint = (f.__module__ + '.' + f.__name__)[16:]
if template is not None:
old_f = f
def f(**kwargs):
rv = old_f(**kwargs)
if not isinstance(rv, Response):
rv = TemplateResponse(template, **(rv or {}))
return rv
f.__name__ = old_f.__name__
f.__doc__ = old_f.__doc__
exported_views[endpoint] = (f, string, extra)
return f
return wrapped
def url_for(endpoint, **values):
"""
Build a URL
"""
return local.request.url_adapter.build(endpoint, values)
class Request(BaseRequest):
"""
The concrete request object used in the WSGI application.
It has some helper functions that can be used to build URLs.
"""
charset = 'utf-8'
def __init__(self, environ, url_adapter):
BaseRequest.__init__(self, environ)
self.url_adapter = url_adapter
local.request = self
class ThreadedRequest(object):
"""
A pseudo request object that always poins to the current
context active request.
"""
def __getattr__(self, name):
if name == '__members__':
return [x for x in dir(local.request) if not
x.startswith('_')]
return getattr(local.request, name)
def __setattr__(self, name, value):
return setattr(local.request, name, value)
class Response(BaseResponse):
"""
The concrete response object for the WSGI application.
"""
charset = 'utf-8'
default_mimetype = 'text/html'
class TemplateResponse(Response):
"""
Render a template to a response.
"""
def __init__(self, template_name, **values):
from coolmagic import helpers
values.update(
request=local.request,
h=helpers
)
template = template_env.get_template(template_name)
Response.__init__(self, template.render(values))

View file

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
"""
coolmagic.views
~~~~~~~~~~~~~~~
This module collects and assambles the urls.
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""

View file

@ -1,36 +0,0 @@
# -*- coding: utf-8 -*-
"""
coolmagic.views.static
~~~~~~~~~~~~~~~~~~~~~~
Some static views.
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from coolmagic.helpers import *
@export('/', template='static/index.html')
def index():
pass
@export('/about', template='static/about.html')
def about():
pass
@export('/broken')
def broken():
foo = request.args.get('foo', 42)
raise RuntimeError('that\'s really broken')
@export(None, template='static/not_found.html')
def not_found():
"""
This function is always executed if an url does not
match or a `NotFound` exception is raised.
"""
pass

Some files were not shown because too many files have changed in this diff Show more