     Werkzeug 2.0.2, Feb 01, 2022

     Pallets

     Copyright © 2007 Pallets

   Generated by Sphinx 4.2.0.

Werkzeug
********

     Werkzeug 2.0.2, Feb 01, 2022

     Pallets

     Copyright © 2007 Pallets

`werkzeug' German noun: “tool”.  Etymology: `werk' (“work”), `zeug'
(“stuff”)

Werkzeug is a comprehensive WSGI(1) web application library.  It began
as a simple collection of various utilities for WSGI applications and
has become one of the most advanced WSGI utility libraries.

Werkzeug doesn’t enforce any dependencies.  It is up to the developer to
choose a template engine, database adapter, and even how to handle
requests.

 — The Detailed Node Listing —

Getting Started

Installation

Dependencies

Virtual environments

Werkzeug Tutorial

API Levels

Serving and Testing

Serving WSGI Applications

SSL

Testing WSGI Applications

Debugging Applications

Reference

Request / Response Objects

URL Routing

WSGI Helpers

HTTP Utilities

Data Structures

Utilities

Middleware

HTTP Exceptions

Deployment

Application Deployment

CGI

mod_wsgi (Apache)

FastCGI

HTTP Proxying

Additional Information

Important Terms

Unicode

Dealing with Request Data

Changes

   ---------- Footnotes ----------

   (1) https://wsgi.readthedocs.io/en/latest/

1 Getting Started
*****************

1.1 Installation
================

1.1.1 Python Version
--------------------

We recommend using the latest version of Python.  Werkzeug supports
Python 3.6 and newer.

1.1.2 Dependencies
------------------

Werkzeug does not have any direct dependencies.

1.1.2.1 Optional dependencies
.............................

These distributions will not be installed automatically.  Werkzeug will
detect and use them if you install them.

   * Colorama(1) provides request log highlighting when using the
     development server on Windows.  This works automatically on other
     systems.

   * Watchdog(2) provides a faster, more efficient reloader for the
     development server.

   ---------- Footnotes ----------

   (1) https://pypi.org/project/colorama/

   (2) https://pypi.org/project/watchdog/

1.1.3 Virtual environments
--------------------------

Use a virtual environment to manage the dependencies for your project,
both in development and in production.

What problem does a virtual environment solve?  The more Python projects
you have, the more likely it is that you need to work with different
versions of Python libraries, or even Python itself.  Newer versions of
libraries for one project can break compatibility in another project.

Virtual environments are independent groups of Python libraries, one for
each project.  Packages installed for one project will not affect other
projects or the operating system’s packages.

Python comes bundled with the venv(1) module to create virtual
environments.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/venv.html#module-venv

1.1.3.1 Create an environment
.............................

Create a project folder and a ‘venv’ folder within:

     mkdir myproject
     cd myproject
     python3 -m venv venv

On Windows:

     py -3 -m venv venv

1.1.3.2 Activate the environment
................................

Before you work on your project, activate the corresponding environment:

     . venv/bin/activate

On Windows:

     venv\Scripts\activate

Your shell prompt will change to show the name of the activated
environment.

1.1.4 Install Werkzeug
----------------------

Within the activated environment, use the following command to install
Werkzeug:

     pip install Werkzeug

1.2 Werkzeug Tutorial
=====================

Welcome to the Werkzeug tutorial in which we will create a TinyURL(1)
clone that stores URLs in a redis instance.  The libraries we will use
for this applications are Jinja(2) 2 for the templates, redis(3) 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(4).

   ---------- Footnotes ----------

   (1) https://tinyurl.com/

   (2) http://jinja.pocoo.org/

   (3) https://redis.io/

   (4) https://github.com/dmajkic/redis/downloads

1.2.1 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(1) here instead of a relational
database to keep this simple and because that’s the kind of job that
redis(2) excels at.

The final result will look something like this:

   ---------- Footnotes ----------

   (1) https://redis.io/

   (2) https://redis.io/

1.2.2 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 = f"Hello {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.

1.2.3 Step 1: Creating the Folders
----------------------------------

Before we get started, let’s 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.

1.2.4 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
     from werkzeug.urls import url_parse
     from werkzeug.wrappers import Request, Response
     from werkzeug.routing import Map, Rule
     from werkzeug.exceptions import HTTPException, NotFound
     from werkzeug.middleware.shared_data 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 ‘Request’ object and calls the ‘dispatch_request’ method which
then has to return a ‘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.

1.2.5 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!”.

1.2.6 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')

1.2.7 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 Map instance and add a bunch of 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, f'on_{endpoint}')(request, **values)
         except HTTPException as e:
             return e

We bind the URL map to the current environment and get back a
‘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': 'foo'}

If it does not match anything, it will raise a NotFound.
exception, which is an 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.

1.2.8 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(f"/{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 = url_parse(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(f'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(f'url-target:{short_id}', url)
         self.redis.set(f'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.

1.2.9 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(f'url-target:{short_id}')
         if link_target is None:
             raise NotFound()
         self.redis.incr(f'click-count:{short_id}')
         return redirect(link_target)

In this case we will raise a 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.

1.2.10 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(f'url-target:{short_id}')
         if link_target is None:
             raise NotFound()
         click_count = int(self.redis.get(f'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 int(1) by hand.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/functions.html#int

1.2.11 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':

     <!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':

     {% 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':

     {% 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 %}

1.2.12 Step 9: The Style
------------------------

For this to look better than ugly black and white, here a simple
stylesheet that goes along:

`static/style.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; }

1.2.13 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(1)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/tree/main/examples/shortly

1.3 API Levels
==============

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 ‘Request’ and ‘Response’ objects (aka the
“wrappers”) provide is also available in small utility functions.

1.3.1 Example
-------------

This example implements a small ‘Hello World’ application that greets
the user with the name entered.

     from html import escape
     from werkzeug.wrappers import Request, Response

     @Request.application
     def hello_world(request):
         result = ['<title>Greeter</title>']
         if request.method == 'POST':
             result.append(f"<h1>Hello {escape(request.form['name'])}!</h1>")
         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 html import escape
     from werkzeug.formparser import parse_form_data

     def hello_world(environ, start_response):
         result = ['<title>Greeter</title>']
         if environ['REQUEST_METHOD'] == 'POST':
             form = parse_form_data(environ)[1]
             result.append(f"<h1>Hello {escape(form['name'])}!</h1>")
         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).encode('utf-8')]

1.3.2 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.

1.4 Quickstart
==============

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 3333(1) (WSGI) and RFC 2616(2) (HTTP).

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-3333

   (2) https://tools.ietf.org/html/rfc2616.html

1.5 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 ‘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 uses a
confusing string encoding scheme, and it does not provide any way to
access the form data besides parsing that data by hand.

1.6 Enter Request
=================

For access to the request data the ‘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
‘Request’.

     >>> request.path
     '/foo'
     >>> request.script_root
     ''
     >>> 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 ‘from_values()’ method:

     >>> from io 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']
     'blafasel'

Same for the supplied form data:

     >>> request.form['name']
     '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 ‘FileStorage’ objects which provide some
common operations to work with them.

Request headers can be accessed by using the ‘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.

1.7 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_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)

With the accept 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, tzinfo=datetime.timezone.utc)
     >>> 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

1.8 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
‘status’ and ‘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, timezone
     >>> response.date = datetime(2009, 2, 20, 17, 42, 51, tzinfo=timezone.utc)
     >>> 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 ‘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 ‘make_conditional’ with the request object.

The response is modified accordingly (status code changed, response body
removed, entity headers removed etc.)

2 Serving and Testing
*********************

2.1 Serving WSGI Applications
=============================

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:

     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.

 -- Function: werkzeug.serving.run_simple (hostname, port, application,
          use_reloader=False, use_debugger=False, use_evalex=True,
          extra_files=None, exclude_patterns=None, reloader_interval=1,
          reloader_type='auto', threaded=False, processes=1,
          request_handler=None, static_files=None,
          passthrough_errors=False, ssl_context=None)

     Start a WSGI application.  Optional features include a reloader,
     multithreading and fork support.

     This function has a command-line interface too:

          python -m werkzeug.serving --help

     Changed in version 2.0: Added ‘exclude_patterns’ parameter.

     Changed in version 0.15: Bind to a Unix socket by passing a path
     that starts with ‘unix://’ as the ‘hostname’.

     New in version 0.10: Improved the reloader and added support for
     changing the backend through the ‘reloader_type’ parameter.  See
     Reloader for more information.

     New in version 0.9: Added command-line interface.

     New in version 0.8: Added support for automatically loading a SSL
     context from certificate file and private key.

     New in version 0.6: support for SSL was added.

     New in version 0.5: ‘static_files’ was added to simplify serving of
     static files as well as ‘passthrough_errors’.

     Parameters:

        * ‘hostname’ (str(1)) – The host to bind to, for example
          ‘'localhost'’.  If the value is a path that starts with
          ‘unix://’ it will bind to a Unix socket instead of a TCP
          socket..

        * ‘port’ (int(2)) – The port for the server.  eg: ‘8080’

        * ‘application’ (‘WSGIApplication’) – the WSGI application to
          execute

        * ‘use_reloader’ (bool(3)) – should the server automatically
          restart the python process if modules were changed?

        * ‘use_debugger’ (bool(4)) – should the werkzeug debugging
          system be used?

        * ‘use_evalex’ (bool(5)) – should the exception evaluation
          feature be enabled?

        * ‘extra_files’ (‘Optional’‘[’‘Iterable’‘[’str(6)‘]’‘]’) – a
          list of files the reloader should watch additionally to the
          modules.  For example configuration files.

        * ‘exclude_patterns’ (‘Optional’‘[’‘Iterable’‘[’str(7)‘]’‘]’) –
          List of fnmatch(8) patterns to ignore when running the
          reloader.  For example, ignore cache files that shouldn’t
          reload when updated.

        * ‘reloader_interval’ (int(9)) – the interval for the reloader
          in seconds.

        * ‘reloader_type’ (str(10)) – the type of reloader to use.  The
          default is auto detection.  Valid values are ‘'stat'’ and
          ‘'watchdog'’.  See Reloader for more information.

        * ‘threaded’ (bool(11)) – should the process handle each request
          in a separate thread?

        * ‘processes’ (int(12)) – if greater than 1 then handle each
          request in a new process up to this maximum number of
          concurrent processes.

        * ‘request_handler’
          (‘Optional’‘[’‘Type’‘[’‘werkzeug.serving.WSGIRequestHandler’‘]’‘]’)
          – optional parameter that can be used to replace the default
          one.  You can use this to replace it with a different
          ‘BaseHTTPRequestHandler’ subclass.

        * ‘static_files’ (‘Optional’‘[’‘Dict’‘[’str(13)‘,
          ’‘Union’‘[’str(14)‘, ’‘Tuple’‘[’str(15)‘,
          ’str(16)‘]’‘]’‘]’‘]’) – a list or dict of paths for static
          files.  This works exactly like ‘SharedDataMiddleware’, it’s
          actually just wrapping the application in that middleware
          before serving.

        * ‘passthrough_errors’ (bool(17)) – set this to ‘True’ to
          disable the error catching.  This means that the server will
          die on errors but it can be useful to hook debuggers in (pdb
          etc.)

        * ‘ssl_context’ (‘Optional’‘[’‘Union’‘[’ssl.SSLContext(18)‘,
          ’‘Tuple’‘[’str(19)‘, ’‘Optional’‘[’str(20)‘]’‘]’‘,
          ’‘te.Literal’‘[’‘'adhoc'’‘]’‘]’‘]’) – an SSL context for the
          connection.  Either an ssl.SSLContext(21), a tuple in the form
          ‘(cert_file, pkey_file)’, the string ‘'adhoc'’ if the server
          should automatically create one, or ‘None’ to disable SSL
          (which is the default).

     Return type: None(22)

 -- Function: werkzeug.serving.is_running_from_reloader ()

     Checks if the application is running from within the Werkzeug
     reloader subprocess.

     New in version 0.10.

     Return type: bool(23)

 -- Function: werkzeug.serving.make_ssl_devcert (base_path, host=None,
          cn=None)

     Creates an SSL key for development.  This should be used instead of
     the ‘'adhoc'’ key which generates a new cert on each server start.
     It accepts a path for where it should store the key and cert and
     either a host or CN. If a host is given it will use the CN
     ‘*.host/CN=host’.

     For more information see run_simple().

     New in version 0.9.

     Parameters:

        * ‘base_path’ (str(24)) – the path to the certificate and key.
          The extension ‘.crt’ is added for the certificate, ‘.key’ is
          added for the key.

        * ‘host’ (‘Optional’‘[’str(25)‘]’) – the name of the host.  This
          can be used as an alternative for the ‘cn’.

        * ‘cn’ (‘Optional’‘[’str(26)‘]’) – the ‘CN’ to use.

     Return type: Tuple[str(27), str(28)]

     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 Application Deployment pages.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/functions.html#int

   (3) https://docs.python.org/3/library/functions.html#bool

   (4) https://docs.python.org/3/library/functions.html#bool

   (5) https://docs.python.org/3/library/functions.html#bool

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/fnmatch.html#module-fnmatch

   (9) https://docs.python.org/3/library/functions.html#int

   (10) https://docs.python.org/3/library/stdtypes.html#str

   (11) https://docs.python.org/3/library/functions.html#bool

   (12) https://docs.python.org/3/library/functions.html#int

   (13) https://docs.python.org/3/library/stdtypes.html#str

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/stdtypes.html#str

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/functions.html#bool

   (18) https://docs.python.org/3/library/ssl.html#ssl.SSLContext

   (19) https://docs.python.org/3/library/stdtypes.html#str

   (20) https://docs.python.org/3/library/stdtypes.html#str

   (21) https://docs.python.org/3/library/ssl.html#ssl.SSLContext

   (22) https://docs.python.org/3/library/constants.html#None

   (23) https://docs.python.org/3/library/functions.html#bool

   (24) https://docs.python.org/3/library/stdtypes.html#str

   (25) https://docs.python.org/3/library/stdtypes.html#str

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/stdtypes.html#str

   (28) https://docs.python.org/3/library/stdtypes.html#str

2.1.1 Reloader
--------------

Changed in version 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(1) 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 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.

   ---------- Footnotes ----------

   (1) https://pypi.org/project/watchdog/

2.1.2 Colored Logging
---------------------

The development server highlights the request logs in different colors
based on the status code.  On Windows, Colorama(1) must be installed as
well to enable this.

   ---------- Footnotes ----------

   (1) https://pypi.org/project/colorama/

2.1.3 Virtual Hosts
-------------------

Many web applications utilize multiple subdomains.  This can be a bit
tricky to simulate locally.  Fortunately there is the hosts file(1) 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
URL Routing system to dispatch between different hosts or parse
‘request.host’ yourself.

   ---------- Footnotes ----------

   (1) https://en.wikipedia.org/wiki/Hosts_file

2.1.4 Shutting Down The Server
------------------------------

In some cases it can be useful to shut down a server after handling a
request.  For example, a local command line tool that needs OAuth
authentication could temporarily start a server to listen for a
response, record the user’s token, then stop the server.

One method to do this could be to start a server in a multiprocessing(1)
process, then terminate the process after a value is passed back to the
parent.

     import multiprocessing
     from werkzeug import Request, Response, run_simple

     def get_token(q: multiprocessing.Queue) -> None:
         @Request.application
         def app(request: Request) -> Response:
             q.put(request.args["token"])
             return Response("", 204)

         run_simple("localhost", 5000, app)

     if __name__ == "__main__":
         q = multiprocessing.Queue()
         p = multiprocessing.Process(target=get_token, args=(q,))
         p.start()
         print("waiting")
         token = q.get(block=True)
         p.terminate()
         print(token)

That example uses Werkzeug’s development server, but any production
server that can be started as a Python process could use the same
technique and should be preferred for security.  Another method could be
to start a subprocess(2) process and send the value back over ‘stdout’.

Deprecated since version 2.0: Shutting down the server with
‘environ["werkzeug.server.shutdown"]’ is deprecated and will be removed
in Werkzeug 2.1.

The development server provides a way to shutdown the server from a
request.  This will only work with the development server.  The
development server injects a function into the WSGI environ with the
‘"werkzeug.server.shutdown"’ key.

     def shutdown_server(environ):
         shutdown = environ.get("werkzeug.server.shutdown")

         if shutdown is None:
             raise RuntimeError("Not running the development server.")

         shutdown()

   ---------- Footnotes ----------

   (1)
https://docs.python.org/3/library/multiprocessing.html#module-multiprocessing

   (2)
https://docs.python.org/3/library/subprocess.html#module-subprocess

2.1.5 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(1) 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’)

   ---------- Footnotes ----------

   (1) https://en.wikipedia.org/wiki/Hosts_file

2.1.6 SSL
---------

New in version 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.

2.1.6.1 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
     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.

2.1.6.2 Loading Contexts by Hand
................................

You can use a ‘ssl.SSLContext’ object instead of a tuple for full
control over the TLS configuration.

     import ssl
     ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
     ctx.load_cert_chain('ssl.cert', 'ssl.key')
     run_simple('localhost', 4000, application, ssl_context=ctx)

2.1.6.3 Generating Certificates
...............................

A key and certificate can be created in advance using the openssl tool
instead of the 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

2.1.6.4 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 cryptography library to be installed.

2.1.7 Unix Sockets
------------------

The dev server can bind to a Unix socket instead of a TCP socket.
run_simple() will bind to a Unix socket if the ‘hostname’ parameter
starts with ‘'unix://'’.

     from werkzeug.serving import run_simple
     run_simple('unix://example.sock', 0, app)

2.2 Testing WSGI Applications
=============================

2.2.1 Test Client
-----------------

Werkzeug provides a Client to simulate requests to a WSGI
application without starting a server.  The client has methods for
making different types of requests, as well as managing cookies across
requests.

     >>> from werkzeug.test import Client
     >>> from werkzeug.testapp import test_app
     >>> c = Client(test_app)
     >>> response = c.get("/")
     >>> response.status_code
     200
     >>> resp.headers
     Headers([('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '6658')])
     >>> response.get_data(as_text=True)
     '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"...'

The client’s request methods return instances of TestResponse.
This provides extra attributes and methods on top of Response.
that are useful for testing.

2.2.2 Request Body
------------------

By passing a dict to ‘data’, the client will construct a request body
with file and form data.  It will set the content type to
‘application/x-www-form-urlencoded’ if there are no files, or
‘multipart/form-data’ there are.

     import io

     response = client.post(data={
         "name": "test",
         "file": (BytesIO("file contents".encode("utf8")), "test.txt")
     })

Pass a string, bytes, or file-like object to ‘data’ to use that as the
raw request body.  In that case, you should set the content type
appropriately.  For example, to post YAML:

     response = client.post(
         data="a: value\nb: 1\n", content_type="application/yaml"
     )

A shortcut when testing JSON APIs is to pass a dict to ‘json’ instead of
using ‘data’.  This will automatically call ‘json.dumps()’ and set the
content type to ‘application/json’.  Additionally, if the app returns
JSON, ‘response.json’ will automatically call ‘json.loads()’.

     response = client.post("/api", json={"a": "value", "b": 1})
     obj = response.json()

2.2.3 Environment Builder
-------------------------

EnvironBuilder is used to construct a WSGI environ dict.  The
test client uses this internally to prepare its requests.  The arguments
passed to the client request methods are the same as the builder.

Sometimes, it can be useful to construct a WSGI environment manually.
An environ builder or dict can be passed to the test client request
methods in place of other arguments to use a custom environ.

     from werkzeug.test import EnvironBuilder
     builder = EnvironBuilder(...)
     # build an environ dict
     environ = builder.get_environ()
     # build an environ dict wrapped in a request
     request = builder.get_request()

The test client responses make this available through
TestResponse.request and ‘response.request.environ’.

2.2.4 API
---------

 -- Class: werkzeug.test.Client (application, response_wrapper=None,
          use_cookies=True, allow_subdomain_redirects=False)

     This class allows you to send requests to a wrapped application.

     The use_cookies parameter indicates whether cookies should be
     stored and sent for subsequent requests.  This is True by default,
     but passing False will disable this behaviour.

     If you want to request some subdomain of your application you may
     set ‘allow_subdomain_redirects’ to ‘True’ as if not no external
     redirects are allowed.

     Changed in version 2.0: ‘response_wrapper’ is always a subclass of
     :class:‘TestResponse’.

     Changed in version 0.5: Added the ‘use_cookies’ parameter.

     Parameters:

        * ‘application’ (‘WSGIApplication’) –

        * ‘response_wrapper’ (‘Optional’‘[’‘Type’‘[’Response.
          ‘]’‘]’) –

        * ‘use_cookies’ (bool(1)) –

        * ‘allow_subdomain_redirects’ (bool(2)) –

     Return type: None(3)

      -- Method: set_cookie (server_name, key, value='', max_age=None,
               expires=None, path='/', domain=None, secure=False,
               httponly=False, samesite=None, charset='utf-8')

          Sets a cookie in the client’s cookie jar.  The server name is
          required and has to match the one that is also passed to the
          open call.

          Parameters:

             * ‘server_name’ (str(4)) –

             * ‘key’ (str(5)) –

             * ‘value’ (str(6)) –

             * ‘max_age’ (‘Optional’‘[’‘Union’‘[’datetime.timedelta(7)‘,
               ’int(8)‘]’‘]’) –

             * ‘expires’ (‘Optional’‘[’‘Union’‘[’str(9)‘,
               ’datetime.datetime(10)‘, ’int(11)‘, ’float(12)‘]’‘]’) –

             * ‘path’ (str(13)) –

             * ‘domain’ (‘Optional’‘[’str(14)‘]’) –

             * ‘secure’ (bool(15)) –

             * ‘httponly’ (bool(16)) –

             * ‘samesite’ (‘Optional’‘[’str(17)‘]’) –

             * ‘charset’ (str(18)) –

          Return type: None(19)

      -- Method: delete_cookie (server_name, key, path='/', domain=None,
               secure=False, httponly=False, samesite=None)

          Deletes a cookie in the test client.

          Parameters:

             * ‘server_name’ (str(20)) –

             * ‘key’ (str(21)) –

             * ‘path’ (str(22)) –

             * ‘domain’ (‘Optional’‘[’str(23)‘]’) –

             * ‘secure’ (bool(24)) –

             * ‘httponly’ (bool(25)) –

             * ‘samesite’ (‘Optional’‘[’str(26)‘]’) –

          Return type: None(27)

      -- Method: open (*args, as_tuple=False, buffered=False,
               follow_redirects=False, **kwargs)

          Generate an environ dict from the given arguments, make a
          request to the application using it, and return the response.

          Parameters:

             * ‘args’ (‘Any’) – Passed to EnvironBuilder to
               create the environ for the request.  If a single arg is
               passed, it can be an existing EnvironBuilder.
               or an environ dict.

             * ‘buffered’ (bool(28)) – Convert the iterator returned by
               the app into a list.  If the iterator has a ‘close()’
               method, it is called automatically.

             * ‘follow_redirects’ (bool(29)) – Make additional requests
               to follow HTTP redirects until a non-redirect status is
               returned.  TestResponse.history lists the
               intermediate responses.

             * ‘as_tuple’ (bool(30)) –

             * ‘kwargs’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

          Changed in version 2.0: ‘as_tuple’ is deprecated and will be
          removed in Werkzeug 2.1.  Use TestResponse.request.
          and ‘request.environ’ instead.

          Changed in version 2.0: The request input stream is closed
          when calling ‘response.close()’.  Input streams for redirects
          are automatically closed.

          Changed in version 0.5: If a dict is provided as file in the
          dict for the ‘data’ parameter the content type has to be
          called ‘content_type’ instead of ‘mimetype’.  This change was
          made for consistency with ‘werkzeug.FileWrapper’.

          Changed in version 0.5: Added the ‘follow_redirects’
          parameter.

      -- Method: get (*args, **kw)

          Call open() with ‘method’ set to ‘GET’.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kw’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

      -- Method: post (*args, **kw)

          Call open() with ‘method’ set to ‘POST’.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kw’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

      -- Method: put (*args, **kw)

          Call open() with ‘method’ set to ‘PUT’.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kw’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

      -- Method: delete (*args, **kw)

          Call open() with ‘method’ set to ‘DELETE’.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kw’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

      -- Method: patch (*args, **kw)

          Call open() with ‘method’ set to ‘PATCH’.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kw’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

      -- Method: options (*args, **kw)

          Call open() with ‘method’ set to ‘OPTIONS’.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kw’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

      -- Method: head (*args, **kw)

          Call open() with ‘method’ set to ‘HEAD’.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kw’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

      -- Method: trace (*args, **kw)

          Call open() with ‘method’ set to ‘TRACE’.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kw’ (‘Any’) –

          Return type: werkzeug.test.TestResponse.

 -- Class: werkzeug.test.TestResponse (response, status, headers,
          request, history=(), **kwargs)

     Response subclass that provides extra information about
     requests made with the test Client.

     Test client requests will always return an instance of this class.
     If a custom response class is passed to the client, it is
     subclassed along with this to support test information.

     If the test request included large files, or if the application is
     serving a file, call ‘close()’ to close any open files and prevent
     Python showing a ‘ResourceWarning’.

     Parameters:

        * ‘response’ (‘Union’‘[’‘Iterable’‘[’str(31)‘]’‘,
          ’‘Iterable’‘[’bytes(32)‘]’‘]’) –

        * ‘status’ (str(33)) –

        * ‘headers’ (see werkzeug.datastructures.Headers) –

        * ‘request’ (see werkzeug.wrappers.request.Request) –

        * ‘history’ (‘Tuple’‘[’werkzeug.test.TestResponse.‘,
          ’‘...’‘]’) –

        * ‘kwargs’ (‘Any’) –

     Return type: None(34)

      -- Attribute: request: werkzeug.wrappers.request.Request.

          A request object with the environ used to make the request
          that resulted in this response.

      -- Attribute: history: Tuple[see werkzeug.test.TestResponse,
               ...]

          A list of intermediate responses.  Populated when the test
          request is made with ‘follow_redirects’ enabled.

 -- Class: werkzeug.test.EnvironBuilder (path='/', base_url=None,
          query_string=None, method='GET', input_stream=None,
          content_type=None, content_length=None, errors_stream=None,
          multithread=False, multiprocess=False, run_once=False,
          headers=None, data=None, environ_base=None,
          environ_overrides=None, charset='utf-8', mimetype=None,
          json=None, auth=None)

     This class can be used to conveniently create a WSGI environment
     for testing purposes.  It can be used to quickly create WSGI
     environments or request objects from arbitrary data.

     The signature of this class is also used in some other places as of
     Werkzeug 0.5 (see create_environ(), ‘Response.from_values()’,
     see Client.open()).  Because of this most of the
     functionality is available through the constructor alone.

     Files and regular form data can be manipulated independently of
     each other with the form and files.
     attributes, but are passed with the same argument to the
     constructor: ‘data’.

     ‘data’ can be any of these values:

        - a ‘str’ or ‘bytes’ object: The object is converted into an
          input_stream, the content_length is set
          and you have to provide a content_type.

        - a ‘dict’ or ‘MultiDict’: The keys have to be strings.  The
          values have to be either any of the following objects, or a
          list of any of the following objects:

             - a ‘file’-like object: These are converted into
               ‘FileStorage’ objects automatically.

             - a ‘tuple’: The ‘add_file()’ method is called with the key
               and the unpacked ‘tuple’ items as positional arguments.

             - a ‘str’: The string is set as form data for the
               associated key.

        - a file-like object: The object content is loaded in memory and
          then handled like a regular ‘str’ or a ‘bytes’.

     Parameters:

        * ‘path’ (str(35)) – the path of the request.  In the WSGI
          environment this will end up as ‘PATH_INFO’. If the
          ‘query_string’ is not defined and there is a question mark in
          the ‘path’ everything after it is used as query string.

        * ‘base_url’ (‘Optional’‘[’str(36)‘]’) – the base URL is a URL
          that is used to extract the WSGI URL scheme, host (server name
          + server port) and the script root (‘SCRIPT_NAME’).

        * ‘query_string’ (‘Optional’‘[’‘Union’‘[’‘Mapping’‘[’str(37)‘,
          ’str(38)‘]’‘, ’str(39)‘]’‘]’) – an optional string or dict
          with URL parameters.

        * ‘method’ (str(40)) – the HTTP method to use, defaults to
          ‘GET’.

        * ‘input_stream’ (‘Optional’‘[’‘IO’‘[’bytes(41)‘]’‘]’) – an
          optional input stream.  Do not specify this and ‘data’.  As
          soon as an input stream is set you can’t modify args
          and files unless you set the
          input_stream to ‘None’ again.

        * ‘content_type’ (‘Optional’‘[’str(42)‘]’) – The content type
          for the request.  As of 0.5 you don’t have to provide this
          when specifying files and form data via ‘data’.

        * ‘content_length’ (‘Optional’‘[’int(43)‘]’) – The content
          length for the request.  You don’t have to specify this when
          providing data via ‘data’.

        * ‘errors_stream’ (‘Optional’‘[’‘IO’‘[’str(44)‘]’‘]’) – an
          optional error stream that is used for ‘wsgi.errors’.
          Defaults to ‘stderr’.

        * ‘multithread’ (bool(45)) – controls ‘wsgi.multithread’.
          Defaults to ‘False’.

        * ‘multiprocess’ (bool(46)) – controls ‘wsgi.multiprocess’.
          Defaults to ‘False’.

        * ‘run_once’ (bool(47)) – controls ‘wsgi.run_once’.  Defaults to
          ‘False’.

        * ‘headers’ (‘Optional’‘[’‘Union’‘[’
          werkzeug.datastructures.Headers.‘,
          ’‘Iterable’‘[’‘Tuple’‘[’str(48)‘, ’str(49)‘]’‘]’‘]’‘]’) – an
          optional list or ‘Headers’ object of headers.

        * ‘data’ (‘Optional’‘[’‘Union’‘[’‘IO’‘[’bytes(50)‘]’‘,
          ’str(51)‘, ’bytes(52)‘, ’‘Mapping’‘[’str(53)‘,
          ’‘Any’‘]’‘]’‘]’) – a string or dict of form data or a
          file-object.  See explanation above.

        * ‘json’ (‘Optional’‘[’‘Mapping’‘[’str(54)‘, ’‘Any’‘]’‘]’) – An
          object to be serialized and assigned to ‘data’.  Defaults the
          content type to ‘"application/json"’.  Serialized with the
          function assigned to json_dumps.

        * ‘environ_base’ (‘Optional’‘[’‘Mapping’‘[’str(55)‘,
          ’‘Any’‘]’‘]’) – an optional dict of environment defaults.

        * ‘environ_overrides’ (‘Optional’‘[’‘Mapping’‘[’str(56)‘,
          ’‘Any’‘]’‘]’) – an optional dict of environment overrides.

        * ‘charset’ (str(57)) – the charset used to encode string data.

        * ‘auth’ (‘Optional’‘[’‘Union’‘[’
          werkzeug.datastructures.Authorization.‘,
          ’‘Tuple’‘[’str(58)‘, ’str(59)‘]’‘]’‘]’) – An authorization
          object to use for the ‘Authorization’ header value.  A
          ‘(username, password)’ tuple is a shortcut for ‘Basic’
          authorization.

        * ‘mimetype’ (‘Optional’‘[’str(60)‘]’) –

     Return type: None(61)

     Changed in version 2.0: ‘REQUEST_URI’ and ‘RAW_URI’ is the full raw
     URI including the query string, not only the path.

     Changed in version 2.0: The default request_class is
     ‘Request’ instead of ‘BaseRequest’.

     New in version 2.0: Added the ‘auth’ parameter.

     New in version 0.15: The ‘json’ param and json_dumps().
     method.

     New in version 0.15: The environ has keys ‘REQUEST_URI’ and
     ‘RAW_URI’ containing the path before perecent-decoding.  This is
     not part of the WSGI PEP, but many WSGI servers include it.

     Changed in version 0.6: ‘path’ and ‘base_url’ can now be unicode
     strings that are encoded with ‘iri_to_uri()’.

      -- Attribute: server_protocol = 'HTTP/1.1'

          the server protocol to use.  defaults to HTTP/1.1

      -- Attribute: wsgi_version = (1, 0)

          the wsgi version to use.  defaults to (1, 0)

      -- Attribute: request_class

          alias of werkzeug.wrappers.request.Request.

      -- Method: static json_dumps (obj, *, skipkeys=False,
               ensure_ascii=True, check_circular=True, allow_nan=True,
               cls=None, indent=None, separators=None, default=None,
               sort_keys=False, **kw)

          The serialization function used when ‘json’ is passed.

      -- Method: classmethod from_environ (environ, **kwargs)

          Turn an environ dict back into a builder.  Any extra kwargs
          override the args extracted from the environ.

          Changed in version 2.0: Path and query values are passed
          through the WSGI decoding dance to avoid double encoding.

          New in version 0.15.

          Parameters:

             * ‘environ’ (‘WSGIEnvironment’) –

             * ‘kwargs’ (‘Any’) –

          Return type: EnvironBuilder.

      -- Property: base_url: str(62)

          The base URL is used to extract the URL scheme, host name,
          port, and root path.

      -- Property: content_type: Optional[str(63)]

          The content type for the request.  Reflected from and to the
          ‘headers’.  Do not set if you set files or
          form for auto detection.

      -- Property: mimetype: Optional[str(64)]

          The mimetype (content type without charset etc.)

          New in version 0.14.

      -- Property: mimetype_params: Mapping[str(65), str(66)]

          The mimetype parameters as dict.  For example if the content
          type is ‘text/html; charset=utf-8’ the params would be
          ‘{'charset': 'utf-8'}’.

          New in version 0.14.

      -- Property: content_length: Optional[int(67)]

          The content length as integer.  Reflected from and to the
          ‘headers’.  Do not set if you set files or
          form for auto detection.

      -- Property: form: werkzeug.datastructures.MultiDict.

          A ‘MultiDict’ of form values.

      -- Property: files: werkzeug.datastructures.FileMultiDict.

          A ‘FileMultiDict’ of uploaded files.  Use ‘add_file()’ to add
          new files.

      -- Property: input_stream: Optional[IO[bytes(68)]]

          An optional input stream.  This is mutually exclusive with
          setting form and files, setting it will
          clear those.  Do not provide this if the method is not ‘POST’
          or another method that has a body.

      -- Property: query_string: str(69)

          The query string.  If you set this to a string args.
          will no longer be available.

      -- Property: args: werkzeug.datastructures.MultiDict.

          The URL arguments as ‘MultiDict’.

      -- Property: server_name: str(70)

          The server name (read-only, use ‘host’ to set)

      -- Property: server_port: int(71)

          The server port as integer (read-only, use ‘host’ to set)

      -- Method: close ()

          Closes all files.  If you put real ‘file’ objects into the
          files dict you can call this method to
          automatically close them all in one go.

          Return type: None(72)

      -- Method: get_environ ()

          Return the built environ.

          Changed in version 0.15: The content type and length headers
          are set based on input stream detection.  Previously this only
          set the WSGI keys.

          Return type: WSGIEnvironment

      -- Method: get_request (cls=None)

          Returns a request with the data.  If the request class is not
          specified request_class is used.

          Parameters: ‘cls’ (‘Optional’‘[’‘Type’‘[’
          werkzeug.wrappers.request.Request.‘]’‘]’) – The request
          wrapper to use.

          Return type: werkzeug.wrappers.request.Request.

 -- Function: werkzeug.test.create_environ (*args, **kwargs)

     Create a new WSGI environ dict based on the values passed.  The
     first parameter should be the path of the request which defaults to
     ‘/’.  The second one can either be an absolute path (in that case
     the host is localhost:80) or a full path to the request with
     scheme, netloc port and the path to the script.

     This accepts the same arguments as the EnvironBuilder.
     constructor.

     Changed in version 0.5: This function is now a thin wrapper over
     EnvironBuilder which was added in 0.5.  The ‘headers’,
     ‘environ_base’, ‘environ_overrides’ and ‘charset’ parameters were
     added.

     Parameters:

        * ‘args’ (‘Any’) –

        * ‘kwargs’ (‘Any’) –

     Return type: WSGIEnvironment

 -- Function: werkzeug.test.run_wsgi_app (app, environ, buffered=False)

     Return a tuple in the form (app_iter, status, headers) of the
     application output.  This works best if you pass it an application
     that returns an iterator all the time.

     Sometimes applications may use the ‘write()’ callable returned by
     the ‘start_response’ function.  This tries to resolve such edge
     cases automatically.  But if you don’t get the expected output you
     should set ‘buffered’ to ‘True’ which enforces buffering.

     If passed an invalid WSGI application the behavior of this function
     is undefined.  Never pass non-conforming WSGI applications to this
     function.

     Parameters:

        * ‘app’ (‘WSGIApplication’) – the application to execute.

        * ‘buffered’ (bool(73)) – set to ‘True’ to enforce buffering.

        * ‘environ’ (‘WSGIEnvironment’) –

     Returns: tuple in the form ‘(app_iter, status, headers)’

     Return type: Tuple[Iterable[bytes(74)], str(75), see
     werkzeug.datastructures.Headers]

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/functions.html#bool

   (2) https://docs.python.org/3/library/functions.html#bool

   (3) https://docs.python.org/3/library/constants.html#None

   (4) https://docs.python.org/3/library/stdtypes.html#str

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7)
https://docs.python.org/3/library/datetime.html#datetime.timedelta

   (8) https://docs.python.org/3/library/functions.html#int

   (9) https://docs.python.org/3/library/stdtypes.html#str

   (10)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (11) https://docs.python.org/3/library/functions.html#int

   (12) https://docs.python.org/3/library/functions.html#float

   (13) https://docs.python.org/3/library/stdtypes.html#str

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/functions.html#bool

   (16) https://docs.python.org/3/library/functions.html#bool

   (17) https://docs.python.org/3/library/stdtypes.html#str

   (18) https://docs.python.org/3/library/stdtypes.html#str

   (19) https://docs.python.org/3/library/constants.html#None

   (20) https://docs.python.org/3/library/stdtypes.html#str

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23) https://docs.python.org/3/library/stdtypes.html#str

   (24) https://docs.python.org/3/library/functions.html#bool

   (25) https://docs.python.org/3/library/functions.html#bool

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/constants.html#None

   (28) https://docs.python.org/3/library/functions.html#bool

   (29) https://docs.python.org/3/library/functions.html#bool

   (30) https://docs.python.org/3/library/functions.html#bool

   (31) https://docs.python.org/3/library/stdtypes.html#str

   (32) https://docs.python.org/3/library/stdtypes.html#bytes

   (33) https://docs.python.org/3/library/stdtypes.html#str

   (34) https://docs.python.org/3/library/constants.html#None

   (35) https://docs.python.org/3/library/stdtypes.html#str

   (36) https://docs.python.org/3/library/stdtypes.html#str

   (37) https://docs.python.org/3/library/stdtypes.html#str

   (38) https://docs.python.org/3/library/stdtypes.html#str

   (39) https://docs.python.org/3/library/stdtypes.html#str

   (40) https://docs.python.org/3/library/stdtypes.html#str

   (41) https://docs.python.org/3/library/stdtypes.html#bytes

   (42) https://docs.python.org/3/library/stdtypes.html#str

   (43) https://docs.python.org/3/library/functions.html#int

   (44) https://docs.python.org/3/library/stdtypes.html#str

   (45) https://docs.python.org/3/library/functions.html#bool

   (46) https://docs.python.org/3/library/functions.html#bool

   (47) https://docs.python.org/3/library/functions.html#bool

   (48) https://docs.python.org/3/library/stdtypes.html#str

   (49) https://docs.python.org/3/library/stdtypes.html#str

   (50) https://docs.python.org/3/library/stdtypes.html#bytes

   (51) https://docs.python.org/3/library/stdtypes.html#str

   (52) https://docs.python.org/3/library/stdtypes.html#bytes

   (53) https://docs.python.org/3/library/stdtypes.html#str

   (54) https://docs.python.org/3/library/stdtypes.html#str

   (55) https://docs.python.org/3/library/stdtypes.html#str

   (56) https://docs.python.org/3/library/stdtypes.html#str

   (57) https://docs.python.org/3/library/stdtypes.html#str

   (58) https://docs.python.org/3/library/stdtypes.html#str

   (59) https://docs.python.org/3/library/stdtypes.html#str

   (60) https://docs.python.org/3/library/stdtypes.html#str

   (61) https://docs.python.org/3/library/constants.html#None

   (62) https://docs.python.org/3/library/stdtypes.html#str

   (63) https://docs.python.org/3/library/stdtypes.html#str

   (64) https://docs.python.org/3/library/stdtypes.html#str

   (65) https://docs.python.org/3/library/stdtypes.html#str

   (66) https://docs.python.org/3/library/stdtypes.html#str

   (67) https://docs.python.org/3/library/functions.html#int

   (68) https://docs.python.org/3/library/stdtypes.html#bytes

   (69) https://docs.python.org/3/library/stdtypes.html#str

   (70) https://docs.python.org/3/library/stdtypes.html#str

   (71) https://docs.python.org/3/library/functions.html#int

   (72) https://docs.python.org/3/library/constants.html#None

   (73) https://docs.python.org/3/library/functions.html#bool

   (74) https://docs.python.org/3/library/stdtypes.html#bytes

   (75) https://docs.python.org/3/library/stdtypes.html#str

2.3 Debugging Applications
==========================

Depending on the WSGI gateway/server, exceptions are handled
differently.  Most of the time, exceptions go to stderr or the error
log, and a generic “500 Internal Server Error” message is displayed.

Since this is not the best debugging environment, Werkzeug provides a
WSGI middleware that renders nice tracebacks, optionally with an
interactive debug console to execute code in any frame.

     Danger: The debugger allows the execution of arbitrary code which
     makes it a major security risk.  `The debugger must never be used
     on production machines.  We cannot stress this enough.  Do not
     enable the debugger in production.'

     Note: The interactive debugger does not work in forking
     environments, such as a server that starts multiple processes.
     Most such environments are production servers, where the debugger
     should not be enabled anyway.

2.3.1 Enabling the Debugger
---------------------------

Enable the debugger by wrapping the application with the
DebuggedApplication middleware.  Alternatively, you can pass
‘use_debugger=True’ to ‘run_simple()’ and it will do that for you.

 -- Class: werkzeug.debug.DebuggedApplication (app, evalex=False,
          request_key='werkzeug.request', console_path='/console',
          console_init_func=None, show_hidden_frames=False,
          pin_security=True, pin_logging=True)

     Enables debugging support for a given application:

          from werkzeug.debug import DebuggedApplication
          from myapp import app
          app = DebuggedApplication(app, evalex=True)

     The ‘evalex’ keyword argument allows evaluating expressions in a
     traceback’s frame context.

     Parameters:

        * ‘app’ (‘WSGIApplication’) – the WSGI application to run
          debugged.

        * ‘evalex’ (bool(1)) – enable exception evaluation feature
          (interactive debugging).  This requires a non-forking server.

        * ‘request_key’ (str(2)) – The key that points to the request
          object in ths environment.  This parameter is ignored in
          current versions.

        * ‘console_path’ (str(3)) – the URL for a general purpose
          console.

        * ‘console_init_func’ (‘Optional’‘[’‘Callable’‘[’‘[’‘]’‘,
          ’‘Dict’‘[’str(4)‘, ’‘Any’‘]’‘]’‘]’) – the function that is
          executed before starting the general purpose console.  The
          return value is used as initial namespace.

        * ‘show_hidden_frames’ (bool(5)) – by default hidden traceback
          frames are skipped.  You can show them by setting this
          parameter to ‘True’.

        * ‘pin_security’ (bool(6)) – can be used to disable the pin
          based security system.

        * ‘pin_logging’ (bool(7)) – enables the logging of the pin
          system.

     Return type: None(8)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/functions.html#bool

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/stdtypes.html#str

   (5) https://docs.python.org/3/library/functions.html#bool

   (6) https://docs.python.org/3/library/functions.html#bool

   (7) https://docs.python.org/3/library/functions.html#bool

   (8) https://docs.python.org/3/library/constants.html#None

2.3.2 Using the Debugger
------------------------

Once enabled and an error happens during a request you will see a
detailed traceback instead of a generic “internal server error”.  The
traceback is still output to the terminal as well.

The error message is displayed at the top.  Clicking it jumps to the
bottom of the traceback.  Frames that represent user code, as opposed to
built-ins or installed packages, are highlighted blue.  Clicking a frame
will show more lines for context, clicking again will hide them.

If you have the ‘evalex’ feature enabled you can get a console for every
frame in the traceback by hovering over a frame and clicking the console
icon that appears at the right.  Once clicked a console opens where you
can execute Python code in:

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.

2.3.3 Debugger PIN
------------------

Starting with Werkzeug 0.11 the debug console is protected by a PIN.
This is a security helper to make it less likely for the debugger to be
exploited if you forget to disable it when deploying to production.  The
PIN based authentication is enabled by default.

The first time a console is opened, a dialog 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.  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 an incorrect PIN is entered too many times the server needs to be
restarted.

`This feature is not meant to entirely secure the debugger.  It is
intended to make it harder for an attacker to exploit the debugger.
Never enable the debugger in production.'

2.3.4 Pasting Errors
--------------------

If you click on the “Traceback (most recent call last)” header, the view
switches to a traditional text-based traceback.  You can copy and paste
this in order to provide information when asking a question or reporting
an issue.

3 Reference
***********

3.1 Request / Response Objects
==============================

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).

3.1.1 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 Request class wraps the
‘environ’ for easier access to request variables (form data, request
headers etc.).

The 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(f"Hello {request.args.get('name', 'World!')}!")
         return response(environ, start_response)

Because this is a very common task the 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(f"Hello {request.args.get('name', 'World!')}!")

The ‘application’ is still a valid WSGI application that accepts the
environment and ‘start_response’ callable.

3.1.2 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’.

3.1.3 Wrapper Classes
---------------------

 -- Class: werkzeug.wrappers.Request (environ, populate_request=True,
          shallow=False)

     Represents an incoming WSGI HTTP request, with headers and body
     taken from the WSGI environment.  Has properties and methods for
     using the functionality defined by various HTTP specs.  The data in
     requests object is read-only.

     Text data is assumed to use UTF-8 encoding, which should be true
     for the vast majority of modern clients.  Using an encoding set by
     the client is unsafe in Python due to extra encodings it provides,
     such as ‘zip’.  To change the assumed encoding, subclass and
     replace ‘charset’.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – The WSGI environ is generated
          by the WSGI server and contains information about the server
          configuration and client request.

        * ‘populate_request’ (bool(1)) – Add this request object to the
          WSGI environ as ‘environ['werkzeug.request']’.  Can be useful
          when debugging.

        * ‘shallow’ (bool(2)) – Makes reading from stream.
          (and any method that would read from it) raise a
          RuntimeError(3).  Useful to prevent consuming the form data in
          middleware, which would make it unavailable to the final
          application.

     Return type: None(4)

     Changed in version 2.0: Combine ‘BaseRequest’ and mixins into a
     single ‘Request’ class.  Using the old classes is deprecated and
     will be removed in Werkzeug 2.1.

     Changed in version 0.5: Read-only mode is enforced with immutable
     classes for all data.

      -- Method: _get_file_stream (total_content_length, content_type,
               filename=None, content_length=None)

          Called to get a stream for the file upload.

          This must provide a file-like class with ‘read()’,
          ‘readline()’ and ‘seek()’ methods that is both writeable and
          readable.

          The default implementation returns a temporary file if the
          total content length is higher than 500KB. Because many
          browsers do not provide a content length for the files only
          the total content length matters.

          Parameters:

             * ‘total_content_length’ (‘Optional’‘[’int(5)‘]’) – the
               total content length of all the data in the request
               combined.  This value is guaranteed to be there.

             * ‘content_type’ (‘Optional’‘[’str(6)‘]’) – the mimetype of
               the uploaded file.

             * ‘filename’ (‘Optional’‘[’str(7)‘]’) – the filename of the
               uploaded file.  May be ‘None’.

             * ‘content_length’ (‘Optional’‘[’int(8)‘]’) – the length of
               this file.  This value is usually not provided because
               webbrowsers do not provide this value.

          Return type: IO[bytes(9)]

      -- Property: accept_charsets:
               werkzeug.datastructures.CharsetAccept.

          List of charsets this client supports as CharsetAccept
          object.

      -- Property: accept_encodings:
               werkzeug.datastructures.Accept.

          List of encodings this client accepts.  Encodings in a HTTP
          term are compression encodings such as gzip.  For charsets
          have a look at ‘accept_charset’.

      -- Property: accept_languages:
               werkzeug.datastructures.LanguageAccept.

          List of languages this client accepts as LanguageAccept
          object.

      -- Property: accept_mimetypes:
               werkzeug.datastructures.MIMEAccept.

          List of mimetypes this client supports as MIMEAccept
          object.

      -- Attribute: access_control_request_headers

          Sent with a preflight request to indicate which headers will
          be sent with the cross origin request.  Set
          ‘access_control_allow_headers’ on the response to indicate
          which headers are allowed.

      -- Attribute: access_control_request_method

          Sent with a preflight request to indicate which method will be
          used for the cross origin request.  Set
          ‘access_control_allow_methods’ on the response to indicate
          which methods are allowed.

      -- Property: access_route: List[str(10)]

          If a forwarded header exists this is a list of all ip
          addresses from the client ip to the last proxy server.

      -- Method: classmethod application (f)

          Decorate a function as responder that accepts the request as
          the last argument.  This works like the ‘responder()’
          decorator but the function is passed the request object as the
          last argument and the request object will be closed
          automatically:

               @Request.application
               def my_wsgi_app(request):
                   return Response('Hello World!')

          As of Werkzeug 0.14 HTTP exceptions are automatically caught
          and converted to responses instead of failing.

          Parameters: ‘f’ (‘Callable’‘[’‘[’Request.‘]’‘,
          ’‘WSGIApplication’‘]’) – the WSGI callable to decorate

          Returns: a new WSGI callable

          Return type: WSGIApplication

      -- Property: args: MultiDict[str(11), str(12)]

          The parsed URL parameters (the part in the URL after the
          question mark).

          By default an ImmutableMultiDict is returned from
          this function.  This can be changed by setting
          parameter_storage_class to a different type.  This might
          be necessary if the order of the form data is important.

      -- Property: authorization: Optional[see
               werkzeug.datastructures.Authorization]

          The ‘Authorization’ object in parsed form.

      -- Property: base_url: str(13)

          Like url but without the query string.

      -- Property: cache_control:
               werkzeug.datastructures.RequestCacheControl.

          A RequestCacheControl object for the incoming cache
          control headers.

      -- Method: close ()

          Closes associated resources of this request object.  This
          closes all file handles explicitly.  You can also use the
          request object in a with statement which will automatically
          close it.

          New in version 0.9.

          Return type: None(14)

      -- Attribute: content_encoding

          The Content-Encoding entity-header field is used as a modifier
          to the media-type.  When present, its value indicates what
          additional content codings have been applied to the
          entity-body, and thus what decoding mechanisms must be applied
          in order to obtain the media-type referenced by the
          Content-Type header field.

          New in version 0.9.

      -- Property: content_length: Optional[int(15)]

          The Content-Length entity-header field indicates the size of
          the entity-body in bytes or, in the case of the HEAD method,
          the size of the entity-body that would have been sent had the
          request been a GET.

      -- Attribute: content_md5

          The Content-MD5 entity-header field, as defined in RFC 1864,
          is an MD5 digest of the entity-body for the purpose of
          providing an end-to-end message integrity check (MIC) of the
          entity-body.  (Note: a MIC is good for detecting accidental
          modification of the entity-body in transit, but is not proof
          against malicious attacks.)

          New in version 0.9.

      -- Attribute: content_type

          The Content-Type entity-header field indicates the media type
          of the entity-body sent to the recipient or, in the case of
          the HEAD method, the media type that would have been sent had
          the request been a GET.

      -- Property: cookies: ImmutableMultiDict[str(16), str(17)]

          A dict(18) with the contents of all cookies transmitted with
          the request.

      -- Property: data: bytes(19)

          Contains the incoming request data as string in case it came
          with a mimetype Werkzeug does not handle.

      -- Attribute: date

          The Date general-header field represents the date and time at
          which the message was originated, having the same semantics as
          orig-date in RFC 822.

          Changed in version 2.0: The datetime object is timezone-aware.

      -- Attribute: dict_storage_class

          alias of werkzeug.datastructures.ImmutableMultiDict.

      -- Attribute: disable_data_descriptor: Optional[bool(20)] = None

          Disable the data property to avoid reading from the
          input stream.

          Deprecated since version 2.0: Will be removed in Werkzeug 2.1.
          Create the request with ‘shallow=True’ instead.

          New in version 0.9.

      -- Attribute: environ: WSGIEnvironment

          The WSGI environment containing HTTP headers and information
          from the WSGI server.

      -- Property: files: ImmutableMultiDict[str(21), FileStorage]

          MultiDict object containing all uploaded files.
          Each key in files is the name from the ‘<input
          type="file" name="">’.  Each value in files is a
          Werkzeug FileStorage object.

          It basically behaves like a standard file object you know from
          Python, with the difference that it also has a save()
          function that can store the file on the filesystem.

          Note that files will only contain data if the
          request method was POST, PUT or PATCH and the ‘<form>’ that
          posted to the request had ‘enctype="multipart/form-data"’.  It
          will be empty otherwise.

          See the MultiDict. / see FileStorage.
          documentation for more details about the used data structure.

      -- Property: form: ImmutableMultiDict[str(22), str(23)]

          The form parameters.  By default an ImmutableMultiDict
          is returned from this function.  This can be changed by
          setting parameter_storage_class to a different
          type.  This might be necessary if the order of the form data
          is important.

          Please keep in mind that file uploads will not end up here,
          but instead in the files attribute.

          Changed in version 0.9: Previous to Werkzeug 0.9 this would
          only contain form data for POST and PUT requests.

      -- Attribute: form_data_parser_class

          alias of werkzeug.formparser.FormDataParser.

      -- Method: classmethod from_values (*args, **kwargs)

          Create a new request object based on the values provided.  If
          environ is given missing values are filled from there.  This
          method is useful for small scripts when you need to simulate a
          request from an URL. Do not use this method for unittesting,
          there is a full featured client object (‘Client’) that allows
          to create multipart requests, support for cookies etc.

          This accepts the same options as the EnvironBuilder.

          Changed in version 0.5: This method now accepts the same
          arguments as EnvironBuilder.  Because of this the
          ‘environ’ parameter is now called ‘environ_overrides’.

          Returns: request object

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kwargs’ (‘Any’) –

          Return type: werkzeug.wrappers.request.Request.

      -- Property: full_path: str(24)

          Requested path, including the query string.

      -- Method: get_data (cache=True, as_text=False,
               parse_form_data=False)

          This reads the buffered incoming data from the client into one
          bytes object.  By default this is cached but that behavior can
          be changed by setting ‘cache’ to ‘False’.

          Usually it’s a bad idea to call this method without checking
          the content length first as a client could send dozens of
          megabytes or more to cause memory problems on the server.

          Note that if the form data was already parsed this method will
          not return anything as form data parsing does not cache the
          data like this method does.  To implicitly invoke form data
          parsing function set ‘parse_form_data’ to ‘True’.  When this
          is done the return value of this method will be an empty
          string if the form parser handles the data.  This generally is
          not necessary as if the whole data is cached (which is the
          default) the form parser will used the cached data to parse
          the form data.  Please be generally aware of checking the
          content length first in any case before calling this method to
          avoid exhausting server memory.

          If ‘as_text’ is set to ‘True’ the return value will be a
          decoded string.

          New in version 0.9.

          Parameters:

             * ‘cache’ (bool(25)) –

             * ‘as_text’ (bool(26)) –

             * ‘parse_form_data’ (bool(27)) –

          Return type: Union[bytes(28), str(29)]

      -- Method: get_json (force=False, silent=False, cache=True)

          Parse data as JSON.

          If the mimetype does not indicate JSON (‘application/json’,
          see is_json), this returns ‘None’.

          If parsing fails, see on_json_loading_failed() is
          called and its return value is used as the return value.

          Parameters:

             * ‘force’ (bool(30)) – Ignore the mimetype and always try
               to parse JSON.

             * ‘silent’ (bool(31)) – Silence parsing errors and return
               ‘None’ instead.

             * ‘cache’ (bool(32)) – Store the parsed JSON to return for
               subsequent calls.

          Return type: Optional[Any]

      -- Attribute: headers

          The headers received with the request.

      -- Property: host: str(33)

          The host name the request was made to, including the port if
          it’s non-standard.  Validated with ‘trusted_hosts’.

      -- Property: host_url: str(34)

          The request URL scheme and host only.

      -- Property: if_match: werkzeug.datastructures.ETags.

          An object containing all the etags in the ‘If-Match’ header.

          Return type: ETags.

      -- Property: if_modified_since: Optional[datetime.datetime(35)]

          The parsed ‘If-Modified-Since’ header as a datetime object.

          Changed in version 2.0: The datetime object is timezone-aware.

      -- Property: if_none_match: werkzeug.datastructures.ETags.

          An object containing all the etags in the ‘If-None-Match’
          header.

          Return type: ETags.

      -- Property: if_range: werkzeug.datastructures.IfRange.

          The parsed ‘If-Range’ header.

          Changed in version 2.0: ‘IfRange.date’ is timezone-aware.

          New in version 0.7.

      -- Property: if_unmodified_since: Optional[datetime.datetime(36)]

          The parsed ‘If-Unmodified-Since’ header as a datetime object.

          Changed in version 2.0: The datetime object is timezone-aware.

      -- Attribute: input_stream

          The WSGI input stream.

          In general it’s a bad idea to use this one because you can
          easily read past the boundary.  Use the stream.
          instead.

      -- Property: is_json: bool(37)

          Check if the mimetype indicates JSON data, either
          ‘application/json’ or ‘application/*+json’.

      -- Attribute: is_multiprocess

          boolean that is ‘True’ if the application is served by a WSGI
          server that spawns multiple processes.

      -- Attribute: is_multithread

          boolean that is ‘True’ if the application is served by a
          multithreaded WSGI server.

      -- Attribute: is_run_once

          boolean that is ‘True’ if the application will be executed
          only once in a process lifetime.  This is the case for CGI for
          example, but it’s not guaranteed that the execution only
          happens one time.

      -- Property: is_secure: bool(38)

          ‘True’ if the request was made with a secure protocol (HTTPS
          or WSS).

      -- Property: json: Optional[Any]

          The parsed JSON data if mimetype indicates JSON
          (‘application/json’, see is_json).

          Calls get_json() with default arguments.

      -- Attribute: json_module = <module 'json' from
               '/usr/lib64/python3.8/json/__init__.py'>

          A module or other object that has ‘dumps’ and ‘loads’
          functions that match the API of the built-in json(39) module.

      -- Attribute: list_storage_class

          alias of werkzeug.datastructures.ImmutableList.

      -- Method: make_form_data_parser ()

          Creates the form data parser.  Instantiates the
          form_data_parser_class with some parameters.

          New in version 0.8.

          Return type: werkzeug.formparser.FormDataParser.

      -- Attribute: max_content_length: Optional[int(40)] = None

          the maximum content length.  This is forwarded to the form
          data parsing function (‘parse_form_data()’).  When set and the
          form or files attribute is accessed and
          the parsing fails because more than the specified value is
          transmitted a RequestEntityTooLarge exception is
          raised.

          Have a look at Dealing with Request Data for more
          details.

          New in version 0.5.

      -- Attribute: max_form_memory_size: Optional[int(41)] = None

          the maximum form field size.  This is forwarded to the form
          data parsing function (‘parse_form_data()’).  When set and the
          form or files attribute is accessed and
          the data in memory for post data is longer than the specified
          value a RequestEntityTooLarge exception is raised.

          Have a look at Dealing with Request Data for more
          details.

          New in version 0.5.

      -- Attribute: max_forwards

          The Max-Forwards request-header field provides a mechanism
          with the TRACE and OPTIONS methods to limit the number of
          proxies or gateways that can forward the request to the next
          inbound server.

      -- Attribute: method

          The method the request was made with, such as ‘GET’.

      -- Property: mimetype: str(42)

          Like content_type, but without parameters (eg,
          without charset, type etc.)  and always lowercase.  For
          example if the content type is ‘text/HTML; charset=utf-8’ the
          mimetype would be ‘'text/html'’.

      -- Property: mimetype_params: Dict[str(43), str(44)]

          The mimetype parameters as dict.  For example if the content
          type is ‘text/html; charset=utf-8’ the params would be
          ‘{'charset': 'utf-8'}’.

      -- Method: on_json_loading_failed (e)

          Called if get_json() parsing fails and isn’t
          silenced.  If this method returns a value, it is used as the
          return value for get_json().  The default
          implementation raises BadRequest.

          Parameters: ‘e’ (ValueError(45)) –

          Return type: Any

      -- Attribute: origin

          The host that the request originated from.  Set
          ‘access_control_allow_origin’ on the response to indicate
          which origins are allowed.

      -- Attribute: parameter_storage_class

          alias of werkzeug.datastructures.ImmutableMultiDict.

      -- Attribute: path

          The path part of the URL after root_path.  This is
          the path used for routing within the application.

      -- Property: pragma: werkzeug.datastructures.HeaderSet.

          The Pragma general-header field is used to include
          implementation-specific directives that might apply to any
          recipient along the request/response chain.  All pragma
          directives specify optional behavior from the viewpoint of the
          protocol; however, some systems MAY require that behavior be
          consistent with the directives.

      -- Attribute: query_string

          The part of the URL after the “?”.  This is the raw value, use
          args for the parsed values.

      -- Property: range: Optional[see werkzeug.datastructures.Range]

          The parsed ‘Range’ header.

          New in version 0.7.

          Return type: Range.

      -- Attribute: referrer

          The Referer[sic] request-header field allows the client to
          specify, for the server’s benefit, the address (URI) of the
          resource from which the Request-URI was obtained (the
          “referrer”, although the header field is misspelled).

      -- Attribute: remote_addr

          The address of the client sending the request.

      -- Attribute: remote_user

          If the server supports user authentication, and the script is
          protected, this attribute contains the username the user has
          authenticated as.

      -- Attribute: root_path

          The prefix that the application is mounted under, without a
          trailing slash.  path comes after this.

      -- Property: root_url: str(46)

          The request URL scheme, host, and root path.  This is the root
          that the application is accessed from.

      -- Attribute: scheme

          The URL scheme of the protocol the request used, such as
          ‘https’ or ‘wss’.

      -- Property: script_root: str(47)

          Alias for ‘self.root_path’.  ‘environ["SCRIPT_ROOT"]’ without
          a trailing slash.

      -- Attribute: server

          The address of the server.  ‘(host, port)’, ‘(path, None)’ for
          unix sockets, or ‘None’ if not known.

      -- Attribute: shallow: bool(48)

          Set when creating the request object.  If ‘True’, reading from
          the request body will cause a ‘RuntimeException’.  Useful to
          prevent modifying the stream from middleware.

      -- Property: stream: IO[bytes(49)]

          If the incoming form data was not encoded with a known
          mimetype the data is stored unmodified in this stream for
          consumption.  Most of the time it is a better idea to use
          data which will give you that data as a string.
          The stream only returns the data once.

          Unlike input_stream this stream is properly guarded
          that you can’t accidentally read past the length of the input.
          Werkzeug will internally always refer to this stream to read
          data which makes it possible to wrap this object with a stream
          that does filtering.

          Changed in version 0.9: This stream is now always available
          but might be consumed by the form parser later on.  Previously
          the stream was only set if no parsing happened.

      -- Property: url: str(50)

          The full request URL with the scheme, host, root path, path,
          and query string.

      -- Property: url_charset: str(51)

          The charset that is assumed for URLs.  Defaults to the value
          of ‘charset’.

          New in version 0.6.

      -- Property: url_root: str(52)

          Alias for root_url.  The URL with scheme, host, and
          root path.  For example, ‘https://example.com/app/’.

      -- Property: user_agent: werkzeug.user_agent.UserAgent.

          The user agent.  Use ‘user_agent.string’ to get the header
          value.  Set user_agent_class to a subclass of
          UserAgent to provide parsing for the other properties or
          other extended data.

          Changed in version 2.0: The built in parser is deprecated and
          will be removed in Werkzeug 2.1.  A ‘UserAgent’ subclass must
          be set to parse data from the string.

      -- Attribute: user_agent_class

          alias of ‘werkzeug.useragents._UserAgent’

      -- Property: values: CombinedMultiDict[str(53), str(54)]

          A werkzeug.datastructures.CombinedMultiDict that
          combines args and form.

          For GET requests, only ‘args’ are present, not ‘form’.

          Changed in version 2.0: For GET requests, only ‘args’ are
          present, not ‘form’.

      -- Property: want_form_data_parsed: bool(55)

          ‘True’ if the request method carries content.  By default this
          is true if a ‘Content-Type’ is sent.

          New in version 0.8.

 -- Class: werkzeug.wrappers.Response (response=None, status=None,
          headers=None, mimetype=None, content_type=None,
          direct_passthrough=False)

     Represents an outgoing WSGI HTTP response with body, status, and
     headers.  Has properties and methods for using the functionality
     defined by various HTTP specs.

     The response body is flexible to support different use cases.  The
     simple form is passing bytes, or a string which will be encoded as
     UTF-8.  Passing an iterable of bytes or strings makes this a
     streaming response.  A generator is particularly useful for
     building a CSV file in memory or using SSE (Server Sent Events).  A
     file-like object is also iterable, although the send_file()
     helper should be used in that case.

     The response object is itself a WSGI application callable.  When
     called (see __call__()) with ‘environ’ and ‘start_response’,
     it will pass its status and headers to ‘start_response’ then return
     its body as an iterable.

          from werkzeug.wrappers.response import Response

          def index():
              return Response("Hello, World!")

          def application(environ, start_response):
              path = environ.get("PATH_INFO") or "/"

              if path == "/":
                  response = index()
              else:
                  response = Response("Not Found", status=404)

              return response(environ, start_response)

     Parameters:

        * ‘response’ (‘Union’‘[’‘Iterable’‘[’str(56)‘]’‘,
          ’‘Iterable’‘[’bytes(57)‘]’‘]’) – The data for the body of the
          response.  A string or bytes, or tuple or list of strings or
          bytes, for a fixed-length response, or any other iterable of
          strings or bytes for a streaming response.  Defaults to an
          empty body.

        * ‘status’ (‘Optional’‘[’‘Union’‘[’int(58)‘, ’str(59)‘,
          ’http.HTTPStatus(60)‘]’‘]’) – The status code for the
          response.  Either an int, in which case the default status
          message is added, or a string in the form ‘{code} {message}’,
          like ‘404 Not Found’.  Defaults to 200.

        * ‘headers’ (see werkzeug.datastructures.Headers) – A
          Headers object, or a list of ‘(key, value)’ tuples
          that will be converted to a ‘Headers’ object.

        * ‘mimetype’ (‘Optional’‘[’str(61)‘]’) – The mime type (content
          type without charset or other parameters) of the response.  If
          the value starts with ‘text/’ (or matches some other special
          cases), the charset will be added to create the
          ‘content_type’.

        * ‘content_type’ (‘Optional’‘[’str(62)‘]’) – The full content
          type of the response.  Overrides building the value from
          ‘mimetype’.

        * ‘direct_passthrough’ (bool(63)) – Pass the response body
          directly through as the WSGI iterable.  This can be used when
          the body is a binary file or other iterator of bytes, to skip
          some unnecessary checks.  Use send_file() instead
          of setting this manually.

     Return type: None(64)

     Changed in version 2.0: Combine ‘BaseResponse’ and mixins into a
     single ‘Response’ class.  Using the old classes is deprecated and
     will be removed in Werkzeug 2.1.

     Changed in version 0.5: The ‘direct_passthrough’ parameter was
     added.

      -- Method: __call__ (environ, start_response)

          Process this response as WSGI application.

          Parameters:

             * ‘environ’ (‘WSGIEnvironment’) – the WSGI environment.

             * ‘start_response’ (‘StartResponse’) – the response
               callable provided by the WSGI server.

          Returns: an application iterator

          Return type: Iterable[bytes(65)]

      -- Method: _ensure_sequence (mutable=False)

          This method can be called by methods that need a sequence.  If
          ‘mutable’ is true, it will also ensure that the response
          sequence is a standard Python list.

          New in version 0.6.

          Parameters: ‘mutable’ (bool(66)) –

          Return type: None(67)

      -- Attribute: accept_ranges

          The ‘Accept-Ranges’ header.  Even though the name would
          indicate that multiple values are supported, it must be one
          string token only.

          The values ‘'bytes'’ and ‘'none'’ are common.

          New in version 0.7.

      -- Property: access_control_allow_credentials: bool(68)

          Whether credentials can be shared by the browser to JavaScript
          code.  As part of the preflight request it indicates whether
          credentials can be used on the cross origin request.

      -- Attribute: access_control_allow_headers

          Which headers can be sent with the cross origin request.

      -- Attribute: access_control_allow_methods

          Which methods can be used for the cross origin request.

      -- Attribute: access_control_allow_origin

          The origin or ‘*’ for any origin that may make cross origin
          requests.

      -- Attribute: access_control_expose_headers

          Which headers can be shared by the browser to JavaScript code.

      -- Attribute: access_control_max_age

          The maximum age in seconds the access control settings can be
          cached for.

      -- Method: add_etag (overwrite=False, weak=False)

          Add an etag for the current response if there is none yet.

          Changed in version 2.0: SHA-1 is used to generate the value.
          MD5 may not be available in some environments.

          Parameters:

             * ‘overwrite’ (bool(69)) –

             * ‘weak’ (bool(70)) –

          Return type: None(71)

      -- Attribute: age

          The Age response-header field conveys the sender’s estimate of
          the amount of time since the response (or its revalidation)
          was generated at the origin server.

          Age values are non-negative decimal integers, representing
          time in seconds.

      -- Property: allow: werkzeug.datastructures.HeaderSet.

          The Allow entity-header field lists the set of methods
          supported by the resource identified by the Request-URI. The
          purpose of this field is strictly to inform the recipient of
          valid methods associated with the resource.  An Allow header
          field MUST be present in a 405 (Method Not Allowed) response.

      -- Attribute: autocorrect_location_header = True

          Should this response object correct the location header to be
          RFC conformant?  This is true by default.

          New in version 0.8.

      -- Attribute: automatically_set_content_length = True

          Should this response object automatically set the
          content-length header if possible?  This is true by default.

          New in version 0.8.

      -- Property: cache_control:
               werkzeug.datastructures.ResponseCacheControl.

          The Cache-Control general-header field is used to specify
          directives that MUST be obeyed by all caching mechanisms along
          the request/response chain.

      -- Method: calculate_content_length ()

          Returns the content length if available or ‘None’ otherwise.

          Return type: Optional[int(72)]

      -- Method: call_on_close (func)

          Adds a function to the internal list of functions that should
          be called as part of closing down the response.  Since 0.7
          this function also returns the function that was passed so
          that this can be used as a decorator.

          New in version 0.6.

          Parameters: ‘func’ (‘Callable’‘[’‘[’‘]’‘, ’‘Any’‘]’) –

          Return type: Callable[[], Any]

      -- Method: close ()

          Close the wrapped response if possible.  You can also use the
          object in a with statement which will automatically close it.

          New in version 0.9: Can now be used in a with statement.

          Return type: None(73)

      -- Attribute: content_encoding

          The Content-Encoding entity-header field is used as a modifier
          to the media-type.  When present, its value indicates what
          additional content codings have been applied to the
          entity-body, and thus what decoding mechanisms must be applied
          in order to obtain the media-type referenced by the
          Content-Type header field.

      -- Property: content_language:
               werkzeug.datastructures.HeaderSet.

          The Content-Language entity-header field describes the natural
          language(s) of the intended audience for the enclosed entity.
          Note that this might not be equivalent to all the languages
          used within the entity-body.

      -- Attribute: content_length

          The Content-Length entity-header field indicates the size of
          the entity-body, in decimal number of OCTETs, sent to the
          recipient or, in the case of the HEAD method, the size of the
          entity-body that would have been sent had the request been a
          GET.

      -- Attribute: content_location

          The Content-Location entity-header field MAY be used to supply
          the resource location for the entity enclosed in the message
          when that entity is accessible from a location separate from
          the requested resource’s URI.

      -- Attribute: content_md5

          The Content-MD5 entity-header field, as defined in RFC 1864,
          is an MD5 digest of the entity-body for the purpose of
          providing an end-to-end message integrity check (MIC) of the
          entity-body.  (Note: a MIC is good for detecting accidental
          modification of the entity-body in transit, but is not proof
          against malicious attacks.)

      -- Property: content_range:
               werkzeug.datastructures.ContentRange.

          The ‘Content-Range’ header as a ContentRange.
          object.  Available even if the header is not set.

          New in version 0.7.

      -- Property: content_security_policy:
               werkzeug.datastructures.ContentSecurityPolicy

          The ‘Content-Security-Policy’ header as a
          ‘ContentSecurityPolicy’ object.  Available even if the header
          is not set.

          The Content-Security-Policy header adds an additional layer of
          security to help detect and mitigate certain types of attacks.

      -- Property: content_security_policy_report_only:
               werkzeug.datastructures.ContentSecurityPolicy

          The ‘Content-Security-policy-report-only’ header as a
          ‘ContentSecurityPolicy’ object.  Available even if the header
          is not set.

          The Content-Security-Policy-Report-Only header adds a csp
          policy that is not enforced but is reported thereby helping
          detect certain types of attacks.

      -- Attribute: content_type

          The Content-Type entity-header field indicates the media type
          of the entity-body sent to the recipient or, in the case of
          the HEAD method, the media type that would have been sent had
          the request been a GET.

      -- Attribute: cross_origin_embedder_policy

          Prevents a document from loading any cross-origin resources
          that do not explicitly grant the document permission.  Values
          must be a member of the ‘werkzeug.http.COEP’ enum.

      -- Attribute: cross_origin_opener_policy

          Allows control over sharing of browsing context group with
          cross-origin documents.  Values must be a member of the
          ‘werkzeug.http.COOP’ enum.

      -- Property: data: Union[bytes(74), str(75)]

          A descriptor that calls get_data() and
          set_data().

      -- Attribute: date

          The Date general-header field represents the date and time at
          which the message was originated, having the same semantics as
          orig-date in RFC 822.

          Changed in version 2.0: The datetime object is timezone-aware.

      -- Method: delete_cookie (key, path='/', domain=None,
               secure=False, httponly=False, samesite=None)

          Delete a cookie.  Fails silently if key doesn’t exist.

          Parameters:

             * ‘key’ (str(76)) – the key (name) of the cookie to be
               deleted.

             * ‘path’ (str(77)) – if the cookie that should be deleted
               was limited to a path, the path has to be defined here.

             * ‘domain’ (‘Optional’‘[’str(78)‘]’) – if the cookie that
               should be deleted was limited to a domain, that domain
               has to be defined here.

             * ‘secure’ (bool(79)) – If ‘True’, the cookie will only be
               available via HTTPS.

             * ‘httponly’ (bool(80)) – Disallow JavaScript access to the
               cookie.

             * ‘samesite’ (‘Optional’‘[’str(81)‘]’) – Limit the scope of
               the cookie to only be attached to requests that are
               “same-site”.

          Return type: None(82)

      -- Attribute: direct_passthrough

          Pass the response body directly through as the WSGI iterable.
          This can be used when the body is a binary file or other
          iterator of bytes, to skip some unnecessary checks.  Use
          send_file() instead of setting this manually.

      -- Attribute: expires

          The Expires entity-header field gives the date/time after
          which the response is considered stale.  A stale cache entry
          may not normally be returned by a cache.

          Changed in version 2.0: The datetime object is timezone-aware.

      -- Method: classmethod force_type (response, environ=None)

          Enforce that the WSGI response is a response object of the
          current type.  Werkzeug will use the Response.
          internally in many situations like the exceptions.  If you
          call ‘get_response()’ on an exception you will get back a
          regular Response object, even if you are using a
          custom subclass.

          This method can enforce a given response type, and it will
          also convert arbitrary WSGI callables into response objects if
          an environ is provided:

               # convert a Werkzeug response object into an instance of the
               # MyResponseClass subclass.
               response = MyResponseClass.force_type(response)

               # convert any WSGI application into a response object
               response = MyResponseClass.force_type(response, environ)

          This is especially useful if you want to post-process
          responses in the main dispatcher and use functionality
          provided by your subclass.

          Keep in mind that this will modify response objects in place
          if possible!

          Parameters:

             * ‘response’ (see Response) – a response object or
               wsgi application.

             * ‘environ’ (‘Optional’‘[’‘WSGIEnvironment’‘]’) – a WSGI
               environment object.

          Returns: a response object.

          Return type: Response.

      -- Method: freeze (no_etag=None)

          Make the response object ready to be pickled.  Does the
          following:

             * Buffer the response into a list, ignoring
               ‘implicity_sequence_conversion’ and
               direct_passthrough.

             * Set the ‘Content-Length’ header.

             * Generate an ‘ETag’ header if one is not already set.

          Changed in version 2.0: An ‘ETag’ header is added, the
          ‘no_etag’ parameter is deprecated and will be removed in
          Werkzeug 2.1.

          Changed in version 0.6: The ‘Content-Length’ header is set.

          Parameters: ‘no_etag’ (None(83)) –

          Return type: None(84)

      -- Method: classmethod from_app (app, environ, buffered=False)

          Create a new response object from an application output.  This
          works best if you pass it an application that returns a
          generator all the time.  Sometimes applications may use the
          ‘write()’ callable returned by the ‘start_response’ function.
          This tries to resolve such edge cases automatically.  But if
          you don’t get the expected output you should set ‘buffered’ to
          ‘True’ which enforces buffering.

          Parameters:

             * ‘app’ (‘WSGIApplication’) – the WSGI application to
               execute.

             * ‘environ’ (‘WSGIEnvironment’) – the WSGI environment to
               execute against.

             * ‘buffered’ (bool(85)) – set to ‘True’ to enforce
               buffering.

          Returns: a response object.

          Return type: Response.

      -- Method: get_app_iter (environ)

          Returns the application iterator for the given environ.
          Depending on the request method and the current status code
          the return value might be an empty response rather than the
          one from the response.

          If the request method is ‘HEAD’ or the status code is in a
          range where the HTTP specification requires an empty response,
          an empty iterable is returned.

          New in version 0.6.

          Parameters: ‘environ’ (‘WSGIEnvironment’) – the WSGI
          environment of the request.

          Returns: a response iterable.

          Return type: Iterable[bytes(86)]

      -- Method: get_data (as_text=False)

          The string representation of the response body.  Whenever you
          call this property the response iterable is encoded and
          flattened.  This can lead to unwanted behavior if you stream
          big data.

          This behavior can be disabled by setting
          implicit_sequence_conversion to ‘False’.

          If ‘as_text’ is set to ‘True’ the return value will be a
          decoded string.

          New in version 0.9.

          Parameters: ‘as_text’ (bool(87)) –

          Return type: Union[bytes(88), str(89)]

      -- Method: get_etag ()

          Return a tuple in the form ‘(etag, is_weak)’.  If there is no
          ETag the return value is ‘(None, None)’.

          Return type: Union[Tuple[str(90), bool(91)], Tuple[None(92),
          None(93)]]

      -- Method: get_json (force=False, silent=False)

          Parse data as JSON. Useful during testing.

          If the mimetype does not indicate JSON (‘application/json’,
          see is_json), this returns ‘None’.

          Unlike Request.get_json(), the result is not cached.

          Parameters:

             * ‘force’ (bool(94)) – Ignore the mimetype and always try
               to parse JSON.

             * ‘silent’ (bool(95)) – Silence parsing errors and return
               ‘None’ instead.

          Return type: Optional[Any]

      -- Method: get_wsgi_headers (environ)

          This is automatically called right before the response is
          started and returns headers modified for the given
          environment.  It returns a copy of the headers from the
          response with some modifications applied if necessary.

          For example the location header (if present) is joined with
          the root URL of the environment.  Also the content length is
          automatically set to zero here for certain status codes.

          Changed in version 0.6: Previously that function was called
          ‘fix_headers’ and modified the response object in place.  Also
          since 0.6, IRIs in location and content-location headers are
          handled properly.

          Also starting with 0.6, Werkzeug will attempt to set the
          content length if it is able to figure it out on its own.
          This is the case if all the strings in the response iterable
          are already encoded and the iterable is buffered.

          Parameters: ‘environ’ (‘WSGIEnvironment’) – the WSGI
          environment of the request.

          Returns: returns a new Headers object.

          Return type: werkzeug.datastructures.Headers.

      -- Method: get_wsgi_response (environ)

          Returns the final WSGI response as tuple.  The first item in
          the tuple is the application iterator, the second the status
          and the third the list of headers.  The response returned is
          created specially for the given environment.  For example if
          the request method in the WSGI environment is ‘'HEAD'’ the
          response will be empty and only the headers and status code
          will be present.

          New in version 0.6.

          Parameters: ‘environ’ (‘WSGIEnvironment’) – the WSGI
          environment of the request.

          Returns: an ‘(app_iter, status, headers)’ tuple.

          Return type: Tuple[Iterable[bytes(96)], str(97),
          List[Tuple[str(98), str(99)]]]

      -- Attribute: implicit_sequence_conversion = True

          if set to ‘False’ accessing properties on the response object
          will not try to consume the response iterator and convert it
          into a list.

          New in version 0.6.2: That attribute was previously called
          ‘implicit_seqence_conversion’.  (Notice the typo).  If you did
          use this feature, you have to adapt your code to the name
          change.

      -- Property: is_json: bool(100)

          Check if the mimetype indicates JSON data, either
          ‘application/json’ or ‘application/*+json’.

      -- Property: is_sequence: bool(101)

          If the iterator is buffered, this property will be ‘True’.  A
          response object will consider an iterator to be buffered if
          the response attribute is a list or tuple.

          New in version 0.6.

      -- Property: is_streamed: bool(102)

          If the response is streamed (the response is not an iterable
          with a length information) this property is ‘True’.  In this
          case streamed means that there is no information about the
          number of iterations.  This is usually ‘True’ if a generator
          is passed to the response object.

          This is useful for checking before applying some sort of post
          filtering that should not take place for streamed responses.

      -- Method: iter_encoded ()

          Iter the response encoded with the encoding of the response.
          If the response object is invoked as WSGI application the
          return value of this method is used as application iterator
          unless direct_passthrough was activated.

          Return type: Iterator[bytes(103)]

      -- Property: json: Optional[Any]

          The parsed JSON data if mimetype indicates JSON
          (‘application/json’, see is_json).

          Calls get_json() with default arguments.

      -- Attribute: json_module = <module 'json' from
               '/usr/lib64/python3.8/json/__init__.py'>

          A module or other object that has ‘dumps’ and ‘loads’
          functions that match the API of the built-in json(104) module.

      -- Attribute: last_modified

          The Last-Modified entity-header field indicates the date and
          time at which the origin server believes the variant was last
          modified.

          Changed in version 2.0: The datetime object is timezone-aware.

      -- Attribute: location

          The Location response-header field is used to redirect the
          recipient to a location other than the Request-URI for
          completion of the request or identification of a new resource.

      -- Method: make_conditional (request_or_environ,
               accept_ranges=False, complete_length=None)

          Make the response conditional to the request.  This method
          works best if an etag was defined for the response already.
          The ‘add_etag’ method can be used to do that.  If called
          without etag just the date header is set.

          This does nothing if the request method in the request or
          environ is anything but GET or HEAD.

          For optimal performance when handling range requests, it’s
          recommended that your response data object implements
          ‘seekable’, ‘seek’ and ‘tell’ methods as described by
          io.IOBase(105).  Objects returned by wrap_file().
          automatically implement those methods.

          It does not remove the body of the response because that’s
          something the __call__() function does for us
          automatically.

          Returns self so that you can do ‘return
          resp.make_conditional(req)’ but modifies the object in-place.

          Parameters:

             * ‘request_or_environ’ (‘WSGIEnvironment’) – a request
               object or WSGI environment to be used to make the
               response conditional against.

             * ‘accept_ranges’ (‘Union’‘[’bool(106)‘, ’str(107)‘]’) –
               This parameter dictates the value of ‘Accept-Ranges’
               header.  If ‘False’ (default), the header is not set.  If
               ‘True’, it will be set to ‘"bytes"’.  If ‘None’, it will
               be set to ‘"none"’.  If it’s a string, it will use this
               value.

             * ‘complete_length’ (‘Optional’‘[’int(108)‘]’) – Will be
               used only in valid Range Requests.  It will set
               ‘Content-Range’ complete length value and compute
               ‘Content-Length’ real value.  This parameter is mandatory
               for successful Range Requests completion.

          Raises: RequestedRangeNotSatisfiable if ‘Range’
          header could not be parsed or satisfied.

          Return type: Response.

          Changed in version 2.0: Range processing is skipped if length
          is 0 instead of raising a 416 Range Not Satisfiable error.

      -- Method: make_sequence ()

          Converts the response iterator in a list.  By default this
          happens automatically if required.  If
          ‘implicit_sequence_conversion’ is disabled, this method is not
          automatically called and some properties might raise
          exceptions.  This also encodes all the items.

          New in version 0.6.

          Return type: None(109)

      -- Property: mimetype: Optional[str(110)]

          The mimetype (content type without charset etc.)

      -- Property: mimetype_params: Dict[str(111), str(112)]

          The mimetype parameters as dict.  For example if the content
          type is ‘text/html; charset=utf-8’ the params would be
          ‘{'charset': 'utf-8'}’.

          New in version 0.5.

      -- Attribute: response: Union[Iterable[str(113)],
               Iterable[bytes(114)]]

          The response body to send as the WSGI iterable.  A list of
          strings or bytes represents a fixed-length response, any other
          iterable is a streaming response.  Strings are encoded to
          bytes as UTF-8.

          Do not set to a plain string or bytes, that will cause sending
          the response to be very inefficient as it will iterate one
          byte at a time.

      -- Property: retry_after: Optional[datetime.datetime(115)]

          The Retry-After response-header field can be used with a 503
          (Service Unavailable) response to indicate how long the
          service is expected to be unavailable to the requesting
          client.

          Time in seconds until expiration or date.

          Changed in version 2.0: The datetime object is timezone-aware.

      -- Method: set_cookie (key, value='', max_age=None, expires=None,
               path='/', domain=None, secure=False, httponly=False,
               samesite=None)

          Sets a cookie.

          A warning is raised if the size of the cookie header exceeds
          ‘max_cookie_size’, but the header will still be set.

          Parameters:

             * ‘key’ (str(116)) – the key (name) of the cookie to be
               set.

             * ‘value’ (str(117)) – the value of the cookie.

             * ‘max_age’
               (‘Optional’‘[’‘Union’‘[’datetime.timedelta(118)‘,
               ’int(119)‘]’‘]’) – should be a number of seconds, or
               ‘None’ (default) if the cookie should last only as long
               as the client’s browser session.

             * ‘expires’ (‘Optional’‘[’‘Union’‘[’str(120)‘,
               ’datetime.datetime(121)‘, ’int(122)‘, ’float(123)‘]’‘]’)
               – should be a ‘datetime’ object or UNIX timestamp.

             * ‘path’ (‘Optional’‘[’str(124)‘]’) – limits the cookie to
               a given path, per default it will span the whole domain.

             * ‘domain’ (‘Optional’‘[’str(125)‘]’) – if you want to set
               a cross-domain cookie.  For example,
               ‘domain=".example.com"’ will set a cookie that is
               readable by the domain ‘www.example.com’,
               ‘foo.example.com’ etc.  Otherwise, a cookie will only be
               readable by the domain that set it.

             * ‘secure’ (bool(126)) – If ‘True’, the cookie will only be
               available via HTTPS.

             * ‘httponly’ (bool(127)) – Disallow JavaScript access to
               the cookie.

             * ‘samesite’ (‘Optional’‘[’str(128)‘]’) – Limit the scope
               of the cookie to only be attached to requests that are
               “same-site”.

          Return type: None(129)

      -- Method: set_data (value)

          Sets a new string as response.  The value must be a string or
          bytes.  If a string is set it’s encoded to the charset of the
          response (utf-8 by default).

          New in version 0.9.

          Parameters: ‘value’ (‘Union’‘[’bytes(130)‘, ’str(131)‘]’) –

          Return type: None(132)

      -- Method: set_etag (etag, weak=False)

          Set the etag, and override the old one if there was one.

          Parameters:

             * ‘etag’ (str(133)) –

             * ‘weak’ (bool(134)) –

          Return type: None(135)

      -- Property: status: str(136)

          The HTTP status code as a string.

      -- Property: status_code: int(137)

          The HTTP status code as a number.

      -- Property: stream: werkzeug.wrappers.response.ResponseStream

          The response iterable as write-only stream.

      -- Property: vary: werkzeug.datastructures.HeaderSet.

          The Vary field value indicates the set of request-header
          fields that fully determines, while the response is fresh,
          whether a cache is permitted to use the response to reply to a
          subsequent request without revalidation.

      -- Property: www_authenticate:
               werkzeug.datastructures.WWWAuthenticate.

          The ‘WWW-Authenticate’ header in a parsed form.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/functions.html#bool

   (2) https://docs.python.org/3/library/functions.html#bool

   (3) https://docs.python.org/3/library/exceptions.html#RuntimeError

   (4) https://docs.python.org/3/library/constants.html#None

   (5) https://docs.python.org/3/library/functions.html#int

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/functions.html#int

   (9) https://docs.python.org/3/library/stdtypes.html#bytes

   (10) https://docs.python.org/3/library/stdtypes.html#str

   (11) https://docs.python.org/3/library/stdtypes.html#str

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/stdtypes.html#str

   (14) https://docs.python.org/3/library/constants.html#None

   (15) https://docs.python.org/3/library/functions.html#int

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/stdtypes.html#str

   (18) https://docs.python.org/3/library/stdtypes.html#dict

   (19) https://docs.python.org/3/library/stdtypes.html#bytes

   (20) https://docs.python.org/3/library/functions.html#bool

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23) https://docs.python.org/3/library/stdtypes.html#str

   (24) https://docs.python.org/3/library/stdtypes.html#str

   (25) https://docs.python.org/3/library/functions.html#bool

   (26) https://docs.python.org/3/library/functions.html#bool

   (27) https://docs.python.org/3/library/functions.html#bool

   (28) https://docs.python.org/3/library/stdtypes.html#bytes

   (29) https://docs.python.org/3/library/stdtypes.html#str

   (30) https://docs.python.org/3/library/functions.html#bool

   (31) https://docs.python.org/3/library/functions.html#bool

   (32) https://docs.python.org/3/library/functions.html#bool

   (33) https://docs.python.org/3/library/stdtypes.html#str

   (34) https://docs.python.org/3/library/stdtypes.html#str

   (35)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (36)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (37) https://docs.python.org/3/library/functions.html#bool

   (38) https://docs.python.org/3/library/functions.html#bool

   (39) https://docs.python.org/3/library/json.html#module-json

   (40) https://docs.python.org/3/library/functions.html#int

   (41) https://docs.python.org/3/library/functions.html#int

   (42) https://docs.python.org/3/library/stdtypes.html#str

   (43) https://docs.python.org/3/library/stdtypes.html#str

   (44) https://docs.python.org/3/library/stdtypes.html#str

   (45) https://docs.python.org/3/library/exceptions.html#ValueError

   (46) https://docs.python.org/3/library/stdtypes.html#str

   (47) https://docs.python.org/3/library/stdtypes.html#str

   (48) https://docs.python.org/3/library/functions.html#bool

   (49) https://docs.python.org/3/library/stdtypes.html#bytes

   (50) https://docs.python.org/3/library/stdtypes.html#str

   (51) https://docs.python.org/3/library/stdtypes.html#str

   (52) https://docs.python.org/3/library/stdtypes.html#str

   (53) https://docs.python.org/3/library/stdtypes.html#str

   (54) https://docs.python.org/3/library/stdtypes.html#str

   (55) https://docs.python.org/3/library/functions.html#bool

   (56) https://docs.python.org/3/library/stdtypes.html#str

   (57) https://docs.python.org/3/library/stdtypes.html#bytes

   (58) https://docs.python.org/3/library/functions.html#int

   (59) https://docs.python.org/3/library/stdtypes.html#str

   (60) https://docs.python.org/3/library/http.html#http.HTTPStatus

   (61) https://docs.python.org/3/library/stdtypes.html#str

   (62) https://docs.python.org/3/library/stdtypes.html#str

   (63) https://docs.python.org/3/library/functions.html#bool

   (64) https://docs.python.org/3/library/constants.html#None

   (65) https://docs.python.org/3/library/stdtypes.html#bytes

   (66) https://docs.python.org/3/library/functions.html#bool

   (67) https://docs.python.org/3/library/constants.html#None

   (68) https://docs.python.org/3/library/functions.html#bool

   (69) https://docs.python.org/3/library/functions.html#bool

   (70) https://docs.python.org/3/library/functions.html#bool

   (71) https://docs.python.org/3/library/constants.html#None

   (72) https://docs.python.org/3/library/functions.html#int

   (73) https://docs.python.org/3/library/constants.html#None

   (74) https://docs.python.org/3/library/stdtypes.html#bytes

   (75) https://docs.python.org/3/library/stdtypes.html#str

   (76) https://docs.python.org/3/library/stdtypes.html#str

   (77) https://docs.python.org/3/library/stdtypes.html#str

   (78) https://docs.python.org/3/library/stdtypes.html#str

   (79) https://docs.python.org/3/library/functions.html#bool

   (80) https://docs.python.org/3/library/functions.html#bool

   (81) https://docs.python.org/3/library/stdtypes.html#str

   (82) https://docs.python.org/3/library/constants.html#None

   (83) https://docs.python.org/3/library/constants.html#None

   (84) https://docs.python.org/3/library/constants.html#None

   (85) https://docs.python.org/3/library/functions.html#bool

   (86) https://docs.python.org/3/library/stdtypes.html#bytes

   (87) https://docs.python.org/3/library/functions.html#bool

   (88) https://docs.python.org/3/library/stdtypes.html#bytes

   (89) https://docs.python.org/3/library/stdtypes.html#str

   (90) https://docs.python.org/3/library/stdtypes.html#str

   (91) https://docs.python.org/3/library/functions.html#bool

   (92) https://docs.python.org/3/library/constants.html#None

   (93) https://docs.python.org/3/library/constants.html#None

   (94) https://docs.python.org/3/library/functions.html#bool

   (95) https://docs.python.org/3/library/functions.html#bool

   (96) https://docs.python.org/3/library/stdtypes.html#bytes

   (97) https://docs.python.org/3/library/stdtypes.html#str

   (98) https://docs.python.org/3/library/stdtypes.html#str

   (99) https://docs.python.org/3/library/stdtypes.html#str

   (100) https://docs.python.org/3/library/functions.html#bool

   (101) https://docs.python.org/3/library/functions.html#bool

   (102) https://docs.python.org/3/library/functions.html#bool

   (103) https://docs.python.org/3/library/stdtypes.html#bytes

   (104) https://docs.python.org/3/library/json.html#module-json

   (105) https://docs.python.org/3/library/io.html#io.IOBase

   (106) https://docs.python.org/3/library/functions.html#bool

   (107) https://docs.python.org/3/library/stdtypes.html#str

   (108) https://docs.python.org/3/library/functions.html#int

   (109) https://docs.python.org/3/library/constants.html#None

   (110) https://docs.python.org/3/library/stdtypes.html#str

   (111) https://docs.python.org/3/library/stdtypes.html#str

   (112) https://docs.python.org/3/library/stdtypes.html#str

   (113) https://docs.python.org/3/library/stdtypes.html#str

   (114) https://docs.python.org/3/library/stdtypes.html#bytes

   (115)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (116) https://docs.python.org/3/library/stdtypes.html#str

   (117) https://docs.python.org/3/library/stdtypes.html#str

   (118)
https://docs.python.org/3/library/datetime.html#datetime.timedelta

   (119) https://docs.python.org/3/library/functions.html#int

   (120) https://docs.python.org/3/library/stdtypes.html#str

   (121)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (122) https://docs.python.org/3/library/functions.html#int

   (123) https://docs.python.org/3/library/functions.html#float

   (124) https://docs.python.org/3/library/stdtypes.html#str

   (125) https://docs.python.org/3/library/stdtypes.html#str

   (126) https://docs.python.org/3/library/functions.html#bool

   (127) https://docs.python.org/3/library/functions.html#bool

   (128) https://docs.python.org/3/library/stdtypes.html#str

   (129) https://docs.python.org/3/library/constants.html#None

   (130) https://docs.python.org/3/library/stdtypes.html#bytes

   (131) https://docs.python.org/3/library/stdtypes.html#str

   (132) https://docs.python.org/3/library/constants.html#None

   (133) https://docs.python.org/3/library/stdtypes.html#str

   (134) https://docs.python.org/3/library/functions.html#bool

   (135) https://docs.python.org/3/library/constants.html#None

   (136) https://docs.python.org/3/library/stdtypes.html#str

   (137) https://docs.python.org/3/library/functions.html#int

3.2 URL Routing
===============

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(1).
All the objects mentioned on this page must be imported from
werkzeug.routing, not from ‘werkzeug’!

   ---------- Footnotes ----------

   (1) https://routes.readthedocs.io/en/latest/

3.2.1 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 [f'Rule points to {endpoint!r} with arguments {args!r}']

So what does that do?  First of all we create a new Map which
stores a bunch of URL rules.  Then we pass it a list of Rule.
objects.

Each 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 MapAdapter.  This url_map adapter can
then be used to match or build domains for the current request.

The MapAdapter.match() method can then either return a tuple
in the form ‘(endpoint, args)’ or raise one of the three exceptions
NotFound, MethodNotAllowed, or ‘RequestRedirect’.
For more details about those exceptions have a look at the documentation
of the MapAdapter.match() method.

3.2.2 Rule Format
-----------------

Rule strings are URL paths with placeholders for variable parts in the
format ‘<converter(arguments):name>’.  ‘converter’ and ‘arguments’ (with
parentheses) are optional.  If no converter is given, the ‘default’
converter is used (‘string’ by default).  The available converters are
discussed below.

Rules that end with a slash are “branches”, others are “leaves”.  If
‘strict_slashes’ is enabled (the default), visiting a branch URL without
a trailing slash will redirect to the URL with a slash appended.

Many HTTP servers merge consecutive slashes into one when receiving
requests.  If ‘merge_slashes’ is enabled (the default), rules will merge
slashes in non-variable parts when matching and building.  Visiting a
URL with consecutive slashes will redirect to the URL with slashes
merged.  If you want to disable ‘merge_slashes’ for a Rule or
Map, you’ll also need to configure your web server
appropriately.

3.2.3 Built-in Converters
-------------------------

Converters for common types of URL variables are built-in.  The
available converters can be overridden or extended through
Map.converters.

 -- Class: werkzeug.routing.UnicodeConverter (map, minlength=1,
          maxlength=None, length=None)

     This converter is the default converter and accepts any string but
     only one path segment.  Thus the string can not include a slash.

     This is the default validator.

     Example:

          Rule('/pages/<page>'),
          Rule('/<string(length=2):lang_code>')

     Parameters:

        * ‘map’ (see Map) – the Map.

        * ‘minlength’ (int(1)) – the minimum length of the string.  Must
          be greater or equal 1.

        * ‘maxlength’ (‘Optional’‘[’int(2)‘]’) – the maximum length of
          the string.

        * ‘length’ (‘Optional’‘[’int(3)‘]’) – the exact length of the
          string.

     Return type: None(4)

 -- Class: werkzeug.routing.PathConverter (map, *args, **kwargs)

     Like the default UnicodeConverter, but it also matches
     slashes.  This is useful for wikis and similar applications:

          Rule('/<path:wikipage>')
          Rule('/<path:wikipage>/edit')

     Parameters:

        * ‘map’ (see Map) – the Map.

        * ‘args’ (‘Any’) –

        * ‘kwargs’ (‘Any’) –

     Return type: None(5)

 -- Class: werkzeug.routing.AnyConverter (map, *items)

     Matches one of the items provided.  Items can either be Python
     identifiers or strings:

          Rule('/<any(about, help, imprint, class, "foo,bar"):page_name>')

     Parameters:

        * ‘map’ (see Map) – the Map.

        * ‘items’ (str(6)) – this function accepts the possible items as
          positional arguments.

     Return type: None(7)

 -- Class: werkzeug.routing.IntegerConverter (map, fixed_digits=0,
          min=None, max=None, signed=False)

     This converter only accepts integer values:

          Rule("/page/<int:page>")

     By default it only accepts unsigned, positive values.  The ‘signed’
     parameter will enable signed, negative values.

          Rule("/page/<int(signed=True):page>")

     Parameters:

        * ‘map’ (see Map) – The Map.

        * ‘fixed_digits’ (int(8)) – The number of fixed digits in the
          URL. If you set this to ‘4’ for example, the rule will only
          match if the URL looks like ‘/0001/’.  The default is variable
          length.

        * ‘min’ (‘Optional’‘[’int(9)‘]’) – The minimal value.

        * ‘max’ (‘Optional’‘[’int(10)‘]’) – The maximal value.

        * ‘signed’ (bool(11)) – Allow signed (negative) values.

     Return type: None(12)

     New in version 0.15: The ‘signed’ parameter.

 -- Class: werkzeug.routing.FloatConverter (map, min=None, max=None,
          signed=False)

     This converter only accepts floating point values:

          Rule("/probability/<float:probability>")

     By default it only accepts unsigned, positive values.  The ‘signed’
     parameter will enable signed, negative values.

          Rule("/offset/<float(signed=True):offset>")

     Parameters:

        * ‘map’ (see Map) – The Map.

        * ‘min’ (‘Optional’‘[’float(13)‘]’) – The minimal value.

        * ‘max’ (‘Optional’‘[’float(14)‘]’) – The maximal value.

        * ‘signed’ (bool(15)) – Allow signed (negative) values.

     Return type: None(16)

     New in version 0.15: The ‘signed’ parameter.

 -- Class: werkzeug.routing.UUIDConverter (map, *args, **kwargs)

     This converter only accepts UUID strings:

          Rule('/object/<uuid:identifier>')

     New in version 0.10.

     Parameters:

        * ‘map’ (see Map) – the Map.

        * ‘args’ (‘Any’) –

        * ‘kwargs’ (‘Any’) –

     Return type: None(17)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/functions.html#int

   (2) https://docs.python.org/3/library/functions.html#int

   (3) https://docs.python.org/3/library/functions.html#int

   (4) https://docs.python.org/3/library/constants.html#None

   (5) https://docs.python.org/3/library/constants.html#None

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/constants.html#None

   (8) https://docs.python.org/3/library/functions.html#int

   (9) https://docs.python.org/3/library/functions.html#int

   (10) https://docs.python.org/3/library/functions.html#int

   (11) https://docs.python.org/3/library/functions.html#bool

   (12) https://docs.python.org/3/library/constants.html#None

   (13) https://docs.python.org/3/library/functions.html#float

   (14) https://docs.python.org/3/library/functions.html#float

   (15) https://docs.python.org/3/library/functions.html#bool

   (16) https://docs.python.org/3/library/constants.html#None

   (17) https://docs.python.org/3/library/constants.html#None

3.2.4 Maps, Rules and Adapters
------------------------------

 -- Class: werkzeug.routing.Map (rules=None, default_subdomain='',
          charset='utf-8', strict_slashes=True, merge_slashes=True,
          redirect_defaults=True, converters=None,
          sort_parameters=False, sort_key=None,
          encoding_errors='replace', host_matching=False)

     The map class stores all the URL rules and some configuration
     parameters.  Some of the configuration values are only stored on
     the ‘Map’ instance since those affect all rules, others are just
     defaults and can be overridden for each rule.  Note that you have
     to specify all arguments besides the ‘rules’ as keyword arguments!

     Parameters:

        * ‘rules’ (‘Optional’‘[’‘Iterable’‘[’
          werkzeug.routing.RuleFactory.‘]’‘]’) – sequence of url
          rules for this map.

        * ‘default_subdomain’ (str(1)) – The default subdomain for rules
          without a subdomain defined.

        * ‘charset’ (str(2)) – charset of the url.  defaults to
          ‘"utf-8"’

        * ‘strict_slashes’ (bool(3)) – If a rule ends with a slash but
          the matched URL does not, redirect to the URL with a trailing
          slash.

        * ‘merge_slashes’ (bool(4)) – Merge consecutive slashes when
          matching or building URLs.  Matches will redirect to the
          normalized URL. Slashes in variable parts are not merged.

        * ‘redirect_defaults’ (bool(5)) – This will redirect to the
          default rule if it wasn’t visited that way.  This helps
          creating unique URLs.

        * ‘converters’ (‘Optional’‘[’‘Mapping’‘[’str(6)‘,
          ’‘Type’‘[’‘werkzeug.routing.BaseConverter’‘]’‘]’‘]’) – A dict
          of converters that adds additional converters to the list of
          converters.  If you redefine one converter this will override
          the original one.

        * ‘sort_parameters’ (bool(7)) – If set to ‘True’ the url
          parameters are sorted.  See ‘url_encode’ for more details.

        * ‘sort_key’ (‘Optional’‘[’‘Callable’‘[’‘[’‘Any’‘]’‘,
          ’‘Any’‘]’‘]’) – The sort key function for ‘url_encode’.

        * ‘encoding_errors’ (str(8)) – the error method to use for
          decoding

        * ‘host_matching’ (bool(9)) – if set to ‘True’ it enables the
          host matching feature and disables the subdomain one.  If
          enabled the ‘host’ parameter to rules is used instead of the
          ‘subdomain’ one.

     Return type: None(10)

     Changed in version 1.0: If ‘url_scheme’ is ‘ws’ or ‘wss’, only
     WebSocket rules will match.

     Changed in version 1.0: Added ‘merge_slashes’.

     Changed in version 0.7: Added ‘encoding_errors’ and
     ‘host_matching’.

     Changed in version 0.5: Added ‘sort_parameters’ and ‘sort_key’.

      -- 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.

      -- Method: add (rulefactory)

          Add a new rule or factory to the map and bind it.  Requires
          that the rule is not bound to another map.

          Parameters: ‘rulefactory’ (see werkzeug.routing.RuleFactory)
          – a Rule or RuleFactory.

          Return type: None(11)

      -- Method: bind (server_name, script_name=None, subdomain=None,
               url_scheme='http', default_method='GET', path_info=None,
               query_args=None)

          Return a new MapAdapter with the details specified
          to the call.  Note that ‘script_name’ will default to ‘'/'’ if
          not further specified or ‘None’.  The ‘server_name’ at least
          is a requirement because the HTTP RFC requires absolute URLs
          for redirects and so all redirect exceptions raised by
          Werkzeug will contain the full canonical URL.

          If no path_info is passed to ‘match()’ it will use the default
          path info passed to bind.  While this doesn’t really make
          sense for manual bind calls, it’s useful if you bind a map to
          a WSGI environment which already contains the path info.

          ‘subdomain’ will default to the ‘default_subdomain’ for this
          map if no defined.  If there is no ‘default_subdomain’ you
          cannot use the subdomain feature.

          Changed in version 1.0: If ‘url_scheme’ is ‘ws’ or ‘wss’, only
          WebSocket rules will match.

          Changed in version 0.15: ‘path_info’ defaults to ‘'/'’ if
          ‘None’.

          Changed in version 0.8: ‘query_args’ can be a string.

          Changed in version 0.7: Added ‘query_args’.

          Parameters:

             * ‘server_name’ (str(12)) –

             * ‘script_name’ (‘Optional’‘[’str(13)‘]’) –

             * ‘subdomain’ (‘Optional’‘[’str(14)‘]’) –

             * ‘url_scheme’ (str(15)) –

             * ‘default_method’ (str(16)) –

             * ‘path_info’ (‘Optional’‘[’str(17)‘]’) –

             * ‘query_args’
               (‘Optional’‘[’‘Union’‘[’‘Mapping’‘[’str(18)‘, ’‘Any’‘]’‘,
               ’str(19)‘]’‘]’) –

          Return type: werkzeug.routing.MapAdapter.

      -- Method: bind_to_environ (environ, server_name=None,
               subdomain=None)

          Like bind() but you can pass it an WSGI
          environment and it will fetch the information from that
          dictionary.  Note that because of limitations in the protocol
          there is no way to get the current subdomain and real
          ‘server_name’ from the environment.  If you don’t provide it,
          Werkzeug will use ‘SERVER_NAME’ and ‘SERVER_PORT’ (or
          ‘HTTP_HOST’ if provided) as used ‘server_name’ with disabled
          subdomain feature.

          If ‘subdomain’ is ‘None’ but an environment and a server name
          is provided it will calculate the current subdomain
          automatically.  Example: ‘server_name’ is ‘'example.com'’ and
          the ‘SERVER_NAME’ in the wsgi ‘environ’ is
          ‘'staging.dev.example.com'’ the calculated subdomain will be
          ‘'staging.dev'’.

          If the object passed as environ has an environ attribute, the
          value of this attribute is used instead.  This allows you to
          pass request objects.  Additionally ‘PATH_INFO’ added as a
          default of the MapAdapter so that you don’t have
          to pass the path info to the match method.

          Changed in version 1.0.0: If the passed server name specifies
          port 443, it will match if the incoming scheme is ‘https’
          without a port.

          Changed in version 1.0.0: A warning is shown when the passed
          server name does not match the incoming WSGI server name.

          Changed in version 0.8: This will no longer raise a ValueError
          when an unexpected server name was passed.

          Changed in version 0.5: previously this method accepted a
          bogus ‘calculate_subdomain’ parameter that did not have any
          effect.  It was removed because of that.

          Parameters:

             * ‘environ’ (‘WSGIEnvironment’) – a WSGI environment.

             * ‘server_name’ (‘Optional’‘[’str(20)‘]’) – an optional
               server name hint (see above).

             * ‘subdomain’ (‘Optional’‘[’str(21)‘]’) – optionally the
               current subdomain (see above).

          Return type: MapAdapter.

      -- Attribute: default_converters = {'any': <class
               'werkzeug.routing.AnyConverter'>, 'default': <class
               'werkzeug.routing.UnicodeConverter'>, 'float': <class
               'werkzeug.routing.FloatConverter'>, 'int': <class
               'werkzeug.routing.IntegerConverter'>, 'path': <class
               'werkzeug.routing.PathConverter'>, 'string': <class
               'werkzeug.routing.UnicodeConverter'>, 'uuid': <class
               'werkzeug.routing.UUIDConverter'>}

          A dict of default converters to be used.

      -- Method: is_endpoint_expecting (endpoint, *arguments)

          Iterate over all rules and check if the endpoint expects the
          arguments provided.  This is for example useful if you have
          some URLs that expect a language code and others that do not
          and you want to wrap the builder a bit so that the current
          language code is automatically added if not provided but
          endpoints expect it.

          Parameters:

             * ‘endpoint’ (str(22)) – the endpoint to check.

             * ‘arguments’ (str(23)) – this function accepts one or more
               arguments as positional arguments.  Each one of them is
               checked.

          Return type: bool(24)

      -- Method: iter_rules (endpoint=None)

          Iterate over all rules or the rules of an endpoint.

          Parameters: ‘endpoint’ (‘Optional’‘[’str(25)‘]’) – if provided
          only the rules for that endpoint are returned.

          Returns: an iterator

          Return type: Iterator[see werkzeug.routing.Rule]

      -- Method: lock_class ()

          The type of lock to use when updating.

          New in version 1.0.

      -- Method: update ()

          Called before matching and building to keep the compiled rules
          in the correct order after things changed.

          Return type: None(26)

 -- Class: werkzeug.routing.MapAdapter (map, server_name, script_name,
          subdomain, url_scheme, path_info, default_method,
          query_args=None)

     Returned by Map.bind() or Map.bind_to_environ()
     and does the URL matching and building based on runtime
     information.

     Parameters:

        * ‘map’ (see werkzeug.routing.Map) –

        * ‘server_name’ (str(27)) –

        * ‘script_name’ (str(28)) –

        * ‘subdomain’ (‘Optional’‘[’str(29)‘]’) –

        * ‘url_scheme’ (str(30)) –

        * ‘path_info’ (str(31)) –

        * ‘default_method’ (str(32)) –

        * ‘query_args’ (‘Optional’‘[’‘Union’‘[’‘Mapping’‘[’str(33)‘,
          ’‘Any’‘]’‘, ’str(34)‘]’‘]’) –

      -- Method: allowed_methods (path_info=None)

          Returns the valid methods that match for a given path.

          New in version 0.7.

          Parameters: ‘path_info’ (‘Optional’‘[’str(35)‘]’) –

          Return type: Iterable[str(36)]

      -- Method: build (endpoint, values=None, method=None,
               force_external=False, append_unknown=True,
               url_scheme=None)

          Building URLs works pretty much the other way round.  Instead
          of ‘match’ you call ‘build’ and pass it the endpoint and a
          dict of arguments for the placeholders.

          The ‘build’ function also accepts an argument called
          ‘force_external’ which, if you set it to ‘True’ will force
          external URLs.  Per default external URLs (include the server
          name) will only be used if the target URL is on a different
          subdomain.

               >>> m = Map([
               ...     Rule('/', endpoint='index'),
               ...     Rule('/downloads/', endpoint='downloads/index'),
               ...     Rule('/downloads/<int:id>', endpoint='downloads/show')
               ... ])
               >>> urls = m.bind("example.com", "/")
               >>> urls.build("index", {})
               '/'
               >>> urls.build("downloads/show", {'id': 42})
               '/downloads/42'
               >>> urls.build("downloads/show", {'id': 42}, force_external=True)
               'http://example.com/downloads/42'

          Because URLs cannot contain non ASCII data you will always get
          bytes back.  Non ASCII characters are urlencoded with the
          charset defined on the map instance.

          Additional values are converted to strings and appended to the
          URL as URL querystring parameters:

               >>> urls.build("index", {'q': 'My Searchstring'})
               '/?q=My+Searchstring'

          When processing those additional values, lists are furthermore
          interpreted as multiple values (as per
          werkzeug.datastructures.MultiDict):

               >>> urls.build("index", {'q': ['a', 'b', 'c']})
               '/?q=a&q=b&q=c'

          Passing a ‘MultiDict’ will also add multiple values:

               >>> urls.build("index", MultiDict((('p', 'z'), ('q', 'a'), ('q', 'b'))))
               '/?p=z&q=a&q=b'

          If a rule does not exist when building a ‘BuildError’
          exception is raised.

          The build method accepts an argument called ‘method’ which
          allows you to specify the method you want to have an URL built
          for if you have different methods for the same endpoint
          specified.

          Parameters:

             * ‘endpoint’ (str(37)) – the endpoint of the URL to build.

             * ‘values’ (‘Optional’‘[’‘Mapping’‘[’str(38)‘,
               ’‘Any’‘]’‘]’) – the values for the URL to build.
               Unhandled values are appended to the URL as query
               parameters.

             * ‘method’ (‘Optional’‘[’str(39)‘]’) – the HTTP method for
               the rule if there are different URLs for different
               methods on the same endpoint.

             * ‘force_external’ (bool(40)) – enforce full canonical
               external URLs.  If the URL scheme is not provided, this
               will generate a protocol-relative URL.

             * ‘append_unknown’ (bool(41)) – unknown parameters are
               appended to the generated URL as query string argument.
               Disable this if you want the builder to ignore those.

             * ‘url_scheme’ (‘Optional’‘[’str(42)‘]’) – Scheme to use in
               place of the bound ‘url_scheme’.

          Return type: str(43)

          Changed in version 2.0: Added the ‘url_scheme’ parameter.

          New in version 0.6: Added the ‘append_unknown’ parameter.

      -- Method: dispatch (view_func, path_info=None, method=None,
               catch_http_exceptions=False)

          Does the complete dispatching process.  ‘view_func’ is called
          with the endpoint and a dict with the values for the view.  It
          should look up the view function, call it, and return a
          response object or WSGI application.  http exceptions are not
          caught by default so that applications can display nicer error
          messages by just catching them by hand.  If you want to stick
          with the default error messages you can pass it
          ‘catch_http_exceptions=True’ and it will catch the http
          exceptions.

          Here a small example for the dispatch usage:

               from werkzeug.wrappers import Request, Response
               from werkzeug.wsgi import responder
               from werkzeug.routing import Map, Rule

               def on_index(request):
                   return Response('Hello from the index')

               url_map = Map([Rule('/', endpoint='index')])
               views = {'index': on_index}

               @responder
               def application(environ, start_response):
                   request = Request(environ)
                   urls = url_map.bind_to_environ(environ)
                   return urls.dispatch(lambda e, v: views[e](request, **v),
                                        catch_http_exceptions=True)

          Keep in mind that this method might return exception objects,
          too, so use ‘Response.force_type’ to get a response object.

          Parameters:

             * ‘view_func’ (‘Callable’‘[’‘[’str(44)‘,
               ’‘Mapping’‘[’str(45)‘, ’‘Any’‘]’‘]’‘,
               ’‘WSGIApplication’‘]’) – a function that is called with
               the endpoint as first argument and the value dict as
               second.  Has to dispatch to the actual view function with
               this information.  (see above)

             * ‘path_info’ (‘Optional’‘[’str(46)‘]’) – the path info to
               use for matching.  Overrides the path info specified on
               binding.

             * ‘method’ (‘Optional’‘[’str(47)‘]’) – the HTTP method used
               for matching.  Overrides the method specified on binding.

             * ‘catch_http_exceptions’ (bool(48)) – set to ‘True’ to
               catch any of the werkzeug ‘HTTPException’s.

          Return type: WSGIApplication

      -- Method: get_host (domain_part)

          Figures out the full host name for the given domain part.  The
          domain part is a subdomain in case host matching is disabled
          or a full host name.

          Parameters: ‘domain_part’ (‘Optional’‘[’str(49)‘]’) –

          Return type: str(50)

      -- Method: make_alias_redirect_url (path, endpoint, values,
               method, query_args)

          Internally called to make an alias redirect URL.

          Parameters:

             * ‘path’ (str(51)) –

             * ‘endpoint’ (str(52)) –

             * ‘values’ (‘Mapping’‘[’str(53)‘, ’‘Any’‘]’) –

             * ‘method’ (str(54)) –

             * ‘query_args’ (‘Union’‘[’‘Mapping’‘[’str(55)‘, ’‘Any’‘]’‘,
               ’str(56)‘]’) –

          Return type: str(57)

      -- Method: match (path_info=None, method=None, return_rule=False,
               query_args=None, websocket=None)

          The usage is simple: you just pass the match method the
          current path info as well as the method (which defaults to
          ‘GET’). The following things can then happen:

             - you receive a ‘NotFound’ exception that indicates that no
               URL is matching.  A ‘NotFound’ exception is also a WSGI
               application you can call to get a default page not found
               page (happens to be the same object as
               ‘werkzeug.exceptions.NotFound’)

             - you receive a ‘MethodNotAllowed’ exception that indicates
               that there is a match for this URL but not for the
               current request method.  This is useful for RESTful
               applications.

             - you receive a ‘RequestRedirect’ exception with a
               ‘new_url’ attribute.  This exception is used to notify
               you about a request Werkzeug requests from your WSGI
               application.  This is for example the case if you request
               ‘/foo’ although the correct URL is ‘/foo/’ You can use
               the ‘RequestRedirect’ instance as response-like object
               similar to all other subclasses of ‘HTTPException’.

             - you receive a ‘WebsocketMismatch’ exception if the only
               match is a WebSocket rule but the bind is an HTTP
               request, or if the match is an HTTP rule but the bind is
               a WebSocket request.

             - you get a tuple in the form ‘(endpoint, arguments)’ if
               there is a match (unless ‘return_rule’ is True, in which
               case you get a tuple in the form ‘(rule, arguments)’)

          If the path info is not passed to the match method the default
          path info of the map is used (defaults to the root URL if not
          defined explicitly).

          All of the exceptions raised are subclasses of ‘HTTPException’
          so they can be used as WSGI responses.  They will all render
          generic error or redirect pages.

          Here is a small example for matching:

               >>> m = Map([
               ...     Rule('/', endpoint='index'),
               ...     Rule('/downloads/', endpoint='downloads/index'),
               ...     Rule('/downloads/<int:id>', endpoint='downloads/show')
               ... ])
               >>> urls = m.bind("example.com", "/")
               >>> urls.match("/", "GET")
               ('index', {})
               >>> urls.match("/downloads/42")
               ('downloads/show', {'id': 42})

          And here is what happens on redirect and missing URLs:

               >>> urls.match("/downloads")
               Traceback (most recent call last):
                 ...
               RequestRedirect: http://example.com/downloads/
               >>> urls.match("/missing")
               Traceback (most recent call last):
                 ...
               NotFound: 404 Not Found

          Parameters:

             * ‘path_info’ (‘Optional’‘[’str(58)‘]’) – the path info to
               use for matching.  Overrides the path info specified on
               binding.

             * ‘method’ (‘Optional’‘[’str(59)‘]’) – the HTTP method used
               for matching.  Overrides the method specified on binding.

             * ‘return_rule’ (bool(60)) – return the rule that matched
               instead of just the endpoint (defaults to ‘False’).

             * ‘query_args’
               (‘Optional’‘[’‘Union’‘[’‘Mapping’‘[’str(61)‘, ’‘Any’‘]’‘,
               ’str(62)‘]’‘]’) – optional query arguments that are used
               for automatic redirects as string or dictionary.  It’s
               currently not possible to use the query arguments for URL
               matching.

             * ‘websocket’ (‘Optional’‘[’bool(63)‘]’) – Match WebSocket
               instead of HTTP requests.  A websocket request has a ‘ws’
               or ‘wss’ ‘url_scheme’.  This overrides that detection.

          Return type: Tuple[Union[str(64), see werkzeug.routing.Rule],
          Mapping[str(65), Any]]

          New in version 1.0: Added ‘websocket’.

          Changed in version 0.8: ‘query_args’ can be a string.

          New in version 0.7: Added ‘query_args’.

          New in version 0.6: Added ‘return_rule’.

      -- Method: test (path_info=None, method=None)

          Test if a rule would match.  Works like ‘match’ but returns
          ‘True’ if the URL matches, or ‘False’ if it does not exist.

          Parameters:

             * ‘path_info’ (‘Optional’‘[’str(66)‘]’) – the path info to
               use for matching.  Overrides the path info specified on
               binding.

             * ‘method’ (‘Optional’‘[’str(67)‘]’) – the HTTP method used
               for matching.  Overrides the method specified on binding.

          Return type: bool(68)

 -- Class: werkzeug.routing.Rule (string, defaults=None, subdomain=None,
          methods=None, build_only=False, endpoint=None,
          strict_slashes=None, merge_slashes=None, redirect_to=None,
          alias=False, host=None, websocket=False)

     A Rule represents one URL pattern.  There are some options for
     ‘Rule’ that change the way it behaves and are passed to the ‘Rule’
     constructor.  Note that besides the rule-string all arguments
     `must' be keyword arguments in order to not break the application
     on Werkzeug upgrades.

     ‘string’

          Rule strings basically are just normal URL paths with
          placeholders in the format ‘<converter(arguments):name>’ where
          the 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 matched without a trailing
          slash will trigger a redirect to the same URL with the missing
          slash appended.

          The converters are defined on the ‘Map’.

     ‘endpoint’

          The endpoint for this rule.  This can be anything.  A
          reference to a function, a string, a number etc.  The
          preferred way is using a string because the endpoint is used
          for URL generation.

     ‘defaults’

          An optional dict with defaults for other rules with the same
          endpoint.  This is a bit tricky but useful if you want to have
          unique URLs:

               url_map = Map([
                   Rule('/all/', defaults={'page': 1}, endpoint='all_entries'),
                   Rule('/all/page/<int:page>', endpoint='all_entries')
               ])

          If a user now visits ‘http://example.com/all/page/1’ he will
          be redirected to ‘http://example.com/all/’.  If
          ‘redirect_defaults’ is disabled on the ‘Map’ instance this
          will only affect the URL generation.

     ‘subdomain’

          The subdomain rule string for this rule.  If not specified the
          rule only matches for the ‘default_subdomain’ of the map.  If
          the map is not bound to a subdomain this feature is disabled.

          Can be useful if you want to have user profiles on different
          subdomains and all subdomains are forwarded to your
          application:

               url_map = Map([
                   Rule('/', subdomain='<username>', endpoint='user/homepage'),
                   Rule('/stats', subdomain='<username>', endpoint='user/stats')
               ])

     ‘methods’

          A sequence of http methods this rule applies to.  If not
          specified, all methods are allowed.  For example this can be
          useful if you want different endpoints for ‘POST’ and ‘GET’.
          If methods are defined and the path matches but the method
          matched against is not in this list or in the list of another
          rule for that path the error raised is of the type
          ‘MethodNotAllowed’ rather than ‘NotFound’.  If ‘GET’ is
          present in the list of methods and ‘HEAD’ is not, ‘HEAD’ is
          added automatically.

     ‘strict_slashes’

          Override the ‘Map’ setting for ‘strict_slashes’ only for this
          rule.  If not specified the ‘Map’ setting is used.

     ‘merge_slashes’

          Override ‘Map.merge_slashes’ for this rule.

     ‘build_only’

          Set this to True and the rule will never match but will create
          a URL that can be build.  This is useful if you have resources
          on a subdomain or folder that are not handled by the WSGI
          application (like static data)

     ‘redirect_to’

          If given this must be either a string or callable.  In case of
          a callable it’s called with the url adapter that triggered the
          match and the values of the URL as keyword arguments and has
          to return the target for the redirect, otherwise it has to be
          a string with placeholders in rule syntax:

               def foo_with_slug(adapter, id):
                   # ask the database for the slug for the old id.  this of
                   # course has nothing to do with werkzeug.
                   return f'foo/{Foo.get_slug_for_id(id)}'

               url_map = Map([
                   Rule('/foo/<slug>', endpoint='foo'),
                   Rule('/some/old/url/<slug>', redirect_to='foo/<slug>'),
                   Rule('/other/old/url/<int:id>', redirect_to=foo_with_slug)
               ])

          When the rule is matched the routing system will raise a
          ‘RequestRedirect’ exception with the target for the redirect.

          Keep in mind that the URL will be joined against the URL root
          of the script so don’t use a leading slash on the target URL
          unless you really mean root of that domain.

     ‘alias’

          If enabled this rule serves as an alias for another rule with
          the same endpoint and arguments.

     ‘host’

          If provided and the URL map has host matching enabled this can
          be used to provide a match rule for the whole host.  This also
          means that the subdomain feature is disabled.

     ‘websocket’

          If ‘True’, this rule is only matches for WebSocket (‘ws://’,
          ‘wss://’) requests.  By default, rules will only match for
          HTTP requests.

     New in version 1.0: Added ‘websocket’.

     New in version 1.0: Added ‘merge_slashes’.

     New in version 0.7: Added ‘alias’ and ‘host’.

     Changed in version 0.6.1: ‘HEAD’ is added to ‘methods’ if ‘GET’ is
     present.

     Parameters:

        * ‘string’ (str(69)) –

        * ‘defaults’ (‘Optional’‘[’‘Mapping’‘[’str(70)‘, ’‘Any’‘]’‘]’) –

        * ‘subdomain’ (‘Optional’‘[’str(71)‘]’) –

        * ‘methods’ (‘Optional’‘[’‘Iterable’‘[’str(72)‘]’‘]’) –

        * ‘build_only’ (bool(73)) –

        * ‘endpoint’ (‘Optional’‘[’str(74)‘]’) –

        * ‘strict_slashes’ (‘Optional’‘[’bool(75)‘]’) –

        * ‘merge_slashes’ (‘Optional’‘[’bool(76)‘]’) –

        * ‘redirect_to’ (‘Optional’‘[’‘Union’‘[’str(77)‘,
          ’‘Callable’‘[’‘[’‘...’‘]’‘, ’str(78)‘]’‘]’‘]’) –

        * ‘alias’ (bool(79)) –

        * ‘host’ (‘Optional’‘[’str(80)‘]’) –

        * ‘websocket’ (bool(81)) –

     Return type: None(82)

      -- Method: empty ()

          Return an unbound copy of this rule.

          This can be useful if want to reuse an already bound URL for
          another map.  See ‘get_empty_kwargs’ to override what keyword
          arguments are provided to the new copy.

          Return type: werkzeug.routing.Rule.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/functions.html#bool

   (4) https://docs.python.org/3/library/functions.html#bool

   (5) https://docs.python.org/3/library/functions.html#bool

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/functions.html#bool

   (8) https://docs.python.org/3/library/stdtypes.html#str

   (9) https://docs.python.org/3/library/functions.html#bool

   (10) https://docs.python.org/3/library/constants.html#None

   (11) https://docs.python.org/3/library/constants.html#None

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/stdtypes.html#str

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/stdtypes.html#str

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/stdtypes.html#str

   (18) https://docs.python.org/3/library/stdtypes.html#str

   (19) https://docs.python.org/3/library/stdtypes.html#str

   (20) https://docs.python.org/3/library/stdtypes.html#str

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23) https://docs.python.org/3/library/stdtypes.html#str

   (24) https://docs.python.org/3/library/functions.html#bool

   (25) https://docs.python.org/3/library/stdtypes.html#str

   (26) https://docs.python.org/3/library/constants.html#None

   (27) https://docs.python.org/3/library/stdtypes.html#str

   (28) https://docs.python.org/3/library/stdtypes.html#str

   (29) https://docs.python.org/3/library/stdtypes.html#str

   (30) https://docs.python.org/3/library/stdtypes.html#str

   (31) https://docs.python.org/3/library/stdtypes.html#str

   (32) https://docs.python.org/3/library/stdtypes.html#str

   (33) https://docs.python.org/3/library/stdtypes.html#str

   (34) https://docs.python.org/3/library/stdtypes.html#str

   (35) https://docs.python.org/3/library/stdtypes.html#str

   (36) https://docs.python.org/3/library/stdtypes.html#str

   (37) https://docs.python.org/3/library/stdtypes.html#str

   (38) https://docs.python.org/3/library/stdtypes.html#str

   (39) https://docs.python.org/3/library/stdtypes.html#str

   (40) https://docs.python.org/3/library/functions.html#bool

   (41) https://docs.python.org/3/library/functions.html#bool

   (42) https://docs.python.org/3/library/stdtypes.html#str

   (43) https://docs.python.org/3/library/stdtypes.html#str

   (44) https://docs.python.org/3/library/stdtypes.html#str

   (45) https://docs.python.org/3/library/stdtypes.html#str

   (46) https://docs.python.org/3/library/stdtypes.html#str

   (47) https://docs.python.org/3/library/stdtypes.html#str

   (48) https://docs.python.org/3/library/functions.html#bool

   (49) https://docs.python.org/3/library/stdtypes.html#str

   (50) https://docs.python.org/3/library/stdtypes.html#str

   (51) https://docs.python.org/3/library/stdtypes.html#str

   (52) https://docs.python.org/3/library/stdtypes.html#str

   (53) https://docs.python.org/3/library/stdtypes.html#str

   (54) https://docs.python.org/3/library/stdtypes.html#str

   (55) https://docs.python.org/3/library/stdtypes.html#str

   (56) https://docs.python.org/3/library/stdtypes.html#str

   (57) https://docs.python.org/3/library/stdtypes.html#str

   (58) https://docs.python.org/3/library/stdtypes.html#str

   (59) https://docs.python.org/3/library/stdtypes.html#str

   (60) https://docs.python.org/3/library/functions.html#bool

   (61) https://docs.python.org/3/library/stdtypes.html#str

   (62) https://docs.python.org/3/library/stdtypes.html#str

   (63) https://docs.python.org/3/library/functions.html#bool

   (64) https://docs.python.org/3/library/stdtypes.html#str

   (65) https://docs.python.org/3/library/stdtypes.html#str

   (66) https://docs.python.org/3/library/stdtypes.html#str

   (67) https://docs.python.org/3/library/stdtypes.html#str

   (68) https://docs.python.org/3/library/functions.html#bool

   (69) https://docs.python.org/3/library/stdtypes.html#str

   (70) https://docs.python.org/3/library/stdtypes.html#str

   (71) https://docs.python.org/3/library/stdtypes.html#str

   (72) https://docs.python.org/3/library/stdtypes.html#str

   (73) https://docs.python.org/3/library/functions.html#bool

   (74) https://docs.python.org/3/library/stdtypes.html#str

   (75) https://docs.python.org/3/library/functions.html#bool

   (76) https://docs.python.org/3/library/functions.html#bool

   (77) https://docs.python.org/3/library/stdtypes.html#str

   (78) https://docs.python.org/3/library/stdtypes.html#str

   (79) https://docs.python.org/3/library/functions.html#bool

   (80) https://docs.python.org/3/library/stdtypes.html#str

   (81) https://docs.python.org/3/library/functions.html#bool

   (82) https://docs.python.org/3/library/constants.html#None

3.2.5 Rule Factories
--------------------

 -- Class: werkzeug.routing.RuleFactory

     As soon as you have more complex URL setups it’s a good idea to use
     rule factories to avoid repetitive tasks.  Some of them are
     builtin, others can be added by subclassing ‘RuleFactory’ and
     overriding ‘get_rules’.

      -- Method: get_rules (map)

          Subclasses of ‘RuleFactory’ have to override this method and
          return an iterable of rules.

          Parameters: ‘map’ (see werkzeug.routing.Map) –

          Return type: Iterable[see werkzeug.routing.Rule]

 -- Class: werkzeug.routing.Subdomain (subdomain, rules)

     All URLs provided by this factory have the subdomain set to a
     specific domain.  For example if you want to use the subdomain for
     the current language this can be a good setup:

          url_map = Map([
              Rule('/', endpoint='#select_language'),
              Subdomain('<string(length=2):lang_code>', [
                  Rule('/', endpoint='index'),
                  Rule('/about', endpoint='about'),
                  Rule('/help', endpoint='help')
              ])
          ])

     All the rules except for the ‘'#select_language'’ endpoint will now
     listen on a two letter long subdomain that holds the language code
     for the current request.

     Parameters:

        * ‘subdomain’ (str(1)) –

        * ‘rules’ (‘Iterable’‘[’werkzeug.routing.RuleFactory.
          ‘]’) –

     Return type: None(2)

 -- Class: werkzeug.routing.Submount (path, rules)

     Like ‘Subdomain’ but prefixes the URL rule with a given string:

          url_map = Map([
              Rule('/', endpoint='index'),
              Submount('/blog', [
                  Rule('/', endpoint='blog/index'),
                  Rule('/entry/<entry_slug>', endpoint='blog/show')
              ])
          ])

     Now the rule ‘'blog/show'’ matches ‘/blog/entry/<entry_slug>’.

     Parameters:

        * ‘path’ (str(3)) –

        * ‘rules’ (‘Iterable’‘[’werkzeug.routing.RuleFactory.
          ‘]’) –

     Return type: None(4)

 -- Class: werkzeug.routing.EndpointPrefix (prefix, rules)

     Prefixes all endpoints (which must be strings for this factory)
     with another string.  This can be useful for sub applications:

          url_map = Map([
              Rule('/', endpoint='index'),
              EndpointPrefix('blog/', [Submount('/blog', [
                  Rule('/', endpoint='index'),
                  Rule('/entry/<entry_slug>', endpoint='show')
              ])])
          ])

     Parameters:

        * ‘prefix’ (str(5)) –

        * ‘rules’ (‘Iterable’‘[’werkzeug.routing.RuleFactory.
          ‘]’) –

     Return type: None(6)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/constants.html#None

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/constants.html#None

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/constants.html#None

3.2.6 Rule Templates
--------------------

 -- Class: werkzeug.routing.RuleTemplate (rules)

     Returns copies of the rules wrapped and expands string templates in
     the endpoint, rule, defaults or subdomain sections.

     Here a small example for such a rule template:

          from werkzeug.routing import Map, Rule, RuleTemplate

          resource = RuleTemplate([
              Rule('/$name/', endpoint='$name.list'),
              Rule('/$name/<int:id>', endpoint='$name.show')
          ])

          url_map = Map([resource(name='user'), resource(name='page')])

     When a rule template is called the keyword arguments are used to
     replace the placeholders in all the string parameters.

     Parameters: ‘rules’ (‘Iterable’‘[’Rule.‘]’) –

     Return type: None(1)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/constants.html#None

3.2.7 Custom Converters
-----------------------

You can add custom converters that add behaviors not provided by the
built-in converters.  To make a custom converter, subclass
‘BaseConverter’ then pass the new class to the Map.
‘converters’ parameter, or add it to url_map.converters.

The converter should have a ‘regex’ attribute with a regular expression
to match with.  If the converter can take arguments in a URL rule, it
should accept them in its ‘__init__’ method.

It can implement a ‘to_python’ method to convert the matched string to
some other object.  This can also do extra validation that wasn’t
possible with the ‘regex’ attribute, and should raise a
‘werkzeug.routing.ValidationError’ in that case.  Raising any other
errors will cause a 500 error.

It can implement a ‘to_url’ method to convert a Python object to a
string when building a URL. Any error raised here will be converted to a
‘werkzeug.routing.BuildError’ and eventually cause a 500 error.

This example implements a ‘BooleanConverter’ that will match the strings
‘"yes"’, ‘"no"’, and ‘"maybe"’, returning a random value for ‘"maybe"’.

     from random import randrange
     from werkzeug.routing import BaseConverter, ValidationError

     class BooleanConverter(BaseConverter):
         regex = r"(?:yes|no|maybe)"

         def __init__(self, url_map, maybe=False):
             super().__init__(url_map)
             self.maybe = maybe

         def to_python(self, value):
             if value == "maybe":
                 if self.maybe:
                     return not randrange(2)
                 raise ValidationError
             return value == 'yes'

         def to_url(self, value):
             return "yes" if value else "no"

     from werkzeug.routing import Map, Rule

     url_map = Map([
         Rule("/vote/<bool:werkzeug_rocks>", endpoint="vote"),
         Rule("/guess/<bool(maybe=True):foo>", endpoint="guess")
     ], converters={'bool': BooleanConverter})

If you want to change the default converter, assign a different
converter to the ‘"default"’ key.

3.2.8 Host Matching
-------------------

New in version 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 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)

3.2.9 WebSockets
----------------

New in version 1.0.

If a Rule is created with ‘websocket=True’, it will only
match if the Map is bound to a request with a ‘url_scheme’ of
‘ws’ or ‘wss’.

     Note: Werkzeug has no further WebSocket support beyond routing.
     This functionality is mostly of use to ASGI projects.

     url_map = Map([
         Rule("/ws", endpoint="comm", websocket=True),
     ])
     adapter = map.bind("example.org", "/ws", url_scheme="ws")
     assert adapter.match() == ("comm", {})

If the only match is a WebSocket rule and the bind is HTTP (or the only
match is HTTP and the bind is WebSocket) a ‘WebsocketMismatch’ (derives
from BadRequest) exception is raised.

As WebSocket URLs have a different scheme, rules are always built with a
scheme and host, ‘force_external=True’ is implied.

     url = adapter.build("comm")
     assert url == "ws://example.org/ws"

3.3 WSGI Helpers
================

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
Request / Response Objects.

3.3.1 Iterator / Stream Helpers
-------------------------------

These classes and functions simplify working with the WSGI application
iterator and the input stream.

 -- Class: werkzeug.wsgi.ClosingIterator (iterable, callbacks=None)

     The WSGI specification requires that all middlewares and gateways
     respect the ‘close’ callback of the iterable returned by the
     application.  Because it is useful to add another close action to a
     returned iterable and adding a custom iterable is a boring task
     this class can be used for that:

          return ClosingIterator(app(environ, start_response), [cleanup_session,
                                                                cleanup_locals])

     If there is just one close function it can be passed instead of the
     list.

     A closing iterator is not needed if the application uses response
     objects and finishes the processing if the response is started:

          try:
              return response(environ, start_response)
          finally:
              cleanup_session()
              cleanup_locals()

     Parameters:

        * ‘iterable’ (‘Iterable’‘[’bytes(1)‘]’) –

        * ‘callbacks’ (‘Optional’‘[’‘Union’‘[’‘Callable’‘[’‘[’‘]’‘,
          ’None(2)‘]’‘, ’‘Iterable’‘[’‘Callable’‘[’‘[’‘]’‘,
          ’None(3)‘]’‘]’‘]’‘]’) –

     Return type: None(4)

 -- Class: werkzeug.wsgi.FileWrapper (file, buffer_size=8192)

     This class can be used to convert a ‘file’-like object into an
     iterable.  It yields ‘buffer_size’ blocks until the file is fully
     read.

     You should not use this class directly but rather use the
     wrap_file() function that uses the WSGI server’s file wrapper
     support if it’s available.

     New in version 0.5.

     If you’re using this object together with a ‘Response’ you have to
     use the ‘direct_passthrough’ mode.

     Parameters:

        * ‘file’ (‘IO’‘[’bytes(5)‘]’) – a ‘file’-like object with a
          ‘read()’ method.

        * ‘buffer_size’ (int(6)) – number of bytes for one iteration.

     Return type: None(7)

 -- Class: werkzeug.wsgi.LimitedStream (stream, limit)

     Wraps a stream so that it doesn’t read more than n bytes.  If the
     stream is exhausted and the caller tries to get more bytes from it
     on_exhausted() is called which by default returns an
     empty string.  The return value of that function is forwarded to
     the reader function.  So if it returns an empty string
     read() will return an empty string as well.

     The limit however must never be higher than what the stream can
     output.  Otherwise readlines() will try to read past
     the limit.

          Note on WSGI compliance: calls to readline() and
          readlines() are not WSGI compliant because it
          passes a size argument to the readline methods.  Unfortunately
          the WSGI PEP is not safely implementable without a size
          argument to readline() because there is no EOF
          marker in the stream.  As a result of that the use of
          readline() is discouraged.

          For the same reason iterating over the LimitedStream
          is not portable.  It internally calls readline().

          We strongly suggest using read() only or using the
          make_line_iter() which safely iterates line-based
          over a WSGI input stream.

     Parameters:

        * ‘stream’ (‘IO’‘[’bytes(8)‘]’) – the stream to wrap.

        * ‘limit’ (int(9)) – the limit for the stream, must not be
          longer than what the string can provide if the stream does not
          end with ‘EOF’ (like ‘wsgi.input’)

     Return type: None(10)

      -- Method: exhaust (chunk_size=65536)

          Exhaust the stream.  This consumes all the data left until the
          limit is reached.

          Parameters: ‘chunk_size’ (int(11)) – the size for a chunk.  It
          will read the chunk until the stream is exhausted and throw
          away the results.

          Return type: None(12)

      -- Property: is_exhausted: bool(13)

          If the stream is exhausted this attribute is ‘True’.

      -- Method: on_disconnect ()

          What should happen if a disconnect is detected?  The return
          value of this function is returned from read functions in case
          the client went away.  By default a ClientDisconnected
          exception is raised.

          Return type: bytes(14)

      -- Method: on_exhausted ()

          This is called when the stream tries to read past the limit.
          The return value of this function is returned from the reading
          function.

          Return type: bytes(15)

      -- Method: read (size=None)

          Read ‘size’ bytes or if size is not provided everything is
          read.

          Parameters: ‘size’ (‘Optional’‘[’int(16)‘]’) – the number of
          bytes read.

          Return type: bytes(17)

      -- Method: readable ()

          Return whether object was opened for reading.

          If False, read() will raise OSError.

          Return type: bool(18)

      -- Method: readline (size=None)

          Reads one line from the stream.

          Parameters: ‘size’ (‘Optional’‘[’int(19)‘]’) –

          Return type: bytes(20)

      -- Method: readlines (size=None)

          Reads a file into a list of strings.  It calls
          readline() until the file is read to the end.  It does
          support the optional ‘size’ argument if the underlying stream
          supports it for ‘readline’.

          Parameters: ‘size’ (‘Optional’‘[’int(21)‘]’) –

          Return type: List[bytes(22)]

      -- Method: tell ()

          Returns the position of the stream.

          New in version 0.9.

          Return type: int(23)

 -- Function: werkzeug.wsgi.make_line_iter (stream, limit=None,
          buffer_size=10240, cap_at_buffer=False)

     Safely iterates line-based over an input stream.  If the input
     stream is not a LimitedStream the ‘limit’ parameter is
     mandatory.

     This uses the stream’s ‘read()’ method internally as opposite to
     the ‘readline()’ method that is unsafe and can only be used in
     violation of the WSGI specification.  The same problem applies to
     the ‘__iter__’ function of the input stream which calls
     ‘readline()’ without arguments.

     If you need line-by-line processing it’s strongly recommended to
     iterate over the input stream using this helper function.

     New in version 0.11.10: added support for the ‘cap_at_buffer’
     parameter.

     New in version 0.9: added support for iterators as input stream.

     Changed in version 0.8: This function now ensures that the limit
     was reached.

     Parameters:

        * ‘stream’ (‘Union’‘[’‘Iterable’‘[’bytes(24)‘]’‘,
          ’‘IO’‘[’bytes(25)‘]’‘]’) – the stream or iterate to iterate
          over.

        * ‘limit’ (‘Optional’‘[’int(26)‘]’) – the limit in bytes for the
          stream.  (Usually content length.  Not necessary if the
          ‘stream’ is a LimitedStream.

        * ‘buffer_size’ (int(27)) – The optional buffer size.

        * ‘cap_at_buffer’ (bool(28)) – if this is set chunks are split
          if they are longer than the buffer size.  Internally this is
          implemented that the buffer size might be exhausted by a
          factor of two however.

     Return type: Iterator[bytes(29)]

 -- Function: werkzeug.wsgi.make_chunk_iter (stream, separator,
          limit=None, buffer_size=10240, cap_at_buffer=False)

     Works like make_line_iter() but accepts a separator
     which divides chunks.  If you want newline based processing you
     should use make_line_iter() instead as it supports
     arbitrary newline markers.

     New in version 0.11.10: added support for the ‘cap_at_buffer’
     parameter.

     New in version 0.9: added support for iterators as input stream.

     New in version 0.8.

     Parameters:

        * ‘stream’ (‘Union’‘[’‘Iterable’‘[’bytes(30)‘]’‘,
          ’‘IO’‘[’bytes(31)‘]’‘]’) – the stream or iterate to iterate
          over.

        * ‘separator’ (bytes(32)) – the separator that divides chunks.

        * ‘limit’ (‘Optional’‘[’int(33)‘]’) – the limit in bytes for the
          stream.  (Usually content length.  Not necessary if the
          ‘stream’ is otherwise already limited).

        * ‘buffer_size’ (int(34)) – The optional buffer size.

        * ‘cap_at_buffer’ (bool(35)) – if this is set chunks are split
          if they are longer than the buffer size.  Internally this is
          implemented that the buffer size might be exhausted by a
          factor of two however.

     Return type: Iterator[bytes(36)]

 -- Function: werkzeug.wsgi.wrap_file (environ, file, buffer_size=8192)

     Wraps a file.  This uses the WSGI server’s file wrapper if
     available or otherwise the generic FileWrapper.

     New in version 0.5.

     If the file wrapper from the WSGI server is used it’s important to
     not iterate over it from inside the application but to pass it
     through unchanged.  If you want to pass out a file wrapper inside a
     response object you have to set ‘Response.direct_passthrough’ to
     ‘True’.

     More information about file wrappers are available in PEP 333(37).

     Parameters:

        * ‘file’ (‘IO’‘[’bytes(38)‘]’) – a ‘file’-like object with a
          ‘read()’ method.

        * ‘buffer_size’ (int(39)) – number of bytes for one iteration.

        * ‘environ’ (‘WSGIEnvironment’) –

     Return type: Iterable[bytes(40)]

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#bytes

   (2) https://docs.python.org/3/library/constants.html#None

   (3) https://docs.python.org/3/library/constants.html#None

   (4) https://docs.python.org/3/library/constants.html#None

   (5) https://docs.python.org/3/library/stdtypes.html#bytes

   (6) https://docs.python.org/3/library/functions.html#int

   (7) https://docs.python.org/3/library/constants.html#None

   (8) https://docs.python.org/3/library/stdtypes.html#bytes

   (9) https://docs.python.org/3/library/functions.html#int

   (10) https://docs.python.org/3/library/constants.html#None

   (11) https://docs.python.org/3/library/functions.html#int

   (12) https://docs.python.org/3/library/constants.html#None

   (13) https://docs.python.org/3/library/functions.html#bool

   (14) https://docs.python.org/3/library/stdtypes.html#bytes

   (15) https://docs.python.org/3/library/stdtypes.html#bytes

   (16) https://docs.python.org/3/library/functions.html#int

   (17) https://docs.python.org/3/library/stdtypes.html#bytes

   (18) https://docs.python.org/3/library/functions.html#bool

   (19) https://docs.python.org/3/library/functions.html#int

   (20) https://docs.python.org/3/library/stdtypes.html#bytes

   (21) https://docs.python.org/3/library/functions.html#int

   (22) https://docs.python.org/3/library/stdtypes.html#bytes

   (23) https://docs.python.org/3/library/functions.html#int

   (24) https://docs.python.org/3/library/stdtypes.html#bytes

   (25) https://docs.python.org/3/library/stdtypes.html#bytes

   (26) https://docs.python.org/3/library/functions.html#int

   (27) https://docs.python.org/3/library/functions.html#int

   (28) https://docs.python.org/3/library/functions.html#bool

   (29) https://docs.python.org/3/library/stdtypes.html#bytes

   (30) https://docs.python.org/3/library/stdtypes.html#bytes

   (31) https://docs.python.org/3/library/stdtypes.html#bytes

   (32) https://docs.python.org/3/library/stdtypes.html#bytes

   (33) https://docs.python.org/3/library/functions.html#int

   (34) https://docs.python.org/3/library/functions.html#int

   (35) https://docs.python.org/3/library/functions.html#bool

   (36) https://docs.python.org/3/library/stdtypes.html#bytes

   (37) https://www.python.org/dev/peps/pep-0333

   (38) https://docs.python.org/3/library/stdtypes.html#bytes

   (39) https://docs.python.org/3/library/functions.html#int

   (40) https://docs.python.org/3/library/stdtypes.html#bytes

3.3.2 Environ Helpers
---------------------

These functions operate on the WSGI environment.  They extract useful
information or perform common manipulations:

 -- Function: werkzeug.wsgi.get_host (environ, trusted_hosts=None)

     Return the host for the given WSGI environment.

     The ‘Host’ header is preferred, then ‘SERVER_NAME’ if it’s not set.
     The returned host will only contain the port if it is different
     than the standard port for the protocol.

     Optionally, verify that the host is trusted using
     host_is_trusted() and raise a SecurityError if it
     is not.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – A WSGI environment dict.

        * ‘trusted_hosts’ (‘Optional’‘[’‘Iterable’‘[’str(1)‘]’‘]’) – A
          list of trusted host names.

     Returns: Host, with port if necessary.

     Raises: SecurityError. – If the host is not trusted.

     Return type: str(2)

 -- Function: werkzeug.wsgi.get_content_length (environ)

     Returns the content length from the WSGI environment as integer.
     If it’s not available or chunked transfer encoding is used, ‘None’
     is returned.

     New in version 0.9.

     Parameters: ‘environ’ (‘WSGIEnvironment’) – the WSGI environ to
     fetch the content length from.

     Return type: Optional[int(3)]

 -- Function: werkzeug.wsgi.get_input_stream (environ,
          safe_fallback=True)

     Returns the input stream from the WSGI environment and wraps it in
     the most sensible way possible.  The stream returned is not the raw
     WSGI stream in most cases but one that is safe to read from without
     taking into account the content length.

     If content length is not set, the stream will be empty for safety
     reasons.  If the WSGI server supports chunked or infinite streams,
     it should set the ‘wsgi.input_terminated’ value in the WSGI environ
     to indicate that.

     New in version 0.9.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – the WSGI environ to fetch the
          stream from.

        * ‘safe_fallback’ (bool(4)) – use an empty stream as a safe
          fallback when the content length is not set.  Disabling this
          allows infinite streams, which can be a denial-of-service
          risk.

     Return type: IO[bytes(5)]

 -- Function: werkzeug.wsgi.get_current_url (environ, root_only=False,
          strip_querystring=False, host_only=False, trusted_hosts=None)

     Recreate the URL for a request from the parts in a WSGI
     environment.

     The URL is an IRI, not a URI, so it may contain Unicode characters.
     Use iri_to_uri() to convert it to ASCII.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – The WSGI environment to get
          the URL parts from.

        * ‘root_only’ (bool(6)) – Only build the root path, don’t
          include the remaining path or query string.

        * ‘strip_querystring’ (bool(7)) – Don’t include the query
          string.

        * ‘host_only’ (bool(8)) – Only build the scheme and host.

        * ‘trusted_hosts’ (‘Optional’‘[’‘Iterable’‘[’str(9)‘]’‘]’) – A
          list of trusted host names to validate the host against.

     Return type: str(10)

 -- Function: werkzeug.wsgi.get_query_string (environ)

     Returns the ‘QUERY_STRING’ from the WSGI environment.  This also
     takes care of the WSGI decoding dance.  The string returned will be
     restricted to ASCII characters.

     Parameters: ‘environ’ (‘WSGIEnvironment’) – WSGI environment to get
     the query string from.

     Return type: str(11)

     New in version 0.9.

 -- Function: werkzeug.wsgi.get_script_name (environ, charset='utf-8',
          errors='replace')

     Return the ‘SCRIPT_NAME’ from the WSGI environment and decode it
     unless ‘charset’ is set to ‘None’.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – WSGI environment to get the
          path from.

        * ‘charset’ (str(12)) – The charset for the path, or ‘None’ if
          no decoding should be performed.

        * ‘errors’ (str(13)) – The decoding error handling.

     Return type: str(14)

     New in version 0.9.

 -- Function: werkzeug.wsgi.get_path_info (environ, charset='utf-8',
          errors='replace')

     Return the ‘PATH_INFO’ from the WSGI environment and decode it
     unless ‘charset’ is ‘None’.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – WSGI environment to get the
          path from.

        * ‘charset’ (str(15)) – The charset for the path info, or ‘None’
          if no decoding should be performed.

        * ‘errors’ (str(16)) – The decoding error handling.

     Return type: str(17)

     New in version 0.9.

 -- Function: werkzeug.wsgi.pop_path_info (environ, charset='utf-8',
          errors='replace')

     Removes and returns the next segment of ‘PATH_INFO’, pushing it
     onto ‘SCRIPT_NAME’. Returns ‘None’ if there is nothing left on
     ‘PATH_INFO’.

     If the ‘charset’ is set to ‘None’ bytes are returned.

     If there are empty segments (‘'/foo//bar’) these are ignored but
     properly pushed to the ‘SCRIPT_NAME’:

          >>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'}
          >>> pop_path_info(env)
          'a'
          >>> env['SCRIPT_NAME']
          '/foo/a'
          >>> pop_path_info(env)
          'b'
          >>> env['SCRIPT_NAME']
          '/foo/a/b'

     Changed in version 0.9: The path is now decoded and a charset and
     encoding parameter can be provided.

     New in version 0.5.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – the WSGI environment that is
          modified.

        * ‘charset’ (str(18)) – The ‘encoding’ parameter passed to
          ‘bytes.decode()’.

        * ‘errors’ (str(19)) – The ‘errors’ paramater passed to
          ‘bytes.decode()’.

     Return type: Optional[str(20)]

 -- Function: werkzeug.wsgi.peek_path_info (environ, charset='utf-8',
          errors='replace')

     Returns the next segment on the ‘PATH_INFO’ or ‘None’ if there is
     none.  Works like pop_path_info() without modifying the
     environment:

          >>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'}
          >>> peek_path_info(env)
          'a'
          >>> peek_path_info(env)
          'a'

     If the ‘charset’ is set to ‘None’ bytes are returned.

     Changed in version 0.9: The path is now decoded and a charset and
     encoding parameter can be provided.

     New in version 0.5.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – the WSGI environment that is
          checked.

        * ‘charset’ (str(21)) –

        * ‘errors’ (str(22)) –

     Return type: Optional[str(23)]

 -- Function: werkzeug.wsgi.extract_path_info (environ_or_baseurl,
          path_or_url, charset='utf-8', errors='werkzeug.url_quote',
          collapse_http_schemes=True)

     Extracts the path info from the given URL (or WSGI environment) and
     path.  The path info returned is a string.  The URLs might also be
     IRIs.

     If the path info could not be determined, ‘None’ is returned.

     Some examples:

          >>> extract_path_info('http://example.com/app', '/app/hello')
          '/hello'
          >>> extract_path_info('http://example.com/app',
          ...                   'https://example.com/app/hello')
          '/hello'
          >>> extract_path_info('http://example.com/app',
          ...                   'https://example.com/app/hello',
          ...                   collapse_http_schemes=False) is None
          True

     Instead of providing a base URL you can also pass a WSGI
     environment.

     Parameters:

        * ‘environ_or_baseurl’ (‘Union’‘[’str(24)‘,
          ’‘WSGIEnvironment’‘]’) – a WSGI environment dict, a base URL
          or base IRI. This is the root of the application.

        * ‘path_or_url’ (‘Union’‘[’str(25)‘,
          ’‘werkzeug.urls._URLTuple’‘]’) – an absolute path from the
          server root, a relative path (in which case it’s the path
          info) or a full URL.

        * ‘charset’ (str(26)) – the charset for byte data in URLs

        * ‘errors’ (str(27)) – the error handling on decode

        * ‘collapse_http_schemes’ (bool(28)) – if set to ‘False’ the
          algorithm does not assume that http and https on the same
          server point to the same resource.

     Return type: Optional[str(29)]

     Changed in version 0.15: The ‘errors’ parameter defaults to leaving
     invalid bytes quoted instead of replacing them.

     New in version 0.6.

 -- Function: werkzeug.wsgi.host_is_trusted (hostname, trusted_list)

     Check if a host matches a list of trusted names.

     Parameters:

        * ‘hostname’ (str(30)) – The name to check.

        * ‘trusted_list’ (‘Iterable’‘[’str(31)‘]’) – A list of valid
          names to match.  If a name starts with a dot it will match all
          subdomains.

     Return type: bool(32)

     New in version 0.9.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/functions.html#int

   (4) https://docs.python.org/3/library/functions.html#bool

   (5) https://docs.python.org/3/library/stdtypes.html#bytes

   (6) https://docs.python.org/3/library/functions.html#bool

   (7) https://docs.python.org/3/library/functions.html#bool

   (8) https://docs.python.org/3/library/functions.html#bool

   (9) https://docs.python.org/3/library/stdtypes.html#str

   (10) https://docs.python.org/3/library/stdtypes.html#str

   (11) https://docs.python.org/3/library/stdtypes.html#str

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/stdtypes.html#str

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/stdtypes.html#str

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/stdtypes.html#str

   (18) https://docs.python.org/3/library/stdtypes.html#str

   (19) https://docs.python.org/3/library/stdtypes.html#str

   (20) https://docs.python.org/3/library/stdtypes.html#str

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23) https://docs.python.org/3/library/stdtypes.html#str

   (24) https://docs.python.org/3/library/stdtypes.html#str

   (25) https://docs.python.org/3/library/stdtypes.html#str

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/stdtypes.html#str

   (28) https://docs.python.org/3/library/functions.html#bool

   (29) https://docs.python.org/3/library/stdtypes.html#str

   (30) https://docs.python.org/3/library/stdtypes.html#str

   (31) https://docs.python.org/3/library/stdtypes.html#str

   (32) https://docs.python.org/3/library/functions.html#bool

3.3.3 Convenience Helpers
-------------------------

 -- Function: werkzeug.wsgi.responder (f)

     Marks a function as responder.  Decorate a function with it and it
     will automatically call the return value as WSGI application.

     Example:

          @responder
          def application(environ, start_response):
              return Response('Hello World!')

     Parameters: ‘f’ (‘Callable’‘[’‘[’‘...’‘]’‘, ’‘WSGIApplication’‘]’)
     –

     Return type: WSGIApplication

 -- Function: werkzeug.testapp.test_app (environ, start_response)

     Simple test application that dumps the environment.  You can use it
     to check if Werkzeug is working properly:

          >>> from werkzeug.serving import run_simple
          >>> from werkzeug.testapp import test_app
          >>> run_simple('localhost', 3000, test_app)
           * Running on http://localhost:3000/

     The application displays important information from the WSGI
     environment, the Python interpreter and the installed libraries.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) –

        * ‘start_response’ (‘StartResponse’) –

     Return type: Iterable[bytes(1)]

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#bytes

3.3.4 Bytes, Strings, and Encodings
-----------------------------------

The values in HTTP requests come in as bytes representing (or encoded
to) ASCII. The WSGI specification ( PEP 3333(1)) decided to always use
the ‘str’ type to represent values.  To accomplish this, the raw bytes
are decoded using the ISO-8859-1 charset to produce a string.

Strings in the WSGI environment are restricted to ISO-8859-1 code
points.  If a string read from the environment might contain characters
outside that charset, it must first be decoded to bytes as ISO-8859-1,
then encoded to a string using the proper charset (typically UTF-8).
The reverse is done when writing to the environ.  This is known as the
“WSGI encoding dance”.

Werkzeug provides functions to deal with this automatically so that you
don’t need to be aware of the inner workings.  Use the functions on this
page as well as EnvironHeaders() to read data out of the
WSGI environment.

Applications should avoid manually creating or modifying a WSGI
environment unless they take care of the proper encoding or decoding
step.  All high level interfaces in Werkzeug will apply the encoding and
decoding as necessary.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-3333

3.3.5 Raw Request URI and Path Encoding
---------------------------------------

The ‘PATH_INFO’ in the environ is the path value after percent-decoding.
For example, the raw path ‘/hello%2fworld’ would show up from the WSGI
server to Werkzeug as ‘/hello/world’.  This loses the information that
the slash was a raw character as opposed to a path separator.

The WSGI specification ( PEP 3333(1)) does not provide a way to get the
original value, so it is impossible to route some types of data in the
path.  The most compatible way to work around this is to send
problematic data in the query string instead of the path.

However, many WSGI servers add a non-standard environ key with the raw
path.  To match this behavior, Werkzeug’s test client and development
server will add the raw value to both the ‘REQUEST_URI’ and ‘RAW_URI’
keys.  If you want to route based on this value, you can use middleware
to replace ‘PATH_INFO’ in the environ before it reaches the application.
However, keep in mind that these keys are non-standard and not
guaranteed to be present.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-3333

3.4 Filesystem Utilities
========================

Various utilities for the local filesystem.

 -- Class: werkzeug.filesystem.BrokenFilesystemWarning

     The warning used by Werkzeug to signal a broken filesystem.  Will
     only be used once per runtime.

 -- Function: werkzeug.filesystem.get_filesystem_encoding ()

     Returns the filesystem encoding that should be used.  Note that
     this is different from the Python understanding of the filesystem
     encoding which might be deeply flawed.  Do not use this value
     against Python’s string APIs because it might be different.  See
     The Filesystem for the exact behavior.

     The concept of a filesystem encoding in generally is not something
     you should rely on.  As such if you ever need to use this function
     except for writing wrapper code reconsider.

     Return type: str(1)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

3.5 HTTP Utilities
==================

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.

3.5.1 Datetime Functions
------------------------

These functions simplify working with times in an HTTP context.
Werkzeug produces timezone-aware datetime(1) objects in UTC. When
passing datetime objects to Werkzeug, it assumes any naive datetime is
in UTC.

When comparing datetime values from Werkzeug, your own datetime objects
must also be timezone-aware, or you must make the values from Werkzeug
naive.

   * ‘dt = datetime.now(timezone.utc)’ gets the current time in UTC.

   * ‘dt = datetime(..., tzinfo=timezone.utc)’ creates a time in UTC.

   * ‘dt = dt.replace(tzinfo=timezone.utc)’ makes a naive object aware
     by assuming it’s in UTC.

   * ‘dt = dt.replace(tzinfo=None)’ makes an aware object naive.

 -- Function: werkzeug.http.parse_date (value)

     Parse an RFC 2822(2) date into a timezone-aware
     datetime.datetime(3) object, or ‘None’ if parsing fails.

     This is a wrapper for email.utils.parsedate_to_datetime()(4).  It
     returns ‘None’ if parsing fails instead of raising an exception,
     and always returns a timezone-aware datetime object.  If the string
     doesn’t have timezone information, it is assumed to be UTC.

     Parameters: ‘value’ (‘Optional’‘[’str(5)‘]’) – A string with a
     supported date format.

     Return type: Optional[datetime.datetime(6)]

     Changed in version 2.0: Return a timezone-aware datetime object.
     Use ‘email.utils.parsedate_to_datetime’.

 -- Function: werkzeug.http.http_date (timestamp=None)

     Format a datetime object or timestamp into an RFC 2822(7) date
     string.

     This is a wrapper for email.utils.format_datetime()(8).  It assumes
     naive datetime objects are in UTC instead of raising an exception.

     Parameters: ‘timestamp’
     (‘Optional’‘[’‘Union’‘[’datetime.datetime(9)‘, ’datetime.date(10)‘,
     ’int(11)‘, ’float(12)‘, ’time.struct_time(13)‘]’‘]’) – The datetime
     or timestamp to format.  Defaults to the current time.

     Return type: str(14)

     Changed in version 2.0: Use ‘email.utils.format_datetime’.  Accept
     ‘date’ objects.

 -- Function: werkzeug.http.cookie_date (expires=None)

     Format a datetime object or timestamp into an RFC 2822(15) date
     string for ‘Set-Cookie expires’.

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     http_date() instead.

     Parameters: ‘expires’
     (‘Optional’‘[’‘Union’‘[’datetime.datetime(16)‘,
     ’datetime.date(17)‘, ’int(18)‘, ’float(19)‘,
     ’time.struct_time(20)‘]’‘]’) –

     Return type: str(21)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/datetime.html#datetime.datetime

   (2) https://tools.ietf.org/html/rfc2822.html

   (3) https://docs.python.org/3/library/datetime.html#datetime.datetime

   (4)
https://docs.python.org/3/library/email.utils.html#email.utils.parsedate_to_datetime

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/datetime.html#datetime.datetime

   (7) https://tools.ietf.org/html/rfc2822.html

   (8)
https://docs.python.org/3/library/email.utils.html#email.utils.format_datetime

   (9) https://docs.python.org/3/library/datetime.html#datetime.datetime

   (10) https://docs.python.org/3/library/datetime.html#datetime.date

   (11) https://docs.python.org/3/library/functions.html#int

   (12) https://docs.python.org/3/library/functions.html#float

   (13) https://docs.python.org/3/library/time.html#time.struct_time

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://tools.ietf.org/html/rfc2822.html

   (16)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (17) https://docs.python.org/3/library/datetime.html#datetime.date

   (18) https://docs.python.org/3/library/functions.html#int

   (19) https://docs.python.org/3/library/functions.html#float

   (20) https://docs.python.org/3/library/time.html#time.struct_time

   (21) https://docs.python.org/3/library/stdtypes.html#str

3.5.2 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(1), Werkzeug implements some custom data structures
that are documented separately.

 -- Function: werkzeug.http.parse_options_header (value, multiple=False)

     Parse a ‘Content-Type’ like header into a tuple with the content
     type and the options:

          >>> parse_options_header('text/html; charset=utf8')
          ('text/html', {'charset': 'utf8'})

     This should not be used to parse ‘Cache-Control’ like headers that
     use a slightly different format.  For these headers use the
     parse_dict_header() function.

     Changed in version 0.15: RFC 2231(2) parameter continuations are
     handled.

     New in version 0.5.

     Parameters:

        * ‘value’ (‘Optional’‘[’str(3)‘]’) – the header to parse.

        * ‘multiple’ (bool(4)) – Whether try to parse and return
          multiple MIME types

     Returns: (mimetype, options) or (mimetype, options, mimetype,
     options, …) if multiple=True

     Return type: Union[Tuple[str(5), Dict[str(6), str(7)]], Tuple[Any,
     …]]

 -- Function: werkzeug.http.parse_set_header (value, on_update=None)

     Parse a set-like header and return a HeaderSet object:

          >>> hs = parse_set_header('token, "quoted value"')

     The return value is an object that treats the items
     case-insensitively and keeps the order of the items:

          >>> 'TOKEN' in hs
          True
          >>> hs.index('quoted value')
          1
          >>> hs
          HeaderSet(['token', 'quoted value'])

     To create a header from the ‘HeaderSet’ again, use the
     dump_header() function.

     Parameters:

        * ‘value’ (‘Optional’‘[’str(8)‘]’) – a set header to be parsed.

        * ‘on_update’ (‘Optional’‘[’‘Callable’‘[’‘[’
          werkzeug.datastructures.HeaderSet.‘]’‘, ’None(9)‘]’‘]’) –
          an optional callable that is called every time a value on the
          HeaderSet object is changed.

     Returns: a HeaderSet.

     Return type: werkzeug.datastructures.HeaderSet.

 -- Function: werkzeug.http.parse_list_header (value)

     Parse lists as described by RFC 2068 Section 2.

     In particular, parse comma-separated lists where the elements of
     the list may include quoted-strings.  A quoted-string could contain
     a comma.  A non-quoted string could have quotes in the middle.
     Quotes are removed automatically after parsing.

     It basically works like parse_set_header() just that
     items may appear multiple times and case sensitivity is preserved.

     The return value is a standard list(10):

          >>> parse_list_header('token, "quoted value"')
          ['token', 'quoted value']

     To create a header from the list(11) again, use the
     dump_header() function.

     Parameters: ‘value’ (str(12)) – a string with a list header.

     Returns: list(13)

     Return type: List[str(14)]

 -- Function: werkzeug.http.parse_dict_header (value, cls=<class
          'dict'>)

     Parse lists of key, value pairs as described by RFC 2068 Section 2
     and convert them into a python dict (or any other mapping object
     created from the type with a dict like interface provided by the
     ‘cls’ argument):

          >>> d = parse_dict_header('foo="is a fish", bar="as well"')
          >>> type(d) is dict
          True
          >>> sorted(d.items())
          [('bar', 'as well'), ('foo', 'is a fish')]

     If there is no value for a key it will be ‘None’:

          >>> parse_dict_header('key_without_value')
          {'key_without_value': None}

     To create a header from the dict(15) again, use the
     dump_header() function.

     Changed in version 0.9: Added support for ‘cls’ argument.

     Parameters:

        * ‘value’ (str(16)) – a string with a dict header.

        * ‘cls’ (‘Type’‘[’dict(17)‘]’) – callable to use for storage of
          parsed results.

     Returns: an instance of ‘cls’

     Return type: Dict[str(18), str(19)]

 -- Function: werkzeug.http.parse_accept_header (value[, class])

     Parses an HTTP Accept-* header.  This does not implement a complete
     valid algorithm but one that supports at least value and quality
     extraction.

     Returns a new ‘Accept’ object (basically a list of ‘(value,
     quality)’ tuples sorted by the quality with some additional
     accessor methods).

     The second parameter can be a subclass of ‘Accept’ that is created
     with the parsed values and returned.

     Parameters:

        * ‘value’ (‘Optional’‘[’str(20)‘]’) – the accept header string
          to be parsed.

        * ‘cls’
          (‘Optional’‘[’‘Type’‘[’‘werkzeug.http._TAnyAccept’‘]’‘]’) –
          the wrapper class for the return value (can be ‘Accept’ or a
          subclass thereof)

     Returns: an instance of ‘cls’.

     Return type: werkzeug.http._TAnyAccept

 -- Function: werkzeug.http.parse_cache_control_header (value,
          on_update=None, cls=None)

     Parse a cache control header.  The RFC differs between response and
     request cache control, this method does not.  It’s your
     responsibility to not use the wrong control statements.

     New in version 0.5: The ‘cls’ was added.  If not specified an
     immutable RequestCacheControl is returned.

     Parameters:

        * ‘value’ (‘Optional’‘[’str(21)‘]’) – a cache control header to
          be parsed.

        * ‘on_update’
          (‘Optional’‘[’‘Callable’‘[’‘[’‘werkzeug.http._TAnyCC’‘]’‘,
          ’None(22)‘]’‘]’) – an optional callable that is called every
          time a value on the ‘CacheControl’ object is changed.

        * ‘cls’ (‘Optional’‘[’‘Type’‘[’‘werkzeug.http._TAnyCC’‘]’‘]’) –
          the class for the returned object.  By default
          RequestCacheControl is used.

     Returns: a ‘cls’ object.

     Return type: werkzeug.http._TAnyCC

 -- Function: werkzeug.http.parse_authorization_header (value)

     Parse an HTTP basic/digest authorization header transmitted by the
     web browser.  The return value is either ‘None’ if the header was
     invalid or not given, otherwise an Authorization object.

     Parameters: ‘value’ (‘Optional’‘[’str(23)‘]’) – the authorization
     header to parse.

     Returns: a Authorization object or ‘None’.

     Return type: Optional[see werkzeug.datastructures.Authorization]

 -- Function: werkzeug.http.parse_www_authenticate_header (value,
          on_update=None)

     Parse an HTTP WWW-Authenticate header into a WWWAuthenticate
     object.

     Parameters:

        * ‘value’ (‘Optional’‘[’str(24)‘]’) – a WWW-Authenticate header
          to parse.

        * ‘on_update’ (‘Optional’‘[’‘Callable’‘[’‘[’
          werkzeug.datastructures.WWWAuthenticate.‘]’‘,
          ’None(25)‘]’‘]’) – an optional callable that is called every
          time a value on the WWWAuthenticate object is
          changed.

     Returns: a WWWAuthenticate object.

     Return type: werkzeug.datastructures.WWWAuthenticate.

 -- Function: werkzeug.http.parse_if_range_header (value)

     Parses an if-range header which can be an etag or a date.  Returns
     a IfRange object.

     Changed in version 2.0: If the value represents a datetime, it is
     timezone-aware.

     New in version 0.7.

     Parameters: ‘value’ (‘Optional’‘[’str(26)‘]’) –

     Return type: werkzeug.datastructures.IfRange.

 -- Function: werkzeug.http.parse_range_header (value,
          make_inclusive=True)

     Parses a range header into a Range object.  If the
     header is missing or malformed ‘None’ is returned.  ‘ranges’ is a
     list of ‘(start, stop)’ tuples where the ranges are non-inclusive.

     New in version 0.7.

     Parameters:

        * ‘value’ (‘Optional’‘[’str(27)‘]’) –

        * ‘make_inclusive’ (bool(28)) –

     Return type: Optional[see werkzeug.datastructures.Range]

 -- Function: werkzeug.http.parse_content_range_header (value,
          on_update=None)

     Parses a range header into a ContentRange object or
     ‘None’ if parsing is not possible.

     New in version 0.7.

     Parameters:

        * ‘value’ (‘Optional’‘[’str(29)‘]’) – a content range header to
          be parsed.

        * ‘on_update’ (‘Optional’‘[’‘Callable’‘[’‘[’
          werkzeug.datastructures.ContentRange.‘]’‘,
          ’None(30)‘]’‘]’) – an optional callable that is called every
          time a value on the ContentRange object is
          changed.

     Return type: Optional[see werkzeug.datastructures.ContentRange]

   ---------- Footnotes ----------

   (1) https://tools.ietf.org/html/rfc2616.html

   (2) https://tools.ietf.org/html/rfc2231.html

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/functions.html#bool

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/stdtypes.html#str

   (9) https://docs.python.org/3/library/constants.html#None

   (10) https://docs.python.org/3/library/stdtypes.html#list

   (11) https://docs.python.org/3/library/stdtypes.html#list

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/stdtypes.html#list

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/stdtypes.html#dict

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/stdtypes.html#dict

   (18) https://docs.python.org/3/library/stdtypes.html#str

   (19) https://docs.python.org/3/library/stdtypes.html#str

   (20) https://docs.python.org/3/library/stdtypes.html#str

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22) https://docs.python.org/3/library/constants.html#None

   (23) https://docs.python.org/3/library/stdtypes.html#str

   (24) https://docs.python.org/3/library/stdtypes.html#str

   (25) https://docs.python.org/3/library/constants.html#None

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/stdtypes.html#str

   (28) https://docs.python.org/3/library/functions.html#bool

   (29) https://docs.python.org/3/library/stdtypes.html#str

   (30) https://docs.python.org/3/library/constants.html#None

3.5.3 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.

 -- Function: werkzeug.http.is_entity_header (header)

     Check if a header is an entity header.

     New in version 0.5.

     Parameters: ‘header’ (str(1)) – the header to test.

     Returns: ‘True’ if it’s an entity header, ‘False’ otherwise.

     Return type: bool(2)

 -- Function: werkzeug.http.is_hop_by_hop_header (header)

     Check if a header is an HTTP/1.1 “Hop-by-Hop” header.

     New in version 0.5.

     Parameters: ‘header’ (str(3)) – the header to test.

     Returns: ‘True’ if it’s an HTTP/1.1 “Hop-by-Hop” header, ‘False’
     otherwise.

     Return type: bool(4)

 -- Function: werkzeug.http.remove_entity_headers (headers,
          allowed=('expires', 'content-location'))

     Remove all entity headers from a list or ‘Headers’ object.  This
     operation works in-place.  ‘Expires’ and ‘Content-Location’ headers
     are by default not removed.  The reason for this is RFC 2616(5)
     section 10.3.5 which specifies some entity headers that should be
     sent.

     Changed in version 0.5: added ‘allowed’ parameter.

     Parameters:

        * ‘headers’ (‘Union’‘[’werkzeug.datastructures.Headers.
          ‘, ’‘List’‘[’‘Tuple’‘[’str(6)‘, ’str(7)‘]’‘]’‘]’) – a list
          or ‘Headers’ object.

        * ‘allowed’ (‘Iterable’‘[’str(8)‘]’) – a list of headers that
          should still be allowed even though they are entity headers.

     Return type: None(9)

 -- Function: werkzeug.http.remove_hop_by_hop_headers (headers)

     Remove all HTTP/1.1 “Hop-by-Hop” headers from a list or ‘Headers’
     object.  This operation works in-place.

     New in version 0.5.

     Parameters: ‘headers’ (‘Union’‘[’
     werkzeug.datastructures.Headers.‘,
     ’‘List’‘[’‘Tuple’‘[’str(10)‘, ’str(11)‘]’‘]’‘]’) – a list or
     ‘Headers’ object.

     Return type: None(12)

 -- Function: werkzeug.http.is_byte_range_valid (start, stop, length)

     Checks if a given byte content range is valid for the given length.

     New in version 0.7.

     Parameters:

        * ‘start’ (‘Optional’‘[’int(13)‘]’) –

        * ‘stop’ (‘Optional’‘[’int(14)‘]’) –

        * ‘length’ (‘Optional’‘[’int(15)‘]’) –

     Return type: bool(16)

 -- Function: werkzeug.http.quote_header_value (value, extra_chars='',
          allow_token=True)

     Quote a header value if necessary.

     New in version 0.5.

     Parameters:

        * ‘value’ (‘Union’‘[’str(17)‘, ’int(18)‘]’) – the value to
          quote.

        * ‘extra_chars’ (str(19)) – a list of extra characters to skip
          quoting.

        * ‘allow_token’ (bool(20)) – if this is enabled token values are
          returned unchanged.

     Return type: str(21)

 -- Function: werkzeug.http.unquote_header_value (value,
          is_filename=False)

     Unquotes a header value.  (Reversal of quote_header_value()).
     This does not use the real unquoting but what browsers are
     actually using for quoting.

     New in version 0.5.

     Parameters:

        * ‘value’ (str(22)) – the header value to unquote.

        * ‘is_filename’ (bool(23)) – The value represents a filename or
          path.

     Return type: str(24)

 -- Function: werkzeug.http.dump_header (iterable, allow_token=True)

     Dump an HTTP header again.  This is the reversal of
     parse_list_header(), parse_set_header() and
     parse_dict_header().  This also quotes strings that include an
     equals sign unless you pass it as dict of key, value pairs.

          >>> dump_header({'foo': 'bar baz'})
          'foo="bar baz"'
          >>> dump_header(('foo', 'bar baz'))
          'foo, "bar baz"'

     Parameters:

        * ‘iterable’ (‘Union’‘[’‘Dict’‘[’str(25)‘, ’‘Union’‘[’str(26)‘,
          ’int(27)‘]’‘]’‘, ’‘Iterable’‘[’str(28)‘]’‘]’) – the iterable
          or dict of values to quote.

        * ‘allow_token’ (bool(29)) – if set to ‘False’ tokens as values
          are disallowed.  See quote_header_value() for more
          details.

     Return type: str(30)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/functions.html#bool

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/functions.html#bool

   (5) https://tools.ietf.org/html/rfc2616.html

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/stdtypes.html#str

   (9) https://docs.python.org/3/library/constants.html#None

   (10) https://docs.python.org/3/library/stdtypes.html#str

   (11) https://docs.python.org/3/library/stdtypes.html#str

   (12) https://docs.python.org/3/library/constants.html#None

   (13) https://docs.python.org/3/library/functions.html#int

   (14) https://docs.python.org/3/library/functions.html#int

   (15) https://docs.python.org/3/library/functions.html#int

   (16) https://docs.python.org/3/library/functions.html#bool

   (17) https://docs.python.org/3/library/stdtypes.html#str

   (18) https://docs.python.org/3/library/functions.html#int

   (19) https://docs.python.org/3/library/stdtypes.html#str

   (20) https://docs.python.org/3/library/functions.html#bool

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23) https://docs.python.org/3/library/functions.html#bool

   (24) https://docs.python.org/3/library/stdtypes.html#str

   (25) https://docs.python.org/3/library/stdtypes.html#str

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/functions.html#int

   (28) https://docs.python.org/3/library/stdtypes.html#str

   (29) https://docs.python.org/3/library/functions.html#bool

   (30) https://docs.python.org/3/library/stdtypes.html#str

3.5.4 Cookies
-------------

 -- Function: werkzeug.http.parse_cookie (header, charset='utf-8',
          errors='replace', cls=None)

     Parse a cookie from a string or WSGI environ.

     The same key can be provided multiple times, the values are stored
     in-order.  The default ‘MultiDict’ will have the first value first,
     and all values can be retrieved with ‘MultiDict.getlist()’.

     Parameters:

        * ‘header’ (‘Optional’‘[’‘Union’‘[’‘WSGIEnvironment’‘, ’str(1)‘,
          ’bytes(2)‘]’‘]’) – The cookie header as a string, or a WSGI
          environ dict with a ‘HTTP_COOKIE’ key.

        * ‘charset’ (str(3)) – The charset for the cookie values.

        * ‘errors’ (str(4)) – The error behavior for the charset
          decoding.

        * ‘cls’ (‘Optional’‘[’‘Type’‘[’‘ds.MultiDict’‘]’‘]’) – A
          dict-like class to store the parsed cookies in.  Defaults to
          ‘MultiDict’.

     Return type: ds.MultiDict[str(5), str(6)]

     Changed in version 1.0.0: Returns a ‘MultiDict’ instead of a
     ‘TypeConversionDict’.

     Changed in version 0.5: Returns a ‘TypeConversionDict’ instead of a
     regular dict.  The ‘cls’ parameter was added.

 -- Function: werkzeug.http.dump_cookie (key, value='', max_age=None,
          expires=None, path='/', domain=None, secure=False,
          httponly=False, charset='utf-8', sync_expires=True,
          max_size=4093, samesite=None)

     Create a Set-Cookie header without the ‘Set-Cookie’ prefix.

     The return value is usually restricted to ascii as the vast
     majority of values are properly escaped, but that is no guarantee.
     It’s tunneled through latin1 as required by PEP 3333(7).

     The return value is not ASCII safe if the key contains unicode
     characters.  This is technically against the specification but
     happens in the wild.  It’s strongly recommended to not use
     non-ASCII values for the keys.

     Parameters:

        * ‘max_age’ (‘Optional’‘[’‘Union’‘[’datetime.timedelta(8)‘,
          ’int(9)‘]’‘]’) – should be a number of seconds, or ‘None’
          (default) if the cookie should last only as long as the
          client’s browser session.  Additionally ‘timedelta’ objects
          are accepted, too.

        * ‘expires’ (‘Optional’‘[’‘Union’‘[’str(10)‘,
          ’datetime.datetime(11)‘, ’int(12)‘, ’float(13)‘]’‘]’) – should
          be a ‘datetime’ object or unix timestamp.

        * ‘path’ (‘Optional’‘[’str(14)‘]’) – limits the cookie to a
          given path, per default it will span the whole domain.

        * ‘domain’ (‘Optional’‘[’str(15)‘]’) – Use this if you want to
          set a cross-domain cookie.  For example,
          ‘domain=".example.com"’ will set a cookie that is readable by
          the domain ‘www.example.com’, ‘foo.example.com’ etc.
          Otherwise, a cookie will only be readable by the domain that
          set it.

        * ‘secure’ (bool(16)) – The cookie will only be available via
          HTTPS

        * ‘httponly’ (bool(17)) – disallow JavaScript to access the
          cookie.  This is an extension to the cookie standard and
          probably not supported by all browsers.

        * ‘charset’ (str(18)) – the encoding for string values.

        * ‘sync_expires’ (bool(19)) – automatically set expires if
          max_age is defined but expires not.

        * ‘max_size’ (int(20)) – Warn if the final header value exceeds
          this size.  The default, 4093, should be safely supported by
          most browsers(21).  Set to 0 to disable this check.

        * ‘samesite’ (‘Optional’‘[’str(22)‘]’) – Limits the scope of the
          cookie such that it will only be attached to requests if those
          requests are same-site.

        * ‘key’ (str(23)) –

        * ‘value’ (‘Union’‘[’bytes(24)‘, ’str(25)‘]’) –

     Return type: str(26)

     Changed in version 1.0.0: The string ‘'None'’ is accepted for
     ‘samesite’.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/stdtypes.html#bytes

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/stdtypes.html#str

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://www.python.org/dev/peps/pep-3333

   (8)
https://docs.python.org/3/library/datetime.html#datetime.timedelta

   (9) https://docs.python.org/3/library/functions.html#int

   (10) https://docs.python.org/3/library/stdtypes.html#str

   (11)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (12) https://docs.python.org/3/library/functions.html#int

   (13) https://docs.python.org/3/library/functions.html#float

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/stdtypes.html#str

   (16) https://docs.python.org/3/library/functions.html#bool

   (17) https://docs.python.org/3/library/functions.html#bool

   (18) https://docs.python.org/3/library/stdtypes.html#str

   (19) https://docs.python.org/3/library/functions.html#bool

   (20) https://docs.python.org/3/library/functions.html#int

   (21) http://browsercookielimits.squawky.net/

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23) https://docs.python.org/3/library/stdtypes.html#str

   (24) https://docs.python.org/3/library/stdtypes.html#bytes

   (25) https://docs.python.org/3/library/stdtypes.html#str

   (26) https://docs.python.org/3/library/stdtypes.html#str

3.5.5 Conditional Response Helpers
----------------------------------

For conditional responses the following functions might be useful:

 -- Function: werkzeug.http.parse_etags (value)

     Parse an etag header.

     Parameters: ‘value’ (‘Optional’‘[’str(1)‘]’) – the tag header to
     parse

     Returns: an ETags object.

     Return type: werkzeug.datastructures.ETags.

 -- Function: werkzeug.http.quote_etag (etag, weak=False)

     Quote an etag.

     Parameters:

        * ‘etag’ (str(2)) – the etag to quote.

        * ‘weak’ (bool(3)) – set to ‘True’ to tag it “weak”.

     Return type: str(4)

 -- Function: werkzeug.http.unquote_etag (etag)

     Unquote a single etag:

          >>> unquote_etag('W/"bar"')
          ('bar', True)
          >>> unquote_etag('"bar"')
          ('bar', False)

     Parameters: ‘etag’ (‘Optional’‘[’str(5)‘]’) – the etag identifier
     to unquote.

     Returns: a ‘(etag, weak)’ tuple.

     Return type: Union[Tuple[str(6), bool(7)], Tuple[None(8), None(9)]]

 -- Function: werkzeug.http.generate_etag (data)

     Generate an etag for some data.

     Changed in version 2.0: Use SHA-1.  MD5 may not be available in
     some environments.

     Parameters: ‘data’ (bytes(10)) –

     Return type: str(11)

 -- Function: werkzeug.http.is_resource_modified (environ, etag=None,
          data=None, last_modified=None, ignore_if_range=True)

     Convenience method for conditional requests.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – the WSGI environment of the
          request to be checked.

        * ‘etag’ (‘Optional’‘[’str(12)‘]’) – the etag for the response
          for comparison.

        * ‘data’ (‘Optional’‘[’bytes(13)‘]’) – or alternatively the data
          of the response to automatically generate an etag using
          generate_etag().

        * ‘last_modified’
          (‘Optional’‘[’‘Union’‘[’datetime.datetime(14)‘,
          ’str(15)‘]’‘]’) – an optional date of the last modification.

        * ‘ignore_if_range’ (bool(16)) – If ‘False’, ‘If-Range’ header
          will be taken into account.

     Returns: ‘True’ if the resource was modified, otherwise ‘False’.

     Return type: bool(17)

     Changed in version 2.0: SHA-1 is used to generate an etag value for
     the data.  MD5 may not be available in some environments.

     Changed in version 1.0.0: The check is run for methods other than
     ‘GET’ and ‘HEAD’.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/functions.html#bool

   (4) https://docs.python.org/3/library/stdtypes.html#str

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/functions.html#bool

   (8) https://docs.python.org/3/library/constants.html#None

   (9) https://docs.python.org/3/library/constants.html#None

   (10) https://docs.python.org/3/library/stdtypes.html#bytes

   (11) https://docs.python.org/3/library/stdtypes.html#str

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/stdtypes.html#bytes

   (14)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (15) https://docs.python.org/3/library/stdtypes.html#str

   (16) https://docs.python.org/3/library/functions.html#bool

   (17) https://docs.python.org/3/library/functions.html#bool

3.5.6 Constants
---------------

 -- Data: werkzeug.http.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.

3.5.7 Form Data Parsing
-----------------------

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 io import BytesIO
     >>> from werkzeug.formparser import parse_form_data
     >>> data = (
     ...     b'--foo\r\nContent-Disposition: form-data; name="test"\r\n'
     ...     b"\r\nHello World!\r\n--foo--"
     ... )
     >>> environ = {
     ...     "wsgi.input": BytesIO(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()
     b''
     >>> form['test']
     '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
‘create_environ()’ function or the ‘EnvironBuilder’ instead.

 -- Class: werkzeug.formparser.FormDataParser (stream_factory=None,
          charset='utf-8', errors='replace', max_form_memory_size=None,
          max_content_length=None, cls=None, silent=True)

     This class implements parsing of form data for Werkzeug.  By itself
     it can parse multipart and url encoded form data.  It can be
     subclassed and extended but for most mimetypes it is a better idea
     to use the untouched stream and expose it as separate attributes on
     a request object.

     New in version 0.8.

     Parameters:

        * ‘stream_factory’ (‘Optional’‘[’‘TStreamFactory’‘]’) – An
          optional callable that returns a new read and writeable file
          descriptor.  This callable works the same as
          ‘Response._get_file_stream()’.

        * ‘charset’ (str(1)) – The character set for URL and url encoded
          form data.

        * ‘errors’ (str(2)) – The encoding error behavior.

        * ‘max_form_memory_size’ (‘Optional’‘[’int(3)‘]’) – the maximum
          number of bytes to be accepted for in-memory stored form data.
          If the data exceeds the value specified an
          ‘RequestEntityTooLarge’ exception is raised.

        * ‘max_content_length’ (‘Optional’‘[’int(4)‘]’) – If this is
          provided and the transmitted data is longer than this value an
          ‘RequestEntityTooLarge’ exception is raised.

        * ‘cls’ (‘Optional’‘[’‘Type’‘[’
          werkzeug.datastructures.MultiDict.‘]’‘]’) – an optional
          dict class to use.  If this is not specified or ‘None’ the
          default ‘MultiDict’ is used.

        * ‘silent’ (bool(5)) – If set to False parsing errors will not
          be caught.

     Return type: None(6)

 -- Function: werkzeug.formparser.parse_form_data (environ,
          stream_factory=None, charset='utf-8', errors='replace',
          max_form_memory_size=None, max_content_length=None, cls=None,
          silent=True)

     Parse the form data in the environ and return it as tuple in the
     form ‘(stream, form, files)’.  You should only call this method if
     the transport method is ‘POST’, ‘PUT’, or ‘PATCH’.

     If the mimetype of the data transmitted is ‘multipart/form-data’
     the files multidict will be filled with ‘FileStorage’ objects.  If
     the mimetype is unknown the input stream is wrapped and returned as
     first argument, else the stream is empty.

     This is a shortcut for the common usage of FormDataParser.

     Have a look at Dealing with Request Data for more
     details.

     New in version 0.5.1: The optional ‘silent’ flag was added.

     New in version 0.5: The ‘max_form_memory_size’,
     ‘max_content_length’ and ‘cls’ parameters were added.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – the WSGI environment to be
          used for parsing.

        * ‘stream_factory’ (‘Optional’‘[’‘TStreamFactory’‘]’) – An
          optional callable that returns a new read and writeable file
          descriptor.  This callable works the same as
          ‘Response._get_file_stream()’.

        * ‘charset’ (str(7)) – The character set for URL and url encoded
          form data.

        * ‘errors’ (str(8)) – The encoding error behavior.

        * ‘max_form_memory_size’ (‘Optional’‘[’int(9)‘]’) – the maximum
          number of bytes to be accepted for in-memory stored form data.
          If the data exceeds the value specified an
          ‘RequestEntityTooLarge’ exception is raised.

        * ‘max_content_length’ (‘Optional’‘[’int(10)‘]’) – If this is
          provided and the transmitted data is longer than this value an
          ‘RequestEntityTooLarge’ exception is raised.

        * ‘cls’ (‘Optional’‘[’‘Type’‘[’
          werkzeug.datastructures.MultiDict.‘]’‘]’) – an optional
          dict class to use.  If this is not specified or ‘None’ the
          default ‘MultiDict’ is used.

        * ‘silent’ (bool(11)) – If set to False parsing errors will not
          be caught.

     Returns: A tuple in the form ‘(stream, form, files)’.

     Return type: t_parse_result

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/functions.html#int

   (4) https://docs.python.org/3/library/functions.html#int

   (5) https://docs.python.org/3/library/functions.html#bool

   (6) https://docs.python.org/3/library/constants.html#None

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/stdtypes.html#str

   (9) https://docs.python.org/3/library/functions.html#int

   (10) https://docs.python.org/3/library/functions.html#int

   (11) https://docs.python.org/3/library/functions.html#bool

3.6 Data Structures
===================

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.

3.6.1 General Purpose
---------------------

Changed in version 0.6: The general purpose classes are now pickleable
in each protocol as long as the contained objects are pickleable.  This
means that the FileMultiDict won’t be pickleable as soon as
it contains a file.

 -- Class: werkzeug.datastructures.TypeConversionDict

     Works like a regular dict but the get() method can
     perform type conversions.  MultiDict and
     CombinedMultiDict are subclasses of this class and provide the
     same feature.

     New in version 0.5.

      -- Method: get (key, default=None, type=None)

          Return the default value if the requested data doesn’t exist.
          If ‘type’ is provided and is a callable it should convert the
          value, return it or raise a ValueError(1) if that is not
          possible.  In this case the function will return the default
          as if the value was not found:

               >>> d = TypeConversionDict(foo='42', bar='blub')
               >>> d.get('foo', type=int)
               42
               >>> d.get('bar', -1, type=int)
               -1

          Parameters:

             * ‘key’ – The key to be looked up.

             * ‘default’ – The default value to be returned if the key
               can’t be looked up.  If not further specified ‘None’ is
               returned.

             * ‘type’ – A callable that is used to cast the value in the
               MultiDict.  If a ValueError(2) is raised by
               this callable the default value is returned.

 -- Class: werkzeug.datastructures.ImmutableTypeConversionDict

     Works like a TypeConversionDict but does not support
     modifications.

     New in version 0.5.

      -- Method: copy ()

          Return a shallow mutable copy of this object.  Keep in mind
          that the standard library’s copy() function is a
          no-op for this class like for any other python immutable type
          (eg: tuple(3)).

 -- Class: werkzeug.datastructures.MultiDict (mapping=None)

     A MultiDict is a dictionary subclass customized to deal
     with multiple values for the same key which is for example used by
     the parsing functions in the wrappers.  This is necessary because
     some HTML form elements pass multiple values for the same key.

     MultiDict implements all standard dictionary methods.
     Internally, it saves all values for a key as a list, but the
     standard dict access methods will only return the first value for a
     key.  If you want to gain access to the other values, too, you have
     to use the ‘list’ methods as explained below.

     Basic Usage:

          >>> d = MultiDict([('a', 'b'), ('a', 'c')])
          >>> d
          MultiDict([('a', 'b'), ('a', 'c')])
          >>> d['a']
          'b'
          >>> d.getlist('a')
          ['b', 'c']
          >>> 'a' in d
          True

     It behaves like a normal dict thus all dict functions will only
     return the first value when multiple values for one key are found.

     From Werkzeug 0.3 onwards, the ‘KeyError’ raised by this class is
     also a subclass of the ‘BadRequest’ HTTP exception and will render
     a page for a ‘400 BAD REQUEST’ if caught in a catch-all for HTTP
     exceptions.

     A MultiDict can be constructed from an iterable of
     ‘(key, value)’ tuples, a dict, a MultiDict or from
     Werkzeug 0.2 onwards some keyword parameters.

     Parameters: ‘mapping’ – the initial value for the MultiDict.
     Either a regular dict, an iterable of ‘(key, value)’ tuples or
     ‘None’.

      -- Method: add (key, value)

          Adds a new value for the key.

          New in version 0.6.

          Parameters:

             * ‘key’ – the key for the value.

             * ‘value’ – the value to add.

      -- Method: clear () -> None. Remove all items from D.

      -- Method: copy ()

          Return a shallow copy of this object.

      -- Method: deepcopy (memo=None)

          Return a deep copy of this object.

      -- Method: fromkeys (value=None, /)

          Create a new dictionary with keys from iterable and values set
          to value.

      -- Method: get (key, default=None, type=None)

          Return the default value if the requested data doesn’t exist.
          If ‘type’ is provided and is a callable it should convert the
          value, return it or raise a ValueError(4) if that is not
          possible.  In this case the function will return the default
          as if the value was not found:

               >>> d = TypeConversionDict(foo='42', bar='blub')
               >>> d.get('foo', type=int)
               42
               >>> d.get('bar', -1, type=int)
               -1

          Parameters:

             * ‘key’ – The key to be looked up.

             * ‘default’ – The default value to be returned if the key
               can’t be looked up.  If not further specified ‘None’ is
               returned.

             * ‘type’ – A callable that is used to cast the value in the
               MultiDict.  If a ValueError(5) is raised by
               this callable the default value is returned.

      -- Method: getlist (key, type=None)

          Return the list of items for a given key.  If that key is not
          in the ‘MultiDict’, the return value will be an empty list.
          Just like ‘get’, ‘getlist’ accepts a ‘type’ parameter.  All
          items will be converted with the callable defined there.

          Parameters:

             * ‘key’ – The key to be looked up.

             * ‘type’ – A callable that is used to cast the value in the
               MultiDict.  If a ValueError(6) is raised by
               this callable the value will be removed from the list.

          Returns: a list(7) of all the values for the key.

      -- Method: items (multi=False)

          Return an iterator of ‘(key, value)’ pairs.

          Parameters: ‘multi’ – If set to ‘True’ the iterator returned
          will have a pair for each value of each key.  Otherwise it
          will only contain pairs for the first value of each key.

      -- Method: keys () -> a set-like object providing a view on D's
               keys

      -- Method: lists ()

          Return a iterator of ‘(key, values)’ pairs, where values is
          the list of all values associated with the key.

      -- Method: listvalues ()

          Return an iterator of all values associated with a key.
          Zipping keys() and this is the same as calling
          lists().:

               >>> d = MultiDict({"foo": [1, 2, 3]})
               >>> zip(d.keys(), d.listvalues()) == d.lists()
               True

      -- Method: pop (key, default=no value)

          Pop the first item for a list on the dict.  Afterwards the key
          is removed from the dict, so additional values are discarded:

               >>> d = MultiDict({"foo": [1, 2, 3]})
               >>> d.pop("foo")
               1
               >>> "foo" in d
               False

          Parameters:

             * ‘key’ – the key to pop.

             * ‘default’ – if provided the value to return if the key
               was not in the dictionary.

      -- Method: popitem ()

          Pop an item from the dict.

      -- Method: popitemlist ()

          Pop a ‘(key, list)’ tuple from the dict.

      -- Method: poplist (key)

          Pop the list for a key from the dict.  If the key is not in
          the dict an empty list is returned.

          Changed in version 0.5: If the key does no longer exist a list
          is returned instead of raising an error.

      -- Method: setdefault (key, default=None)

          Returns the value for the key if it is in the dict, otherwise
          it returns ‘default’ and sets that value for ‘key’.

          Parameters:

             * ‘key’ – The key to be looked up.

             * ‘default’ – The default value to be returned if the key
               is not in the dict.  If not further specified it’s
               ‘None’.

      -- Method: setlist (key, new_list)

          Remove the old values for a key and add new ones.  Note that
          the list you pass the values in will be shallow-copied before
          it is inserted in the dictionary.

               >>> d = MultiDict()
               >>> d.setlist('foo', ['1', '2'])
               >>> d['foo']
               '1'
               >>> d.getlist('foo')
               ['1', '2']

          Parameters:

             * ‘key’ – The key for which the values are set.

             * ‘new_list’ – An iterable with the new values for the key.
               Old values are removed first.

      -- Method: setlistdefault (key, default_list=None)

          Like ‘setdefault’ but sets multiple values.  The list returned
          is not a copy, but the list that is actually used internally.
          This means that you can put new values into the dict by
          appending items to the list:

               >>> d = MultiDict({"foo": 1})
               >>> d.setlistdefault("foo").extend([2, 3])
               >>> d.getlist("foo")
               [1, 2, 3]

          Parameters:

             * ‘key’ – The key to be looked up.

             * ‘default_list’ – An iterable of default values.  It is
               either copied (in case it was a list) or converted into a
               list before returned.

          Returns: a list(8)

      -- Method: to_dict (flat=True)

          Return the contents as regular dict.  If ‘flat’ is ‘True’ the
          returned dict will only have the first item present, if ‘flat’
          is ‘False’ all values will be returned as lists.

          Parameters: ‘flat’ – If set to ‘False’ the dict returned will
          have lists with all the values in it.  Otherwise it will only
          contain the first value for each key.

          Returns: a dict(9)

      -- Method: update (mapping)

          update() extends rather than replaces existing key lists:

               >>> a = MultiDict({'x': 1})
               >>> b = MultiDict({'x': 2, 'y': 3})
               >>> a.update(b)
               >>> a
               MultiDict([('y', 3), ('x', 1), ('x', 2)])

          If the value list for a key in ‘other_dict’ is empty, no new
          values will be added to the dict and the key will not be
          created:

               >>> x = {'empty_list': []}
               >>> y = MultiDict()
               >>> y.update(x)
               >>> y
               MultiDict([])

      -- Method: values ()

          Returns an iterator of the first value on every key’s value
          list.

 -- Class: werkzeug.datastructures.OrderedMultiDict (mapping=None)

     Works like a regular MultiDict but preserves the order
     of the fields.  To convert the ordered multi dict into a list you
     can use the ‘items()’ method and pass it ‘multi=True’.

     In general an OrderedMultiDict is an order of magnitude
     slower than a MultiDict.

          note: Due to a limitation in Python you cannot convert an
          ordered multi dict into a regular dict by using
          ‘dict(multidict)’.  Instead you have to use the ‘to_dict()’
          method, otherwise the internal bucket objects are exposed.

 -- Class: werkzeug.datastructures.ImmutableMultiDict (mapping=None)

     An immutable MultiDict.

     New in version 0.5.

      -- Method: copy ()

          Return a shallow mutable copy of this object.  Keep in mind
          that the standard library’s copy() function is a
          no-op for this class like for any other python immutable type
          (eg: tuple(10)).

 -- Class: werkzeug.datastructures.ImmutableOrderedMultiDict
          (mapping=None)

     An immutable OrderedMultiDict.

     New in version 0.6.

      -- Method: copy ()

          Return a shallow mutable copy of this object.  Keep in mind
          that the standard library’s copy() function is a
          no-op for this class like for any other python immutable type
          (eg: tuple(11)).

 -- Class: werkzeug.datastructures.CombinedMultiDict (dicts=None)

     A read only MultiDict that you can pass multiple
     MultiDict instances as sequence and it will combine the return
     values of all wrapped dicts:

          >>> from werkzeug.datastructures import CombinedMultiDict, MultiDict
          >>> post = MultiDict([('foo', 'bar')])
          >>> get = MultiDict([('blub', 'blah')])
          >>> combined = CombinedMultiDict([get, post])
          >>> combined['foo']
          'bar'
          >>> combined['blub']
          'blah'

     This works for all read operations and will raise a ‘TypeError’ for
     methods that usually change data which isn’t possible.

     From Werkzeug 0.3 onwards, the ‘KeyError’ raised by this class is
     also a subclass of the ‘BadRequest’ HTTP exception and will render
     a page for a ‘400 BAD REQUEST’ if caught in a catch-all for HTTP
     exceptions.

 -- Class: werkzeug.datastructures.ImmutableDict

     An immutable dict(12).

     New in version 0.5.

      -- Method: copy ()

          Return a shallow mutable copy of this object.  Keep in mind
          that the standard library’s copy() function is a
          no-op for this class like for any other python immutable type
          (eg: tuple(13)).

 -- Class: werkzeug.datastructures.ImmutableList (iterable=(), /)

     An immutable list(14).

     New in version 0.5.

     Private:

 -- Class: werkzeug.datastructures.FileMultiDict (mapping=None)

     A special MultiDict that has convenience methods to add
     files to it.  This is used for ‘EnvironBuilder’ and generally
     useful for unittesting.

     New in version 0.5.

      -- Method: add_file (name, file, filename=None, content_type=None)

          Adds a new file to the dict.  ‘file’ can be a file name or a
          ‘file’-like or a FileStorage object.

          Parameters:

             * ‘name’ – the name of the field.

             * ‘file’ – a filename or ‘file’-like object

             * ‘filename’ – an optional filename

             * ‘content_type’ – an optional content type

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/exceptions.html#ValueError

   (2) https://docs.python.org/3/library/exceptions.html#ValueError

   (3) https://docs.python.org/3/library/stdtypes.html#tuple

   (4) https://docs.python.org/3/library/exceptions.html#ValueError

   (5) https://docs.python.org/3/library/exceptions.html#ValueError

   (6) https://docs.python.org/3/library/exceptions.html#ValueError

   (7) https://docs.python.org/3/library/stdtypes.html#list

   (8) https://docs.python.org/3/library/stdtypes.html#list

   (9) https://docs.python.org/3/library/stdtypes.html#dict

   (10) https://docs.python.org/3/library/stdtypes.html#tuple

   (11) https://docs.python.org/3/library/stdtypes.html#tuple

   (12) https://docs.python.org/3/library/stdtypes.html#dict

   (13) https://docs.python.org/3/library/stdtypes.html#tuple

   (14) https://docs.python.org/3/library/stdtypes.html#list

3.6.2 HTTP Related
------------------

 -- Class: werkzeug.datastructures.Headers ([defaults])

     An object that stores some headers.  It has a dict-like interface,
     but is ordered, can store the same key multiple times, and
     iterating yields ‘(key, value)’ pairs instead of only keys.

     This data structure is useful if you want a nicer way to handle
     WSGI headers which are stored as tuples in a list.

     From Werkzeug 0.3 onwards, the KeyError(1) raised by this class is
     also a subclass of the ‘BadRequest’ HTTP exception and will render
     a page for a ‘400 BAD REQUEST’ if caught in a catch-all for HTTP
     exceptions.

     Headers is mostly compatible with the Python
     wsgiref.headers.Headers(2) class, with the exception of
     ‘__getitem__’.  wsgiref(3) will return ‘None’ for
     ‘headers['missing']’, whereas Headers will raise a
     KeyError(4).

     To create a new Headers object pass it a list or dict of
     headers which are used as default values.  This does not reuse the
     list passed to the constructor for internal usage.

     Parameters: ‘defaults’ – The list of default values for the
     Headers.

     Changed in version 0.9: This data structure now stores unicode
     values similar to how the multi dicts do it.  The main difference
     is that bytes can be set as well which will automatically be latin1
     decoded.

     Changed in version 0.9: The ‘linked()’ function was removed without
     replacement as it was an API that does not support the changes to
     the encoding model.

      -- Method: add (_key, _value, **kw)

          Add a new header tuple to the list.

          Keyword arguments can specify additional parameters for the
          header value, with underscores converted to dashes:

               >>> d = Headers()
               >>> d.add('Content-Type', 'text/plain')
               >>> d.add('Content-Disposition', 'attachment', filename='foo.png')

          The keyword argument dumping uses ‘dump_options_header()’
          behind the scenes.

          New in version 0.4.1: keyword arguments were added for
          wsgiref(5) compatibility.

      -- Method: add_header (_key, _value, **_kw)

          Add a new header tuple to the list.

          An alias for add() for compatibility with the
          wsgiref(6) add_header()(7) method.

      -- Method: clear ()

          Clears all headers.

      -- Method: extend (*args, **kwargs)

          Extend headers in this object with items from another object
          containing header items as well as keyword arguments.

          To replace existing keys instead of extending, use
          update() instead.

          If provided, the first argument can be another Headers
          object, a MultiDict, dict(8), or iterable of
          pairs.

          Changed in version 1.0: Support MultiDict.  Allow
          passing ‘kwargs’.

      -- Method: get (key, default=None, type=None, as_bytes=False)

          Return the default value if the requested data doesn’t exist.
          If ‘type’ is provided and is a callable it should convert the
          value, return it or raise a ValueError(9) if that is not
          possible.  In this case the function will return the default
          as if the value was not found:

               >>> d = Headers([('Content-Length', '42')])
               >>> d.get('Content-Length', type=int)
               42

          New in version 0.9: Added support for ‘as_bytes’.

          Parameters:

             * ‘key’ – The key to be looked up.

             * ‘default’ – The default value to be returned if the key
               can’t be looked up.  If not further specified ‘None’ is
               returned.

             * ‘type’ – A callable that is used to cast the value in the
               Headers.  If a ValueError(10) is raised by this
               callable the default value is returned.

             * ‘as_bytes’ – return bytes instead of strings.

      -- Method: get_all (name)

          Return a list of all the values for the named field.

          This method is compatible with the wsgiref(11) get_all()(12)
          method.

      -- Method: getlist (key, type=None, as_bytes=False)

          Return the list of items for a given key.  If that key is not
          in the Headers, the return value will be an empty
          list.  Just like get(), getlist().
          accepts a ‘type’ parameter.  All items will be converted with
          the callable defined there.

          New in version 0.9: Added support for ‘as_bytes’.

          Parameters:

             * ‘key’ – The key to be looked up.

             * ‘type’ – A callable that is used to cast the value in the
               Headers.  If a ValueError(13) is raised by this
               callable the value will be removed from the list.

             * ‘as_bytes’ – return bytes instead of strings.

          Returns: a list(14) of all the values for the key.

      -- Method: has_key (key)

          Deprecated since version 2.0: Will be removed in Werkzeug 2.1.
          Use ‘key in data’ instead.

      -- Method: pop (key=None, default=no value)

          Removes and returns a key or index.

          Parameters: ‘key’ – The key to be popped.  If this is an
          integer the item at that position is removed, if it’s a string
          the value for that key is.  If the key is omitted or ‘None’
          the last item is removed.

          Returns: an item.

      -- Method: popitem ()

          Removes a key or index and returns a (key, value) item.

      -- Method: remove (key)

          Remove a key.

          Parameters: ‘key’ – The key to be removed.

      -- Method: set (_key, _value, **kw)

          Remove all header tuples for ‘key’ and add a new one.  The
          newly added key either appears at the end of the list if there
          was no entry or replaces the first one.

          Keyword arguments can specify additional parameters for the
          header value, with underscores converted to dashes.  See
          add() for more information.

          Changed in version 0.6.1: set() now accepts the
          same arguments as add().

          Parameters:

             * ‘key’ – The key to be inserted.

             * ‘value’ – The value to be inserted.

      -- Method: setdefault (key, default)

          Return the first value for the key if it is in the headers,
          otherwise set the header to the value given by ‘default’ and
          return that.

          Parameters:

             * ‘key’ – The header key to get.

             * ‘default’ – The value to set for the key if it is not in
               the headers.

      -- Method: setlist (key, values)

          Remove any existing values for a header and add new ones.

          Parameters:

             * ‘key’ – The header key to set.

             * ‘values’ – An iterable of values to set for the key.

          New in version 1.0.

      -- Method: setlistdefault (key, default)

          Return the list of values for the key if it is in the headers,
          otherwise set the header to the list of values given by
          ‘default’ and return that.

          Unlike MultiDict.setlistdefault(), modifying the
          returned list will not affect the headers.

          Parameters:

             * ‘key’ – The header key to get.

             * ‘default’ – An iterable of values to set for the key if
               it is not in the headers.

          New in version 1.0.

      -- Method: to_wsgi_list ()

          Convert the headers into a list suitable for WSGI.

          Returns: list

      -- Method: update (*args, **kwargs)

          Replace headers in this object with items from another headers
          object and keyword arguments.

          To extend existing keys instead of replacing, use
          extend() instead.

          If provided, the first argument can be another Headers
          object, a MultiDict, dict(15), or iterable of
          pairs.

          New in version 1.0.

 -- Class: werkzeug.datastructures.EnvironHeaders (environ)

     Read only version of the headers from a WSGI environment.  This
     provides the same interface as ‘Headers’ and is constructed from a
     WSGI environment.

     From Werkzeug 0.3 onwards, the ‘KeyError’ raised by this class is
     also a subclass of the ‘BadRequest’ HTTP exception and will render
     a page for a ‘400 BAD REQUEST’ if caught in a catch-all for HTTP
     exceptions.

 -- Class: werkzeug.datastructures.HeaderSet (headers=None,
          on_update=None)

     Similar to the ETags class this implements a set-like
     structure.  Unlike ETags this is case insensitive and
     used for vary, allow, and content-language headers.

     If not constructed using the ‘parse_set_header()’ function the
     instantiation works like this:

          >>> hs = HeaderSet(['foo', 'bar', 'baz'])
          >>> hs
          HeaderSet(['foo', 'bar', 'baz'])

      -- Method: add (header)

          Add a new header to the set.

      -- Method: as_set (preserve_casing=False)

          Return the set as real python set type.  When calling this,
          all the items are converted to lowercase and the ordering is
          lost.

          Parameters: ‘preserve_casing’ – if set to ‘True’ the items in
          the set returned will have the original case like in the
          HeaderSet, otherwise they will be lowercase.

      -- Method: clear ()

          Clear the set.

      -- Method: discard (header)

          Like remove() but ignores errors.

          Parameters: ‘header’ – the header to be discarded.

      -- Method: find (header)

          Return the index of the header in the set or return -1 if not
          found.

          Parameters: ‘header’ – the header to be looked up.

      -- Method: index (header)

          Return the index of the header in the set or raise an
          IndexError(16).

          Parameters: ‘header’ – the header to be looked up.

      -- Method: remove (header)

          Remove a header from the set.  This raises an KeyError(17) if
          the header is not in the set.

          Changed in version 0.5: In older versions a IndexError(18) was
          raised instead of a KeyError(19) if the object was missing.

          Parameters: ‘header’ – the header to be removed.

      -- Method: to_header ()

          Convert the header set into an HTTP header string.

      -- Method: update (iterable)

          Add all the headers from the iterable to the set.

          Parameters: ‘iterable’ – updates the set with the items from
          the iterable.

 -- Class: werkzeug.datastructures.Accept (values=())

     An Accept object is just a list subclass for lists of
     ‘(value, quality)’ tuples.  It is automatically sorted by
     specificity and quality.

     All Accept objects work similar to a list but provide
     extra functionality for working with the data.  Containment checks
     are normalized to the rules of that header:

          >>> a = CharsetAccept([('ISO-8859-1', 1), ('utf-8', 0.7)])
          >>> a.best
          'ISO-8859-1'
          >>> 'iso-8859-1' in a
          True
          >>> 'UTF8' in a
          True
          >>> 'utf7' in a
          False

     To get the quality for an item you can use normal item lookup:

          >>> print a['utf-8']
          0.7
          >>> a['utf7']
          0

     Changed in version 1.0.0: Accept internal values are no
     longer ordered alphabetically for equal quality tags.  Instead the
     initial order is preserved.

     Changed in version 0.5: Accept objects are forced
     immutable now.

      -- Property: best

          The best match as value.

      -- Method: best_match (matches, default=None)

          Returns the best match from a list of possible matches based
          on the specificity and quality of the client.  If two items
          have the same quality and specificity, the one is returned
          that comes first.

          Parameters:

             * ‘matches’ – a list of matches to check for

             * ‘default’ – the value that is returned if none match

      -- Method: find (key)

          Get the position of an entry or return -1.

          Parameters: ‘key’ – The key to be looked up.

      -- Method: index (key)

          Get the position of an entry or raise ValueError(20).

          Parameters: ‘key’ – The key to be looked up.

          Changed in version 0.5: This used to raise IndexError(21),
          which was inconsistent with the list API.

      -- Method: quality (key)

          Returns the quality of the key.

          New in version 0.6: In previous versions you had to use the
          item-lookup syntax (eg: ‘obj[key]’ instead of
          ‘obj.quality(key)’)

      -- Method: to_header ()

          Convert the header set into an HTTP header string.

      -- Method: values ()

          Iterate over all values.

 -- Class: werkzeug.datastructures.MIMEAccept (values=())

     Like Accept but with special methods and behavior for
     mimetypes.

      -- Property: accept_html

          True if this object accepts HTML.

      -- Property: accept_json

          True if this object accepts JSON.

      -- Property: accept_xhtml

          True if this object accepts XHTML.

 -- Class: werkzeug.datastructures.CharsetAccept (values=())

     Like Accept but with normalization for charsets.

 -- Class: werkzeug.datastructures.LanguageAccept (values=())

     Like Accept but with normalization for language tags.

 -- Class: werkzeug.datastructures.RequestCacheControl (values=(),
          on_update=None)

     A cache control for requests.  This is immutable and gives access
     to all the request-relevant cache control headers.

     To get a header of the RequestCacheControl object again
     you can convert the object into a string or call the ‘to_header()’
     method.  If you plan to subclass it and add your own items have a
     look at the sourcecode for that class.

     New in version 0.5: In previous versions a ‘CacheControl’ class
     existed that was used both for request and response.

      -- Attribute: no_cache

          accessor for ‘no-cache’

      -- Attribute: no_store

          accessor for ‘no-store’

      -- Attribute: max_age

          accessor for ‘max-age’

      -- Attribute: no_transform

          accessor for ‘no-transform’

      -- Property: max_stale

          accessor for ‘max-stale’

      -- Property: min_fresh

          accessor for ‘min-fresh’

      -- Property: only_if_cached

          accessor for ‘only-if-cached’

 -- Class: werkzeug.datastructures.ResponseCacheControl (values=(),
          on_update=None)

     A cache control for responses.  Unlike RequestCacheControl
     this is mutable and gives access to response-relevant cache
     control headers.

     To get a header of the ResponseCacheControl object
     again you can convert the object into a string or call the
     ‘to_header()’ method.  If you plan to subclass it and add your own
     items have a look at the sourcecode for that class.

     New in version 0.5: In previous versions a ‘CacheControl’ class
     existed that was used both for request and response.

      -- Attribute: no_cache

          accessor for ‘no-cache’

      -- Attribute: no_store

          accessor for ‘no-store’

      -- Attribute: max_age

          accessor for ‘max-age’

      -- Attribute: no_transform

          accessor for ‘no-transform’

      -- Property: immutable

          accessor for ‘immutable’

      -- Property: must_revalidate

          accessor for ‘must-revalidate’

      -- Property: private

          accessor for ‘private’

      -- Property: proxy_revalidate

          accessor for ‘proxy-revalidate’

      -- Property: public

          accessor for ‘public’

      -- Property: s_maxage

          accessor for ‘s-maxage’

 -- Class: werkzeug.datastructures.ETags (strong_etags=None,
          weak_etags=None, star_tag=False)

     A set that can be used to check if one etag is present in a
     collection of etags.

      -- Method: as_set (include_weak=False)

          Convert the ‘ETags’ object into a python set.  Per default all
          the weak etags are not part of this set.

      -- Method: contains (etag)

          Check if an etag is part of the set ignoring weak tags.  It is
          also possible to use the ‘in’ operator.

      -- Method: contains_raw (etag)

          When passed a quoted tag it will check if this tag is part of
          the set.  If the tag is weak it is checked against weak and
          strong tags, otherwise strong only.

      -- Method: contains_weak (etag)

          Check if an etag is part of the set including weak and strong
          tags.

      -- Method: is_strong (etag)

          Check if an etag is strong.

      -- Method: is_weak (etag)

          Check if an etag is weak.

      -- Method: to_header ()

          Convert the etags set into a HTTP header string.

 -- Class: werkzeug.datastructures.Authorization (auth_type, data=None)

     Represents an ‘Authorization’ header sent by the client.

     This is returned by parse_authorization_header().  It
     can be useful to create the object manually to pass to the test
     Client.

     Changed in version 0.5: This object became immutable.

      -- Property: cnonce

          If the server sent a qop-header in the ‘WWW-Authenticate’
          header, the client has to provide this value for HTTP digest
          auth.  See the RFC for more details.

      -- Property: nc

          The nonce count value transmitted by clients if a qop-header
          is also transmitted.  HTTP digest auth only.

      -- Property: nonce

          The nonce the server sent for digest auth, sent back by the
          client.  A nonce should be unique for every 401 response for
          HTTP digest auth.

      -- Property: opaque

          The opaque header from the server returned unchanged by the
          client.  It is recommended that this string be base64 or
          hexadecimal data.  Digest auth only.

      -- Property: password

          When the authentication type is basic this is the password
          transmitted by the client, else ‘None’.

      -- Property: qop

          Indicates what “quality of protection” the client has applied
          to the message for HTTP digest auth.  Note that this is a
          single token, not a quoted list of alternatives as in
          WWW-Authenticate.

      -- Property: realm

          This is the server realm sent back for HTTP digest auth.

      -- Property: response

          A string of 32 hex digits computed as defined in RFC 2617,
          which proves that the user knows a password.  Digest auth
          only.

      -- Method: to_header ()

          Convert to a string value for an ‘Authorization’ header.

          New in version 2.0: Added to support passing authorization to
          the test client.

      -- Property: uri

          The URI from Request-URI of the Request-Line; duplicated
          because proxies are allowed to change the Request-Line in
          transit.  HTTP digest auth only.

      -- Property: username

          The username transmitted.  This is set for both basic and
          digest auth all the time.

 -- Class: werkzeug.datastructures.WWWAuthenticate (auth_type=None,
          values=None, on_update=None)

     Provides simple access to ‘WWW-Authenticate’ headers.

      -- Property: algorithm

          A string indicating a pair of algorithms used to produce the
          digest and a checksum.  If this is not present it is assumed
          to be “MD5”.  If the algorithm is not understood, the
          challenge should be ignored (and a different one used, if
          there is more than one).

      -- Method: static auth_property (name, doc=None)

          A static helper function for Authentication subclasses to add
          extra authentication system properties onto a class:

               class FooAuthenticate(WWWAuthenticate):
                   special_realm = auth_property('special_realm')

          For more information have a look at the sourcecode to see how
          the regular properties (see realm etc.)  are
          implemented.

      -- Property: domain

          A list of URIs that define the protection space.  If a URI is
          an absolute path, it is relative to the canonical root URL of
          the server being accessed.

      -- Property: nonce

          A server-specified data string which should be uniquely
          generated each time a 401 response is made.  It is recommended
          that this string be base64 or hexadecimal data.

      -- Property: opaque

          A string of data, specified by the server, which should be
          returned by the client unchanged in the Authorization header
          of subsequent requests with URIs in the same protection space.
          It is recommended that this string be base64 or hexadecimal
          data.

      -- Property: qop

          A set of quality-of-privacy directives such as auth and
          auth-int.

      -- Property: realm

          A string to be displayed to users so they know which username
          and password to use.  This string should contain at least the
          name of the host performing the authentication and might
          additionally indicate the collection of users who might have
          access.

      -- Method: set_basic (realm='authentication required')

          Clear the auth info and enable basic auth.

      -- Method: set_digest (realm, nonce, qop=('auth',), opaque=None,
               algorithm=None, stale=False)

          Clear the auth info and enable digest auth.

      -- Property: stale

          A flag, indicating that the previous request from the client
          was rejected because the nonce value was stale.

      -- Method: to_header ()

          Convert the stored values into a WWW-Authenticate header.

      -- Property: type

          The type of the auth mechanism.  HTTP currently specifies
          ‘Basic’ and ‘Digest’.

 -- Class: werkzeug.datastructures.IfRange (etag=None, date=None)

     Very simple object that represents the ‘If-Range’ header in parsed
     form.  It will either have neither a etag or date or one of either
     but never both.

     New in version 0.7.

      -- Attribute: date

          The date in parsed format or ‘None’.

      -- Attribute: etag

          The etag parsed and unquoted.  Ranges always operate on strong
          etags so the weakness information is not necessary.

      -- Method: to_header ()

          Converts the object back into an HTTP header.

 -- Class: werkzeug.datastructures.Range (units, ranges)

     Represents a ‘Range’ header.  All methods only support only bytes
     as the unit.  Stores a list of ranges if given, but the methods
     only work if only one range is provided.

     Raises: ValueError(22) – If the ranges provided are invalid.

     Changed in version 0.15: The ranges passed in are validated.

     New in version 0.7.

      -- Method: make_content_range (length)

          Creates a ContentRange object from the current
          range and given content length.

      -- Method: range_for_length (length)

          If the range is for bytes, the length is not None and there is
          exactly one range and it is satisfiable it returns a ‘(start,
          stop)’ tuple, otherwise ‘None’.

      -- Attribute: ranges

          A list of ‘(begin, end)’ tuples for the range header provided.
          The ranges are non-inclusive.

      -- Method: to_content_range_header (length)

          Converts the object into ‘Content-Range’ HTTP header, based on
          given length

      -- Method: to_header ()

          Converts the object back into an HTTP header.

      -- Attribute: units

          The units of this range.  Usually “bytes”.

 -- Class: werkzeug.datastructures.ContentRange (units, start, stop,
          length=None, on_update=None)

     Represents the content range header.

     New in version 0.7.

      -- Property: length

          The length of the range or ‘None’.

      -- Method: set (start, stop, length=None, units='bytes')

          Simple method to update the ranges.

      -- Property: start

          The start point of the range or ‘None’.

      -- Property: stop

          The stop point of the range (non-inclusive) or ‘None’.  Can
          only be ‘None’ if also start is ‘None’.

      -- Property: units

          The units to use, usually “bytes”

      -- Method: unset ()

          Sets the units to ‘None’ which indicates that the header
          should no longer be used.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/exceptions.html#KeyError

   (2)
https://docs.python.org/3/library/wsgiref.html#wsgiref.headers.Headers

   (3) https://docs.python.org/3/library/wsgiref.html#module-wsgiref

   (4) https://docs.python.org/3/library/exceptions.html#KeyError

   (5) https://docs.python.org/3/library/wsgiref.html#module-wsgiref

   (6) https://docs.python.org/3/library/wsgiref.html#module-wsgiref

   (7)
https://docs.python.org/3/library/wsgiref.html#wsgiref.headers.Headers.add_header

   (8) https://docs.python.org/3/library/stdtypes.html#dict

   (9) https://docs.python.org/3/library/exceptions.html#ValueError

   (10) https://docs.python.org/3/library/exceptions.html#ValueError

   (11) https://docs.python.org/3/library/wsgiref.html#module-wsgiref

   (12)
https://docs.python.org/3/library/wsgiref.html#wsgiref.headers.Headers.get_all

   (13) https://docs.python.org/3/library/exceptions.html#ValueError

   (14) https://docs.python.org/3/library/stdtypes.html#list

   (15) https://docs.python.org/3/library/stdtypes.html#dict

   (16) https://docs.python.org/3/library/exceptions.html#IndexError

   (17) https://docs.python.org/3/library/exceptions.html#KeyError

   (18) https://docs.python.org/3/library/exceptions.html#IndexError

   (19) https://docs.python.org/3/library/exceptions.html#KeyError

   (20) https://docs.python.org/3/library/exceptions.html#ValueError

   (21) https://docs.python.org/3/library/exceptions.html#IndexError

   (22) https://docs.python.org/3/library/exceptions.html#ValueError

3.6.3 Others
------------

 -- Class: werkzeug.datastructures.FileStorage (stream=None,
          filename=None, name=None, content_type=None,
          content_length=None, headers=None)

     The FileStorage class is a thin wrapper over incoming
     files.  It is used by the request object to represent uploaded
     files.  All the attributes of the wrapper stream are proxied by the
     file storage so it’s possible to do ‘storage.read()’ instead of the
     long form ‘storage.stream.read()’.

      -- 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 Headers object.  This
          usually contains irrelevant information but in combination
          with custom multipart requests the raw headers might be
          interesting.

          New in version 0.6.

      -- Method: close ()

          Close the underlying file if possible.

      -- Property: content_length

          The content-length sent in the header.  Usually not available

      -- Property: content_type

          The content-type sent in the header.  Usually not available

      -- Property: mimetype

          Like content_type, but without parameters (eg,
          without charset, type etc.)  and always lowercase.  For
          example if the content type is ‘text/HTML; charset=utf-8’ the
          mimetype would be ‘'text/html'’.

          New in version 0.7.

      -- Property: mimetype_params

          The mimetype parameters as dict.  For example if the content
          type is ‘text/html; charset=utf-8’ the params would be
          ‘{'charset': 'utf-8'}’.

          New in version 0.7.

      -- Method: save (dst, buffer_size=16384)

          Save the file to a destination path or file object.  If the
          destination is a file object you have to close it yourself
          after the call.  The buffer size is the number of bytes held
          in memory during the copy process.  It defaults to 16KB.

          For secure file saving also have a look at
          ‘secure_filename()’.

          Parameters:

             * ‘dst’ – a filename, os.PathLike(1), or open file object
               to write to.

             * ‘buffer_size’ – Passed as the ‘length’ parameter of
               shutil.copyfileobj()(2).

          Changed in version 1.0: Supports pathlib(3).

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/os.html#os.PathLike

   (2) https://docs.python.org/3/library/shutil.html#shutil.copyfileobj

   (3) https://docs.python.org/3/library/pathlib.html#module-pathlib

3.7 Utilities
=============

Various utility functions shipped with Werkzeug.

3.7.1 HTML Helpers
------------------

 -- Class: werkzeug.utils.HTMLBuilder (dialect)

     Helper object for HTML generation.

     Per default there are two instances of that class.  The ‘html’ one,
     and the ‘xhtml’ one for those two dialects.  The class uses keyword
     parameters and positional parameters to generate small snippets of
     HTML.

     Keyword parameters are converted to XML/SGML attributes, positional
     arguments are used as children.  Because Python accepts positional
     arguments before keyword arguments it’s a good idea to use a list
     with the star-syntax for some children:

          >>> html.p(class_='foo', *[html.a('foo', href='foo.html'), ' ',
          ...                        html.a('bar', href='bar.html')])
          '<p class="foo"><a href="foo.html">foo</a> <a href="bar.html">bar</a></p>'

     This class works around some browser limitations and can not be
     used for arbitrary SGML/XML generation.  For that purpose lxml and
     similar libraries exist.

     Calling the builder escapes the string passed:

          >>> html.p(html("<foo>"))
          '<p>&lt;foo&gt;</p>'

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.

 -- Function: werkzeug.utils.escape (s)

     Replace ‘&’, ‘<’, ‘>’, ‘"’, and ‘'’ with HTML-safe sequences.

     ‘None’ is escaped to an empty string.

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     MarkupSafe instead.

     Parameters: ‘s’ (‘Any’) –

     Return type: str(1)

 -- Function: werkzeug.utils.unescape (s)

     The reverse of escape().  This unescapes all the HTML
     entities, not only those inserted by ‘escape’.

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     MarkupSafe instead.

     Parameters: ‘s’ (str(2)) –

     Return type: str(3)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/stdtypes.html#str

3.7.2 General Helpers
---------------------

 -- Class: werkzeug.utils.cached_property (fget, name=None, doc=None)

     A ‘property()’ that is only evaluated once.  Subsequent access
     returns the cached value.  Setting the property sets the cached
     value.  Deleting the property clears the cached value, accessing it
     again will evaluate it again.

          class Example:
              @cached_property
              def value(self):
                  # calculate something important here
                  return 42

          e = Example()
          e.value  # evaluates
          e.value  # uses cache
          e.value = 16  # sets cache
          del e.value  # clears cache

     The class must have a ‘__dict__’ for this to work.

     Changed in version 2.0: ‘del obj.name’ clears the cached value.

     Parameters:

        * ‘fget’ (‘Callable’‘[’‘[’‘Any’‘]’‘, ’‘werkzeug.utils._T’‘]’) –

        * ‘name’ (‘Optional’‘[’str(1)‘]’) –

        * ‘doc’ (‘Optional’‘[’str(2)‘]’) –

     Return type: None(3)

 -- Function: werkzeug.utils.invalidate_cached_property (obj, name)

     Invalidates the cache for a cached_property.:

          >>> class Test(object):
          ...     @cached_property
          ...     def magic_number(self):
          ...         print("recalculating...")
          ...         return 42
          ...
          >>> var = Test()
          >>> var.magic_number
          recalculating...
          42
          >>> var.magic_number
          42
          >>> invalidate_cached_property(var, "magic_number")
          >>> var.magic_number
          recalculating...
          42

     You must pass the name of the cached property as the second
     argument.

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     ‘del obj.name’ instead.

     Parameters:

        * ‘obj’ (object(4)) –

        * ‘name’ (str(5)) –

     Return type: None(6)

 -- Class: werkzeug.utils.environ_property (name, default=None,
          load_func=None, dump_func=None, read_only=None, doc=None)

     Maps request attributes to environment variables.  This works not
     only for the Werkzeug request object, but also any other class with
     an environ attribute:

          >>> class Test(object):
          ...     environ = {'key': 'value'}
          ...     test = environ_property('key')
          >>> var = Test()
          >>> var.test
          'value'

     If you pass it a second value it’s used as default if the key does
     not exist, the third one can be a converter that takes a value and
     converts it.  If it raises ValueError(7) or TypeError(8) the
     default value is used.  If no default value is provided ‘None’ is
     used.

     Per default the property is read only.  You have to explicitly
     enable it by passing ‘read_only=False’ to the constructor.

 -- Class: werkzeug.utils.header_property (name, default=None,
          load_func=None, dump_func=None, read_only=None, doc=None)

     Like ‘environ_property’ but for headers.

 -- Function: werkzeug.utils.redirect (location, code=302,
          Response=None)

     Returns a response object (a WSGI application) that, if called,
     redirects the client to the target location.  Supported codes are
     301, 302, 303, 305, 307, and 308.  300 is not supported because
     it’s not a real redirect and 304 because it’s the answer for a
     request with a request with defined If-Modified-Since headers.

     New in version 0.10: The class used for the Response object can now
     be passed in.

     New in version 0.6: The location can now be a unicode string that
     is encoded using the ‘iri_to_uri()’ function.

     Parameters:

        * ‘location’ (str(9)) – the location the response should
          redirect to.

        * ‘code’ (int(10)) – the redirect status code.  defaults to 302.

        * ‘Response’ (‘class’) – a Response class to use when
          instantiating a response.  The default is
          werkzeug.wrappers.Response if unspecified.

     Return type: Response.

 -- Function: werkzeug.utils.append_slash_redirect (environ, code=301)

     Redirects to the same URL but with a slash appended.  The behavior
     of this function is undefined if the path ends with a slash
     already.

     Parameters:

        * ‘environ’ (‘WSGIEnvironment’) – the WSGI environment for the
          request that triggers the redirect.

        * ‘code’ (int(11)) – the status code for the redirect.

     Return type: Response.

 -- Function: werkzeug.utils.send_file (path_or_file, environ,
          mimetype=None, as_attachment=False, download_name=None,
          conditional=True, etag=True, last_modified=None, max_age=None,
          use_x_sendfile=False, response_class=None, _root_path=None)

     Send the contents of a file to the client.

     The first argument can be a file path or a file-like object.  Paths
     are preferred in most cases because Werkzeug can manage the file
     and get extra information from the path.  Passing a file-like
     object requires that the file is opened in binary mode, and is
     mostly useful when building a file in memory with io.BytesIO(12).

     Never pass file paths provided by a user.  The path is assumed to
     be trusted, so a user could craft a path to access a file you
     didn’t intend.

     If the WSGI server sets a ‘file_wrapper’ in ‘environ’, it is used,
     otherwise Werkzeug’s built-in wrapper is used.  Alternatively, if
     the HTTP server supports ‘X-Sendfile’, ‘use_x_sendfile=True’ will
     tell the server to send the given path, which is much more
     efficient than reading it in Python.

     Parameters:

        * ‘path_or_file’ (‘Union’‘[’os.PathLike(13)‘, ’str(14)‘,
          ’‘IO’‘[’bytes(15)‘]’‘]’) – The path to the file to send,
          relative to the current working directory if a relative path
          is given.  Alternatively, a file-like object opened in binary
          mode.  Make sure the file pointer is seeked to the start of
          the data.

        * ‘environ’ (‘WSGIEnvironment’) – The WSGI environ for the
          current request.

        * ‘mimetype’ (‘Optional’‘[’str(16)‘]’) – The MIME type to send
          for the file.  If not provided, it will try to detect it from
          the file name.

        * ‘as_attachment’ (bool(17)) – Indicate to a browser that it
          should offer to save the file instead of displaying it.

        * ‘download_name’ (‘Optional’‘[’str(18)‘]’) – The default name
          browsers will use when saving the file.  Defaults to the
          passed file name.

        * ‘conditional’ (bool(19)) – Enable conditional and range
          responses based on request headers.  Requires passing a file
          path and ‘environ’.

        * ‘etag’ (‘Union’‘[’bool(20)‘, ’str(21)‘]’) – Calculate an ETag
          for the file, which requires passing a file path.  Can also be
          a string to use instead.

        * ‘last_modified’
          (‘Optional’‘[’‘Union’‘[’datetime.datetime(22)‘, ’int(23)‘,
          ’float(24)‘]’‘]’) – The last modified time to send for the
          file, in seconds.  If not provided, it will try to detect it
          from the file path.

        * ‘max_age’ (‘Optional’‘[’‘Union’‘[’int(25)‘,
          ’‘Callable’‘[’‘[’‘Optional’‘[’str(26)‘]’‘]’‘,
          ’‘Optional’‘[’int(27)‘]’‘]’‘]’‘]’) – How long the client
          should cache the file, in seconds.  If set, ‘Cache-Control’
          will be ‘public’, otherwise it will be ‘no-cache’ to prefer
          conditional caching.

        * ‘use_x_sendfile’ (bool(28)) – Set the ‘X-Sendfile’ header to
          let the server to efficiently send the file.  Requires support
          from the HTTP server.  Requires passing a file path.

        * ‘response_class’ (‘Optional’‘[’‘Type’‘[’Response.
          ‘]’‘]’) – Build the response using this class.  Defaults to
          Response.

        * ‘_root_path’ (‘Optional’‘[’‘Union’‘[’os.PathLike(29)‘,
          ’str(30)‘]’‘]’) – Do not use.  For internal use only.  Use
          ‘send_from_directory()’ to safely send files under a path.

     Return type: Response.

     Changed in version 2.0.2: ‘send_file’ only sets a detected
     ‘Content-Encoding’ if ‘as_attachment’ is disabled.

     New in version 2.0: Adapted from Flask’s implementation.

     Changed in version 2.0: ‘download_name’ replaces Flask’s
     ‘attachment_filename’ parameter.  If ‘as_attachment=False’, it is
     passed with ‘Content-Disposition: inline’ instead.

     Changed in version 2.0: ‘max_age’ replaces Flask’s ‘cache_timeout’
     parameter.  ‘conditional’ is enabled and ‘max_age’ is not set by
     default.

     Changed in version 2.0: ‘etag’ replaces Flask’s ‘add_etags’
     parameter.  It can be a string to use instead of generating one.

     Changed in version 2.0: If an encoding is returned when guessing
     ‘mimetype’ from ‘download_name’, set the ‘Content-Encoding’ header.

 -- Function: werkzeug.utils.import_string (import_name, silent=False)

     Imports an object based on a string.  This is useful if you want to
     use import paths as endpoints or something similar.  An import path
     can be specified either in dotted notation
     (‘xml.sax.saxutils.escape’) or with a colon as object delimiter
     (‘xml.sax.saxutils:escape’).

     If ‘silent’ is True the return value will be ‘None’ if the import
     fails.

     Parameters:

        * ‘import_name’ (str(31)) – the dotted name for the object to
          import.

        * ‘silent’ (bool(32)) – if set to ‘True’ import errors are
          ignored and ‘None’ is returned instead.

     Returns: imported object

     Return type: Any

 -- Function: werkzeug.utils.find_modules (import_path,
          include_packages=False, recursive=False)

     Finds all the modules below a package.  This can be useful to
     automatically import all views / controllers so that their
     metaclasses / function decorators have a chance to register
     themselves on the application.

     Packages are not returned unless ‘include_packages’ is ‘True’.
     This can also recursively list modules but in that case it will
     import all the packages to get the correct load path of that
     module.

     Parameters:

        * ‘import_path’ (str(33)) – the dotted name for the package to
          find child modules.

        * ‘include_packages’ (bool(34)) – set to ‘True’ if packages
          should be returned, too.

        * ‘recursive’ (bool(35)) – set to ‘True’ if recursion should
          happen.

     Returns: generator

     Return type: Iterator[str(36)]

 -- Function: werkzeug.utils.validate_arguments (func, args, kwargs,
          drop_extra=True)

     Checks if the function accepts the arguments and keyword arguments.
     Returns a new ‘(args, kwargs)’ tuple that can safely be passed to
     the function without causing a ‘TypeError’ because the function
     signature is incompatible.  If ‘drop_extra’ is set to ‘True’ (which
     is the default) any extra positional or keyword arguments are
     dropped automatically.

     The exception raised provides three attributes:

     ‘missing’

          A set of argument names that the function expected but where
          missing.

     ‘extra’

          A dict of keyword arguments that the function can not handle
          but where provided.

     ‘extra_positional’

          A list of values that where given by positional argument but
          the function cannot accept.

     This can be useful for decorators that forward user submitted data
     to a view function:

          from werkzeug.utils import ArgumentValidationError, validate_arguments

          def sanitize(f):
              def proxy(request):
                  data = request.values.to_dict()
                  try:
                      args, kwargs = validate_arguments(f, (request,), data)
                  except ArgumentValidationError:
                      raise BadRequest('The browser failed to transmit all '
                                       'the data expected.')
                  return f(*args, **kwargs)
              return proxy

     Parameters:

        * ‘func’ – the function the validation is performed against.

        * ‘args’ – a tuple of positional arguments.

        * ‘kwargs’ – a dict of keyword arguments.

        * ‘drop_extra’ – set to ‘False’ if you don’t want extra
          arguments to be silently dropped.

     Returns: tuple in the form ‘(args, kwargs)’.

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     inspect.signature()(37) instead.

 -- Function: werkzeug.utils.secure_filename (filename)

     Pass it a filename and it will return a secure version of it.  This
     filename can then safely be stored on a regular file system and
     passed to os.path.join()(38).  The filename returned is an ASCII
     only string for maximum portability.

     On windows systems the function also makes sure that the file is
     not named after one of the special device files.

          >>> secure_filename("My cool movie.mov")
          'My_cool_movie.mov'
          >>> secure_filename("../../../etc/passwd")
          'etc_passwd'
          >>> secure_filename('i contain cool \xfcml\xe4uts.txt')
          'i_contain_cool_umlauts.txt'

     The function might return an empty filename.  It’s your
     responsibility to ensure that the filename is unique and that you
     abort or generate a random filename if the function returned an
     empty one.

     New in version 0.5.

     Parameters: ‘filename’ (str(39)) – the filename to secure

     Return type: str(40)

 -- Function: werkzeug.utils.bind_arguments (func, args, kwargs)

     Bind the arguments provided into a dict.  When passed a function, a
     tuple of arguments and a dict of keyword arguments ‘bind_arguments’
     returns a dict of names as the function would see it.  This can be
     useful to implement a cache decorator that uses the function
     arguments to build the cache key based on the values of the
     arguments.

     Parameters:

        * ‘func’ – the function the arguments should be bound for.

        * ‘args’ – tuple of positional arguments.

        * ‘kwargs’ – a dict of keyword arguments.

     Returns: a dict(41) of bound keyword arguments.

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     ‘Signature.bind()’ instead.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/constants.html#None

   (4) https://docs.python.org/3/library/functions.html#object

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/constants.html#None

   (7) https://docs.python.org/3/library/exceptions.html#ValueError

   (8) https://docs.python.org/3/library/exceptions.html#TypeError

   (9) https://docs.python.org/3/library/stdtypes.html#str

   (10) https://docs.python.org/3/library/functions.html#int

   (11) https://docs.python.org/3/library/functions.html#int

   (12) https://docs.python.org/3/library/io.html#io.BytesIO

   (13) https://docs.python.org/3/library/os.html#os.PathLike

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/stdtypes.html#bytes

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/functions.html#bool

   (18) https://docs.python.org/3/library/stdtypes.html#str

   (19) https://docs.python.org/3/library/functions.html#bool

   (20) https://docs.python.org/3/library/functions.html#bool

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (23) https://docs.python.org/3/library/functions.html#int

   (24) https://docs.python.org/3/library/functions.html#float

   (25) https://docs.python.org/3/library/functions.html#int

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/functions.html#int

   (28) https://docs.python.org/3/library/functions.html#bool

   (29) https://docs.python.org/3/library/os.html#os.PathLike

   (30) https://docs.python.org/3/library/stdtypes.html#str

   (31) https://docs.python.org/3/library/stdtypes.html#str

   (32) https://docs.python.org/3/library/functions.html#bool

   (33) https://docs.python.org/3/library/stdtypes.html#str

   (34) https://docs.python.org/3/library/functions.html#bool

   (35) https://docs.python.org/3/library/functions.html#bool

   (36) https://docs.python.org/3/library/stdtypes.html#str

   (37) https://docs.python.org/3/library/inspect.html#inspect.signature

   (38) https://docs.python.org/3/library/os.path.html#os.path.join

   (39) https://docs.python.org/3/library/stdtypes.html#str

   (40) https://docs.python.org/3/library/stdtypes.html#str

   (41) https://docs.python.org/3/library/stdtypes.html#dict

3.7.3 URL Helpers
-----------------

Please refer to URL Helpers.

3.7.4 User Agent API
--------------------

 -- Class: werkzeug.user_agent.UserAgent (string)

     Represents a parsed user agent header value.

     The default implementation does no parsing, only the string
     attribute is set.  A subclass may parse the string to set the
     common attributes or expose other information.  Set
     werkzeug.wrappers.Request.user_agent_class to use a subclass.

     Parameters: ‘string’ (str(1)) – The header value to parse.

     Return type: None(2)

     New in version 2.0: This replaces the previous ‘useragents’ module,
     but does not provide a built-in parser.

      -- Attribute: platform: Optional[str(3)] = None

          The OS name, if it could be parsed from the string.

      -- Attribute: browser: Optional[str(4)] = None

          The browser name, if it could be parsed from the string.

      -- Attribute: version: Optional[str(5)] = None

          The browser version, if it could be parsed from the string.

      -- Attribute: language: Optional[str(6)] = None

          The browser language, if it could be parsed from the string.

      -- Attribute: string: str(7)

          The original header value.

      -- Method: to_header ()

          Convert to a header value.

          Return type: str(8)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/constants.html#None

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/stdtypes.html#str

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/stdtypes.html#str

3.7.5 UserAgent Parsing (deprecated)
------------------------------------

Deprecated since version 2.0: This module will be removed in Werkzeug
2.1.  Subclass werkzeug.user_agent.UserAgent to use a
dedicated parser instead.

 -- Class: werkzeug.useragents.UserAgent (environ_or_string)

     Represents a parsed user agent header value.

     This uses a basic parser to try to extract some information from
     the header.

     Parameters: ‘environ_or_string’ (‘t.Union’‘[’str(1)‘,
     ’‘WSGIEnvironment’‘]’) – The header value to parse, or a WSGI
     environ containing the header.

     Return type: None(2)

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.
     Subclass werkzeug.user_agent.UserAgent. (note the new
     module name) to use a dedicated parser instead.

     Changed in version 2.0: Passing a WSGI environ is deprecated and
     will be removed in 2.1.

      -- Method: to_header ()

          Convert to a header value.

          Return type: str(3)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/constants.html#None

   (3) https://docs.python.org/3/library/stdtypes.html#str

3.7.6 Security Helpers
----------------------

New in version 0.6.1.

 -- Function: werkzeug.security.generate_password_hash (password,
          method='pbkdf2:sha256', salt_length=16)

     Hash a password with the given method and salt with a string of the
     given length.  The format of the string returned includes the
     method that was used so that check_password_hash() can
     check the hash.

     The format for the hashed string looks like this:

          method$salt$hash

     This method can `not' generate unsalted passwords but it is
     possible to set param method=’plain’ in order to enforce plaintext
     passwords.  If a salt is used, hmac is used internally to salt the
     password.

     If PBKDF2 is wanted it can be enabled by setting the method to
     ‘pbkdf2:method:iterations’ where iterations is optional:

          pbkdf2:sha256:80000$salt$hash
          pbkdf2:sha256$salt$hash

     Parameters:

        * ‘password’ (str(1)) – the password to hash.

        * ‘method’ (str(2)) – the hash method to use (one that hashlib
          supports).  Can optionally be in the format
          ‘pbkdf2:method:iterations’ to enable PBKDF2.

        * ‘salt_length’ (int(3)) – the length of the salt in letters.

     Return type: str(4)

 -- Function: werkzeug.security.check_password_hash (pwhash, password)

     Check a password against a given salted and hashed password value.
     In order to support unsalted legacy passwords this method supports
     plain text passwords, md5 and sha1 hashes (both salted and
     unsalted).

     Returns ‘True’ if the password matched, ‘False’ otherwise.

     Parameters:

        * ‘pwhash’ (str(5)) – a hashed string like returned by
          generate_password_hash().

        * ‘password’ (str(6)) – the plaintext password to compare
          against the hash.

     Return type: bool(7)

 -- Function: werkzeug.security.safe_str_cmp (a, b)

     This function compares strings in somewhat constant time.  This
     requires that the length of at least one string is known in
     advance.

     Returns ‘True’ if the two strings are equal, or ‘False’ if they are
     not.

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     hmac.compare_digest()(8) instead.

     New in version 0.7.

     Parameters:

        * ‘a’ (str(9)) –

        * ‘b’ (str(10)) –

     Return type: bool(11)

 -- Function: werkzeug.security.safe_join (directory, *pathnames)

     Safely join zero or more untrusted path components to a base
     directory to avoid escaping the base directory.

     Parameters:

        * ‘directory’ (str(12)) – The trusted base directory.

        * ‘pathnames’ (str(13)) – The untrusted path components relative
          to the base directory.

     Returns: A safe path, otherwise ‘None’.

     Return type: Optional[str(14)]

 -- Function: werkzeug.security.pbkdf2_hex (data, salt,
          iterations=260000, keylen=None, hashfunc=None)

     Like pbkdf2_bin(), but returns a hex-encoded string.

     Parameters:

        * ‘data’ (‘Union’‘[’str(15)‘, ’bytes(16)‘]’) – the data to
          derive.

        * ‘salt’ (‘Union’‘[’str(17)‘, ’bytes(18)‘]’) – the salt for the
          derivation.

        * ‘iterations’ (int(19)) – the number of iterations.

        * ‘keylen’ (‘Optional’‘[’int(20)‘]’) – the length of the
          resulting key.  If not provided, the digest size will be used.

        * ‘hashfunc’ (‘Optional’‘[’‘Union’‘[’str(21)‘,
          ’‘Callable’‘]’‘]’) – the hash function to use.  This can
          either be the string name of a known hash function, or a
          function from the hashlib module.  Defaults to sha256.

     Return type: str(22)

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     hashlib.pbkdf2_hmac()(23) instead.

     New in version 0.9.

 -- Function: werkzeug.security.pbkdf2_bin (data, salt,
          iterations=260000, keylen=None, hashfunc=None)

     Returns a binary digest for the PBKDF2 hash algorithm of ‘data’
     with the given ‘salt’.  It iterates ‘iterations’ times and produces
     a key of ‘keylen’ bytes.  By default, SHA-256 is used as hash
     function; a different hashlib ‘hashfunc’ can be provided.

     Parameters:

        * ‘data’ (‘Union’‘[’str(24)‘, ’bytes(25)‘]’) – the data to
          derive.

        * ‘salt’ (‘Union’‘[’str(26)‘, ’bytes(27)‘]’) – the salt for the
          derivation.

        * ‘iterations’ (int(28)) – the number of iterations.

        * ‘keylen’ (‘Optional’‘[’int(29)‘]’) – the length of the
          resulting key.  If not provided the digest size will be used.

        * ‘hashfunc’ (‘Optional’‘[’‘Union’‘[’str(30)‘,
          ’‘Callable’‘]’‘]’) – the hash function to use.  This can
          either be the string name of a known hash function or a
          function from the hashlib module.  Defaults to sha256.

     Return type: bytes(31)

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     hashlib.pbkdf2_hmac()(32) instead.

     New in version 0.9.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/functions.html#int

   (4) https://docs.python.org/3/library/stdtypes.html#str

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/functions.html#bool

   (8) https://docs.python.org/3/library/hmac.html#hmac.compare_digest

   (9) https://docs.python.org/3/library/stdtypes.html#str

   (10) https://docs.python.org/3/library/stdtypes.html#str

   (11) https://docs.python.org/3/library/functions.html#bool

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/stdtypes.html#str

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/stdtypes.html#str

   (16) https://docs.python.org/3/library/stdtypes.html#bytes

   (17) https://docs.python.org/3/library/stdtypes.html#str

   (18) https://docs.python.org/3/library/stdtypes.html#bytes

   (19) https://docs.python.org/3/library/functions.html#int

   (20) https://docs.python.org/3/library/functions.html#int

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23)
https://docs.python.org/3/library/hashlib.html#hashlib.pbkdf2_hmac

   (24) https://docs.python.org/3/library/stdtypes.html#str

   (25) https://docs.python.org/3/library/stdtypes.html#bytes

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/stdtypes.html#bytes

   (28) https://docs.python.org/3/library/functions.html#int

   (29) https://docs.python.org/3/library/functions.html#int

   (30) https://docs.python.org/3/library/stdtypes.html#str

   (31) https://docs.python.org/3/library/stdtypes.html#bytes

   (32)
https://docs.python.org/3/library/hashlib.html#hashlib.pbkdf2_hmac

3.7.7 Logging
-------------

Werkzeug uses standard Python logging(1).  The logger is named
‘"werkzeug"’.

     import logging
     logger = logging.getLogger("werkzeug")

If the logger level is not set, it will be set to ‘INFO’ on first use.
If there is no handler for that level, a StreamHandler(2) is added.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/logging.html#module-logging

   (2)
https://docs.python.org/3/library/logging.handlers.html#logging.StreamHandler

3.8 URL Helpers
===============

Functions for working with URLs.

Contains implementations of functions from urllib.parse(1) that handle
bytes and strings.

 -- Class: werkzeug.urls.BaseURL (scheme, netloc, path, query, fragment)

     Superclass of URL and BytesURL.

     Create new instance of _URLTuple(scheme, netloc, path, query,
     fragment)

     Parameters:

        * ‘scheme’ (str(2)) –

        * ‘netloc’ (str(3)) –

        * ‘path’ (str(4)) –

        * ‘query’ (str(5)) –

        * ‘fragment’ (str(6)) –

      -- Property: ascii_host: Optional[str(7)]

          Works exactly like host but will return a result
          that is restricted to ASCII. If it finds a netloc that is not
          ASCII it will attempt to idna decode it.  This is useful for
          socket operations when the URL might include internationalized
          characters.

      -- Property: auth: Optional[str(8)]

          The authentication part in the URL if available, ‘None’
          otherwise.

      -- Method: decode_netloc ()

          Decodes the netloc part into a string.

          Return type: str(9)

      -- Method: decode_query (*args, **kwargs)

          Decodes the query part of the URL. Ths is a shortcut for
          calling url_decode() on the query argument.  The
          arguments and keyword arguments are forwarded to
          url_decode() unchanged.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kwargs’ (‘Any’) –

          Return type: ds.MultiDict[str(10), str(11)]

      -- Method: encode_netloc ()

          Encodes the netloc part to an ASCII safe URL as bytes.

          Return type: str(12)

      -- Method: get_file_location (pathformat=None)

          Returns a tuple with the location of the file in the form
          ‘(server, location)’.  If the netloc is empty in the URL or
          points to localhost, it’s represented as ‘None’.

          The ‘pathformat’ by default is autodetection but needs to be
          set when working with URLs of a specific system.  The
          supported values are ‘'windows'’ when working with Windows or
          DOS paths and ‘'posix'’ when working with posix paths.

          If the URL does not point to a local file, the server and
          location are both represented as ‘None’.

          Parameters: ‘pathformat’ (‘Optional’‘[’str(13)‘]’) – The
          expected format of the path component.  Currently ‘'windows'’
          and ‘'posix'’ are supported.  Defaults to ‘None’ which is
          autodetect.

          Return type: Tuple[Optional[str(14)], Optional[str(15)]]

      -- Property: host: Optional[str(16)]

          The host part of the URL if available, otherwise ‘None’.  The
          host is either the hostname or the IP address mentioned in the
          URL. It will not contain the port.

      -- Method: join (*args, **kwargs)

          Joins this URL with another one.  This is just a convenience
          function for calling into url_join() and then
          parsing the return value again.

          Parameters:

             * ‘args’ (‘Any’) –

             * ‘kwargs’ (‘Any’) –

          Return type: werkzeug.urls.BaseURL.

      -- Property: password: Optional[str(17)]

          The password if it was part of the URL, ‘None’ otherwise.
          This undergoes URL decoding and will always be a string.

      -- Property: port: Optional[int(18)]

          The port in the URL as an integer if it was present, ‘None’
          otherwise.  This does not fill in default ports.

      -- Property: raw_password: Optional[str(19)]

          The password if it was part of the URL, ‘None’ otherwise.
          Unlike password this one is not being decoded.

      -- Property: raw_username: Optional[str(20)]

          The username if it was part of the URL, ‘None’ otherwise.
          Unlike username this one is not being decoded.

      -- Method: replace (**kwargs)

          Return an URL with the same values, except for those
          parameters given new values by whichever keyword arguments are
          specified.

          Parameters: ‘kwargs’ (‘Any’) –

          Return type: werkzeug.urls.BaseURL.

      -- Method: to_iri_tuple ()

          Returns a URL tuple that holds a IRI. This will
          try to decode as much information as possible in the URL
          without losing information similar to how a web browser does
          it for the URL bar.

          It’s usually more interesting to directly call
          uri_to_iri() which will return a string.

          Return type: werkzeug.urls.BaseURL.

      -- Method: to_uri_tuple ()

          Returns a BytesURL tuple that holds a URI. This
          will encode all the information in the URL properly to ASCII
          using the rules a web browser would follow.

          It’s usually more interesting to directly call
          iri_to_uri() which will return a string.

          Return type: werkzeug.urls.BaseURL.

      -- Method: to_url ()

          Returns a URL string or bytes depending on the type of the
          information stored.  This is just a convenience function for
          calling url_unparse() for this URL.

          Return type: str(21)

      -- Property: username: Optional[str(22)]

          The username if it was part of the URL, ‘None’ otherwise.
          This undergoes URL decoding and will always be a string.

 -- Class: werkzeug.urls.BytesURL (scheme, netloc, path, query,
          fragment)

     Represents a parsed URL in bytes.

     Create new instance of _URLTuple(scheme, netloc, path, query,
     fragment)

     Parameters:

        * ‘scheme’ (str(23)) –

        * ‘netloc’ (str(24)) –

        * ‘path’ (str(25)) –

        * ‘query’ (str(26)) –

        * ‘fragment’ (str(27)) –

      -- Method: decode (charset='utf-8', errors='replace')

          Decodes the URL to a tuple made out of strings.  The charset
          is only being used for the path, query and fragment.

          Parameters:

             * ‘charset’ (str(28)) –

             * ‘errors’ (str(29)) –

          Return type: werkzeug.urls.URL.

      -- Method: encode_netloc ()

          Returns the netloc unchanged as bytes.

          Return type: bytes(30)

 -- Class: werkzeug.urls.Href (base='./', charset='utf-8', sort=False,
          key=None)

     Implements a callable that constructs URLs with the given base.
     The function can be called with any number of positional and
     keyword arguments which than are used to assemble the URL. Works
     with URLs and posix paths.

     Positional arguments are appended as individual segments to the
     path of the URL:

          >>> href = Href('/foo')
          >>> href('bar', 23)
          '/foo/bar/23'
          >>> href('foo', bar=23)
          '/foo/foo?bar=23'

     If any of the arguments (positional or keyword) evaluates to ‘None’
     it will be skipped.  If no keyword arguments are given the last
     argument can be a dict(31) or ‘MultiDict’ (or any other dict
     subclass), otherwise the keyword arguments are used for the query
     parameters, cutting off the first trailing underscore of the
     parameter name:

          >>> href(is_=42)
          '/foo?is=42'
          >>> href({'foo': 'bar'})
          '/foo?foo=bar'

     Combining of both methods is not allowed:

          >>> href({'foo': 'bar'}, bar=42)
          Traceback (most recent call last):
            ...
          TypeError: keyword arguments and query-dicts can't be combined

     Accessing attributes on the href object creates a new href object
     with the attribute name as prefix:

          >>> bar_href = href.bar
          >>> bar_href("blub")
          '/foo/bar/blub'

     If ‘sort’ is set to ‘True’ the items are sorted by ‘key’ or the
     default sorting algorithm:

          >>> href = Href("/", sort=True)
          >>> href(a=1, b=2, c=3)
          '/?a=1&b=2&c=3'

     Deprecated since version 2.0: Will be removed in Werkzeug 2.1.  Use
     werkzeug.routing instead.

     New in version 0.5: ‘sort’ and ‘key’ were added.

 -- Class: werkzeug.urls.URL (scheme, netloc, path, query, fragment)

     Represents a parsed URL. This behaves like a regular tuple but also
     has some extra attributes that give further insight into the URL.

     Create new instance of _URLTuple(scheme, netloc, path, query,
     fragment)

     Parameters:

        * ‘scheme’ (str(32)) –

        * ‘netloc’ (str(33)) –

        * ‘path’ (str(34)) –

        * ‘query’ (str(35)) –

        * ‘fragment’ (str(36)) –

      -- Method: encode (charset='utf-8', errors='replace')

          Encodes the URL to a tuple made out of bytes.  The charset is
          only being used for the path, query and fragment.

          Parameters:

             * ‘charset’ (str(37)) –

             * ‘errors’ (str(38)) –

          Return type: werkzeug.urls.BytesURL.

 -- Function: werkzeug.urls.iri_to_uri (iri, charset='utf-8',
          errors='strict', safe_conversion=False)

     Convert an IRI to a URI. All non-ASCII and unsafe characters are
     quoted.  If the URL has a domain, it is encoded to Punycode.

          >>> iri_to_uri('http://\u2603.net/p\xe5th?q=\xe8ry%DF')
          'http://xn--n3h.net/p%C3%A5th?q=%C3%A8ry%DF'

     Parameters:

        * ‘iri’ (‘Union’‘[’str(39)‘, ’‘Tuple’‘[’str(40)‘, ’str(41)‘,
          ’str(42)‘, ’str(43)‘, ’str(44)‘]’‘]’) – The IRI to convert.

        * ‘charset’ (str(45)) – The encoding of the IRI.

        * ‘errors’ (str(46)) – Error handler to use during
          ‘bytes.encode’.

        * ‘safe_conversion’ (bool(47)) – Return the URL unchanged if it
          only contains ASCII characters and no whitespace.  See the
          explanation below.

     Return type: str(48)

     There is a general problem with IRI conversion with some protocols
     that are in violation of the URI specification.  Consider the
     following two IRIs:

          magnet:?xt=uri:whatever
          itms-services://?action=download-manifest

     After parsing, we don’t know if the scheme requires the ‘//’, which
     is dropped if empty, but conveys different meanings in the final
     URL if it’s present or not.  In this case, you can use
     ‘safe_conversion’, which will return the URL unchanged if it only
     contains ASCII characters and no whitespace.  This can result in a
     URI with unquoted characters if it was not already quoted
     correctly, but preserves the URL’s semantics.  Werkzeug uses this
     for the ‘Location’ header for redirects.

     Changed in version 0.15: All reserved characters remain unquoted.
     Previously, only some reserved characters were left unquoted.

     Changed in version 0.9.6: The ‘safe_conversion’ parameter was
     added.

     New in version 0.6.

 -- Function: werkzeug.urls.uri_to_iri (uri, charset='utf-8',
          errors='werkzeug.url_quote')

     Convert a URI to an IRI. All valid UTF-8 characters are unquoted,
     leaving all reserved and invalid characters quoted.  If the URL has
     a domain, it is decoded from Punycode.

          >>> uri_to_iri("http://xn--n3h.net/p%C3%A5th?q=%C3%A8ry%DF")
          'http://\u2603.net/p\xe5th?q=\xe8ry%DF'

     Parameters:

        * ‘uri’ (‘Union’‘[’str(49)‘, ’‘Tuple’‘[’str(50)‘, ’str(51)‘,
          ’str(52)‘, ’str(53)‘, ’str(54)‘]’‘]’) – The URI to convert.

        * ‘charset’ (str(55)) – The encoding to encode unquoted bytes
          with.

        * ‘errors’ (str(56)) – Error handler to use during
          ‘bytes.encode’.  By default, invalid bytes are left quoted.

     Return type: str(57)

     Changed in version 0.15: All reserved and invalid characters remain
     quoted.  Previously, only some reserved characters were preserved,
     and invalid bytes were replaced instead of left quoted.

     New in version 0.6.

 -- Function: werkzeug.urls.url_decode (s, charset='utf-8',
          decode_keys=None, include_empty=True, errors='replace',
          separator='&', cls=None)

     Parse a query string and return it as a ‘MultiDict’.

     Parameters:

        * ‘s’ (‘AnyStr’) – The query string to parse.

        * ‘charset’ (str(58)) – Decode bytes to string with this
          charset.  If not given, bytes are returned as-is.

        * ‘include_empty’ (bool(59)) – Include keys with empty values in
          the dict.

        * ‘errors’ (str(60)) – Error handling behavior when decoding
          bytes.

        * ‘separator’ (str(61)) – Separator character between pairs.

        * ‘cls’ (‘Optional’‘[’‘Type’‘[’‘ds.MultiDict’‘]’‘]’) – Container
          to hold result instead of ‘MultiDict’.

        * ‘decode_keys’ (None(62)) –

     Return type: ds.MultiDict[str(63), str(64)]

     Changed in version 2.0: The ‘decode_keys’ parameter is deprecated
     and will be removed in Werkzeug 2.1.

     Changed in version 0.5: In previous versions “;” and “&” could be
     used for url decoding.  Now only “&” is supported.  If you want to
     use “;”, a different ‘separator’ can be provided.

     Changed in version 0.5: The ‘cls’ parameter was added.

 -- Function: werkzeug.urls.url_decode_stream (stream, charset='utf-8',
          decode_keys=None, include_empty=True, errors='replace',
          separator=b'&', cls=None, limit=None, return_iterator=False)

     Works like url_decode() but decodes a stream.  The
     behavior of stream and limit follows functions like
     make_line_iter().  The generator of pairs is directly fed to
     the ‘cls’ so you can consume the data while it’s parsed.

     Parameters:

        * ‘stream’ (‘IO’‘[’bytes(65)‘]’) – a stream with the encoded
          querystring

        * ‘charset’ (str(66)) – the charset of the query string.  If set
          to ‘None’ no decoding will take place.

        * ‘include_empty’ (bool(67)) – Set to ‘False’ if you don’t want
          empty values to appear in the dict.

        * ‘errors’ (str(68)) – the decoding error behavior.

        * ‘separator’ (bytes(69)) – the pair separator to be used,
          defaults to ‘&’

        * ‘cls’ (‘Optional’‘[’‘Type’‘[’‘ds.MultiDict’‘]’‘]’) – an
          optional dict class to use.  If this is not specified or
          ‘None’ the default ‘MultiDict’ is used.

        * ‘limit’ (‘Optional’‘[’int(70)‘]’) – the content length of the
          URL data.  Not necessary if a limited stream is provided.

        * ‘decode_keys’ (None(71)) –

        * ‘return_iterator’ (bool(72)) –

     Return type: ds.MultiDict[str(73), str(74)]

     Changed in version 2.0: The ‘decode_keys’ and ‘return_iterator’
     parameters are deprecated and will be removed in Werkzeug 2.1.

     New in version 0.8.

 -- Function: werkzeug.urls.url_encode (obj, charset='utf-8',
          encode_keys=None, sort=False, key=None, separator='&')

     URL encode a dict/‘MultiDict’.  If a value is ‘None’ it will not
     appear in the result string.  Per default only values are encoded
     into the target charset strings.

     Parameters:

        * ‘obj’ (‘Union’‘[’‘Mapping’‘[’str(75)‘, ’str(76)‘]’‘,
          ’‘Iterable’‘[’‘Tuple’‘[’str(77)‘, ’str(78)‘]’‘]’‘]’) – the
          object to encode into a query string.

        * ‘charset’ (str(79)) – the charset of the query string.

        * ‘sort’ (bool(80)) – set to ‘True’ if you want parameters to be
          sorted by ‘key’.

        * ‘separator’ (str(81)) – the separator to be used for the
          pairs.

        * ‘key’ (‘Optional’‘[’‘Callable’‘[’‘[’‘Tuple’‘[’str(82)‘,
          ’str(83)‘]’‘]’‘, ’‘Any’‘]’‘]’) – an optional function to be
          used for sorting.  For more details check out the sorted()(84)
          documentation.

        * ‘encode_keys’ (None(85)) –

     Return type: str(86)

     Changed in version 2.0: The ‘encode_keys’ parameter is deprecated
     and will be removed in Werkzeug 2.1.

     Changed in version 0.5: Added the ‘sort’, ‘key’, and ‘separator’
     parameters.

 -- Function: werkzeug.urls.url_encode_stream (obj, stream=None,
          charset='utf-8', encode_keys=None, sort=False, key=None,
          separator='&')

     Like url_encode() but writes the results to a stream
     object.  If the stream is ‘None’ a generator over all encoded pairs
     is returned.

     Parameters:

        * ‘obj’ (‘Union’‘[’‘Mapping’‘[’str(87)‘, ’str(88)‘]’‘,
          ’‘Iterable’‘[’‘Tuple’‘[’str(89)‘, ’str(90)‘]’‘]’‘]’) – the
          object to encode into a query string.

        * ‘stream’ (‘Optional’‘[’‘IO’‘[’str(91)‘]’‘]’) – a stream to
          write the encoded object into or ‘None’ if an iterator over
          the encoded pairs should be returned.  In that case the
          separator argument is ignored.

        * ‘charset’ (str(92)) – the charset of the query string.

        * ‘sort’ (bool(93)) – set to ‘True’ if you want parameters to be
          sorted by ‘key’.

        * ‘separator’ (str(94)) – the separator to be used for the
          pairs.

        * ‘key’ (‘Optional’‘[’‘Callable’‘[’‘[’‘Tuple’‘[’str(95)‘,
          ’str(96)‘]’‘]’‘, ’‘Any’‘]’‘]’) – an optional function to be
          used for sorting.  For more details check out the sorted()(97)
          documentation.

        * ‘encode_keys’ (None(98)) –

     Return type: None(99)

     Changed in version 2.0: The ‘encode_keys’ parameter is deprecated
     and will be removed in Werkzeug 2.1.

     New in version 0.8.

 -- Function: werkzeug.urls.url_fix (s, charset='utf-8')

     Sometimes you get an URL by a user that just isn’t a real URL
     because it contains unsafe characters like ‘ ‘ and so on.  This
     function can fix some of the problems in a similar way browsers
     handle data entered by the user:

          >>> url_fix('http://de.wikipedia.org/wiki/Elf (Begriffskl\xe4rung)')
          'http://de.wikipedia.org/wiki/Elf%20(Begriffskl%C3%A4rung)'

     Parameters:

        * ‘s’ (str(100)) – the string with the URL to fix.

        * ‘charset’ (str(101)) – The target charset for the URL if the
          url was given as a string.

     Return type: str(102)

 -- Function: werkzeug.urls.url_join (base, url, allow_fragments=True)

     Join a base URL and a possibly relative URL to form an absolute
     interpretation of the latter.

     Parameters:

        * ‘base’ (‘Union’‘[’str(103)‘, ’‘Tuple’‘[’str(104)‘, ’str(105)‘,
          ’str(106)‘, ’str(107)‘, ’str(108)‘]’‘]’) – the base URL for
          the join operation.

        * ‘url’ (‘Union’‘[’str(109)‘, ’‘Tuple’‘[’str(110)‘, ’str(111)‘,
          ’str(112)‘, ’str(113)‘, ’str(114)‘]’‘]’) – the URL to join.

        * ‘allow_fragments’ (bool(115)) – indicates whether fragments
          should be allowed.

     Return type: str(116)

 -- Function: werkzeug.urls.url_parse (url, scheme=None,
          allow_fragments=True)

     Parses a URL from a string into a URL tuple.  If the
     URL is lacking a scheme it can be provided as second argument.
     Otherwise, it is ignored.  Optionally fragments can be stripped
     from the URL by setting ‘allow_fragments’ to ‘False’.

     The inverse of this function is url_unparse().

     Parameters:

        * ‘url’ (str(117)) – the URL to parse.

        * ‘scheme’ (‘Optional’‘[’str(118)‘]’) – the default schema to
          use if the URL is schemaless.

        * ‘allow_fragments’ (bool(119)) – if set to ‘False’ a fragment
          will be removed from the URL.

     Return type: werkzeug.urls.BaseURL.

 -- Function: werkzeug.urls.url_quote (string, charset='utf-8',
          errors='strict', safe='/:', unsafe='')

     URL encode a single string with a given encoding.

     Parameters:

        * ‘s’ – the string to quote.

        * ‘charset’ (str(120)) – the charset to be used.

        * ‘safe’ (‘Union’‘[’str(121)‘, ’bytes(122)‘]’) – an optional
          sequence of safe characters.

        * ‘unsafe’ (‘Union’‘[’str(123)‘, ’bytes(124)‘]’) – an optional
          sequence of unsafe characters.

        * ‘string’ (‘Union’‘[’str(125)‘, ’bytes(126)‘]’) –

        * ‘errors’ (str(127)) –

     Return type: str(128)

     New in version 0.9.2: The ‘unsafe’ parameter was added.

 -- Function: werkzeug.urls.url_quote_plus (string, charset='utf-8',
          errors='strict', safe='')

     URL encode a single string with the given encoding and convert
     whitespace to “+”.

     Parameters:

        * ‘s’ – The string to quote.

        * ‘charset’ (str(129)) – The charset to be used.

        * ‘safe’ (str(130)) – An optional sequence of safe characters.

        * ‘string’ (str(131)) –

        * ‘errors’ (str(132)) –

     Return type: str(133)

 -- Function: werkzeug.urls.url_unparse (components)

     The reverse operation to url_parse().  This accepts
     arbitrary as well as URL tuples and returns a URL as a
     string.

     Parameters: ‘components’ (‘Tuple’‘[’str(134)‘, ’str(135)‘,
     ’str(136)‘, ’str(137)‘, ’str(138)‘]’) – the parsed URL as tuple
     which should be converted into a URL string.

     Return type: str(139)

 -- Function: werkzeug.urls.url_unquote (s, charset='utf-8',
          errors='replace', unsafe='')

     URL decode a single string with a given encoding.  If the charset
     is set to ‘None’ no decoding is performed and raw bytes are
     returned.

     Parameters:

        * ‘s’ (‘Union’‘[’str(140)‘, ’bytes(141)‘]’) – the string to
          unquote.

        * ‘charset’ (str(142)) – the charset of the query string.  If
          set to ‘None’ no decoding will take place.

        * ‘errors’ (str(143)) – the error handling for the charset
          decoding.

        * ‘unsafe’ (str(144)) –

     Return type: str(145)

 -- Function: werkzeug.urls.url_unquote_plus (s, charset='utf-8',
          errors='replace')

     URL decode a single string with the given ‘charset’ and decode “+”
     to whitespace.

     Per default encoding errors are ignored.  If you want a different
     behavior you can set ‘errors’ to ‘'replace'’ or ‘'strict'’.

     Parameters:

        * ‘s’ (‘Union’‘[’str(146)‘, ’bytes(147)‘]’) – The string to
          unquote.

        * ‘charset’ (str(148)) – the charset of the query string.  If
          set to ‘None’ no decoding will take place.

        * ‘errors’ (str(149)) – The error handling for the ‘charset’
          decoding.

     Return type: str(150)

   ---------- Footnotes ----------

   (1)
https://docs.python.org/3/library/urllib.parse.html#module-urllib.parse

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/stdtypes.html#str

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/stdtypes.html#str

   (9) https://docs.python.org/3/library/stdtypes.html#str

   (10) https://docs.python.org/3/library/stdtypes.html#str

   (11) https://docs.python.org/3/library/stdtypes.html#str

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/stdtypes.html#str

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/stdtypes.html#str

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/stdtypes.html#str

   (18) https://docs.python.org/3/library/functions.html#int

   (19) https://docs.python.org/3/library/stdtypes.html#str

   (20) https://docs.python.org/3/library/stdtypes.html#str

   (21) https://docs.python.org/3/library/stdtypes.html#str

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23) https://docs.python.org/3/library/stdtypes.html#str

   (24) https://docs.python.org/3/library/stdtypes.html#str

   (25) https://docs.python.org/3/library/stdtypes.html#str

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/stdtypes.html#str

   (28) https://docs.python.org/3/library/stdtypes.html#str

   (29) https://docs.python.org/3/library/stdtypes.html#str

   (30) https://docs.python.org/3/library/stdtypes.html#bytes

   (31) https://docs.python.org/3/library/stdtypes.html#dict

   (32) https://docs.python.org/3/library/stdtypes.html#str

   (33) https://docs.python.org/3/library/stdtypes.html#str

   (34) https://docs.python.org/3/library/stdtypes.html#str

   (35) https://docs.python.org/3/library/stdtypes.html#str

   (36) https://docs.python.org/3/library/stdtypes.html#str

   (37) https://docs.python.org/3/library/stdtypes.html#str

   (38) https://docs.python.org/3/library/stdtypes.html#str

   (39) https://docs.python.org/3/library/stdtypes.html#str

   (40) https://docs.python.org/3/library/stdtypes.html#str

   (41) https://docs.python.org/3/library/stdtypes.html#str

   (42) https://docs.python.org/3/library/stdtypes.html#str

   (43) https://docs.python.org/3/library/stdtypes.html#str

   (44) https://docs.python.org/3/library/stdtypes.html#str

   (45) https://docs.python.org/3/library/stdtypes.html#str

   (46) https://docs.python.org/3/library/stdtypes.html#str

   (47) https://docs.python.org/3/library/functions.html#bool

   (48) https://docs.python.org/3/library/stdtypes.html#str

   (49) https://docs.python.org/3/library/stdtypes.html#str

   (50) https://docs.python.org/3/library/stdtypes.html#str

   (51) https://docs.python.org/3/library/stdtypes.html#str

   (52) https://docs.python.org/3/library/stdtypes.html#str

   (53) https://docs.python.org/3/library/stdtypes.html#str

   (54) https://docs.python.org/3/library/stdtypes.html#str

   (55) https://docs.python.org/3/library/stdtypes.html#str

   (56) https://docs.python.org/3/library/stdtypes.html#str

   (57) https://docs.python.org/3/library/stdtypes.html#str

   (58) https://docs.python.org/3/library/stdtypes.html#str

   (59) https://docs.python.org/3/library/functions.html#bool

   (60) https://docs.python.org/3/library/stdtypes.html#str

   (61) https://docs.python.org/3/library/stdtypes.html#str

   (62) https://docs.python.org/3/library/constants.html#None

   (63) https://docs.python.org/3/library/stdtypes.html#str

   (64) https://docs.python.org/3/library/stdtypes.html#str

   (65) https://docs.python.org/3/library/stdtypes.html#bytes

   (66) https://docs.python.org/3/library/stdtypes.html#str

   (67) https://docs.python.org/3/library/functions.html#bool

   (68) https://docs.python.org/3/library/stdtypes.html#str

   (69) https://docs.python.org/3/library/stdtypes.html#bytes

   (70) https://docs.python.org/3/library/functions.html#int

   (71) https://docs.python.org/3/library/constants.html#None

   (72) https://docs.python.org/3/library/functions.html#bool

   (73) https://docs.python.org/3/library/stdtypes.html#str

   (74) https://docs.python.org/3/library/stdtypes.html#str

   (75) https://docs.python.org/3/library/stdtypes.html#str

   (76) https://docs.python.org/3/library/stdtypes.html#str

   (77) https://docs.python.org/3/library/stdtypes.html#str

   (78) https://docs.python.org/3/library/stdtypes.html#str

   (79) https://docs.python.org/3/library/stdtypes.html#str

   (80) https://docs.python.org/3/library/functions.html#bool

   (81) https://docs.python.org/3/library/stdtypes.html#str

   (82) https://docs.python.org/3/library/stdtypes.html#str

   (83) https://docs.python.org/3/library/stdtypes.html#str

   (84) https://docs.python.org/3/library/functions.html#sorted

   (85) https://docs.python.org/3/library/constants.html#None

   (86) https://docs.python.org/3/library/stdtypes.html#str

   (87) https://docs.python.org/3/library/stdtypes.html#str

   (88) https://docs.python.org/3/library/stdtypes.html#str

   (89) https://docs.python.org/3/library/stdtypes.html#str

   (90) https://docs.python.org/3/library/stdtypes.html#str

   (91) https://docs.python.org/3/library/stdtypes.html#str

   (92) https://docs.python.org/3/library/stdtypes.html#str

   (93) https://docs.python.org/3/library/functions.html#bool

   (94) https://docs.python.org/3/library/stdtypes.html#str

   (95) https://docs.python.org/3/library/stdtypes.html#str

   (96) https://docs.python.org/3/library/stdtypes.html#str

   (97) https://docs.python.org/3/library/functions.html#sorted

   (98) https://docs.python.org/3/library/constants.html#None

   (99) https://docs.python.org/3/library/constants.html#None

   (100) https://docs.python.org/3/library/stdtypes.html#str

   (101) https://docs.python.org/3/library/stdtypes.html#str

   (102) https://docs.python.org/3/library/stdtypes.html#str

   (103) https://docs.python.org/3/library/stdtypes.html#str

   (104) https://docs.python.org/3/library/stdtypes.html#str

   (105) https://docs.python.org/3/library/stdtypes.html#str

   (106) https://docs.python.org/3/library/stdtypes.html#str

   (107) https://docs.python.org/3/library/stdtypes.html#str

   (108) https://docs.python.org/3/library/stdtypes.html#str

   (109) https://docs.python.org/3/library/stdtypes.html#str

   (110) https://docs.python.org/3/library/stdtypes.html#str

   (111) https://docs.python.org/3/library/stdtypes.html#str

   (112) https://docs.python.org/3/library/stdtypes.html#str

   (113) https://docs.python.org/3/library/stdtypes.html#str

   (114) https://docs.python.org/3/library/stdtypes.html#str

   (115) https://docs.python.org/3/library/functions.html#bool

   (116) https://docs.python.org/3/library/stdtypes.html#str

   (117) https://docs.python.org/3/library/stdtypes.html#str

   (118) https://docs.python.org/3/library/stdtypes.html#str

   (119) https://docs.python.org/3/library/functions.html#bool

   (120) https://docs.python.org/3/library/stdtypes.html#str

   (121) https://docs.python.org/3/library/stdtypes.html#str

   (122) https://docs.python.org/3/library/stdtypes.html#bytes

   (123) https://docs.python.org/3/library/stdtypes.html#str

   (124) https://docs.python.org/3/library/stdtypes.html#bytes

   (125) https://docs.python.org/3/library/stdtypes.html#str

   (126) https://docs.python.org/3/library/stdtypes.html#bytes

   (127) https://docs.python.org/3/library/stdtypes.html#str

   (128) https://docs.python.org/3/library/stdtypes.html#str

   (129) https://docs.python.org/3/library/stdtypes.html#str

   (130) https://docs.python.org/3/library/stdtypes.html#str

   (131) https://docs.python.org/3/library/stdtypes.html#str

   (132) https://docs.python.org/3/library/stdtypes.html#str

   (133) https://docs.python.org/3/library/stdtypes.html#str

   (134) https://docs.python.org/3/library/stdtypes.html#str

   (135) https://docs.python.org/3/library/stdtypes.html#str

   (136) https://docs.python.org/3/library/stdtypes.html#str

   (137) https://docs.python.org/3/library/stdtypes.html#str

   (138) https://docs.python.org/3/library/stdtypes.html#str

   (139) https://docs.python.org/3/library/stdtypes.html#str

   (140) https://docs.python.org/3/library/stdtypes.html#str

   (141) https://docs.python.org/3/library/stdtypes.html#bytes

   (142) https://docs.python.org/3/library/stdtypes.html#str

   (143) https://docs.python.org/3/library/stdtypes.html#str

   (144) https://docs.python.org/3/library/stdtypes.html#str

   (145) https://docs.python.org/3/library/stdtypes.html#str

   (146) https://docs.python.org/3/library/stdtypes.html#str

   (147) https://docs.python.org/3/library/stdtypes.html#bytes

   (148) https://docs.python.org/3/library/stdtypes.html#str

   (149) https://docs.python.org/3/library/stdtypes.html#str

   (150) https://docs.python.org/3/library/stdtypes.html#str

3.9 Context Locals
==================

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.

 -- Function: werkzeug.local.release_local (local)

     Releases the contents of the local for the current context.  This
     makes it possible to use locals without a manager.

     Example:

          >>> loc = Local()
          >>> loc.foo = 42
          >>> release_local(loc)
          >>> hasattr(loc, 'foo')
          False

     With this function one can release ‘Local’ objects as well as
     LocalStack objects.  However it is not possible to release
     data held by proxies that way, one always has to retain a reference
     to the underlying local object in order to be able to release it.

     New in version 0.6.1.

     Parameters: ‘local’ (‘Union’‘[’‘werkzeug.local.Local’‘, ’
     werkzeug.local.LocalStack.‘]’) –

     Return type: None(1)

 -- Class: werkzeug.local.LocalManager (locals=None, ident_func=None)

     Local objects cannot manage themselves.  For that you need a local
     manager.  You can pass a local manager multiple locals or add them
     later by appending them to ‘manager.locals’.  Every time the
     manager cleans up, it will clean up all the data left in the locals
     for this context.

     Changed in version 2.0: ‘ident_func’ is deprecated and will be
     removed in Werkzeug 2.1.

     Changed in version 0.7: The ‘ident_func’ parameter was added.

     Changed in version 0.6.1: The release_local() function
     can be used instead of a manager.

     Parameters:

        * ‘locals’
          (‘Optional’‘[’‘Iterable’‘[’‘Union’‘[’‘werkzeug.local.Local’‘,
          ’werkzeug.local.LocalStack.‘]’‘]’‘]’) –

        * ‘ident_func’ (None(2)) –

     Return type: None(3)

      -- Method: cleanup ()

          Manually clean up the data in the locals for this context.
          Call this at the end of the request or use
          ‘make_middleware()’.

          Return type: None(4)

      -- Method: get_ident ()

          Return the context identifier the local objects use internally
          for this context.  You cannot override this method to change
          the behavior but use it to link other context local objects
          (such as SQLAlchemy’s scoped sessions) to the Werkzeug locals.

          Deprecated since version 2.0: Will be removed in Werkzeug 2.1.

          Changed in version 0.7: You can pass a different ident
          function to the local manager that will then be propagated to
          all the locals passed to the constructor.

          Return type: int(5)

      -- Method: make_middleware (app)

          Wrap a WSGI application so that cleaning up happens after
          request end.

          Parameters: ‘app’ (‘WSGIApplication’) –

          Return type: WSGIApplication

      -- Method: middleware (func)

          Like ‘make_middleware’ but for decorating functions.

          Example usage:

               @manager.middleware
               def application(environ, start_response):
                   ...

          The difference to ‘make_middleware’ is that the function
          passed will have all the arguments copied from the inner
          application (name, docstring, module).

          Parameters: ‘func’ (‘WSGIApplication’) –

          Return type: WSGIApplication

 -- Class: werkzeug.local.LocalStack

     This class works similar to a ‘Local’ but keeps a stack of objects
     instead.  This is best explained with an example:

          >>> ls = LocalStack()
          >>> ls.push(42)
          >>> ls.top
          42
          >>> ls.push(23)
          >>> ls.top
          23
          >>> ls.pop()
          23
          >>> ls.top
          42

     They can be force released by using a LocalManager or
     with the release_local() function but the correct way
     is to pop the item from the stack after using.  When the stack is
     empty it will no longer be bound to the current context (and as
     such released).

     By calling the stack without arguments it returns a proxy that
     resolves to the topmost item on the stack.

     New in version 0.6.1.

     Return type: None(6)

      -- Method: pop ()

          Removes the topmost item from the stack, will return the old
          value or ‘None’ if the stack was already empty.

          Return type: Any

      -- Method: push (obj)

          Pushes a new item to the stack

          Parameters: ‘obj’ (‘Any’) –

          Return type: List[Any]

      -- Property: top: Any

          The topmost item on the stack.  If the stack is empty, ‘None’
          is returned.

 -- Class: werkzeug.local.LocalProxy (local, name=None)

     A proxy to the object bound to a ‘Local’.  All operations on the
     proxy are forwarded to the bound object.  If no object is bound, a
     RuntimeError(7) is raised.

          from werkzeug.local import Local
          l = Local()

          # a proxy to whatever l.user is set to
          user = l("user")

          from werkzeug.local import LocalStack
          _request_stack = LocalStack()

          # a proxy to _request_stack.top
          request = _request_stack()

          # a proxy to the session attribute of the request proxy
          session = LocalProxy(lambda: request.session)

     ‘__repr__’ and ‘__class__’ are forwarded, so ‘repr(x)’ and
     ‘isinstance(x, cls)’ will look like the proxied object.  Use
     ‘issubclass(type(x), LocalProxy)’ to check if an object is a proxy.

          repr(user)  # <User admin>
          isinstance(user, User)  # True
          issubclass(type(user), LocalProxy)  # True

     Parameters:

        * ‘local’ – The ‘Local’ or callable that provides the proxied
          object.

        * ‘name’ – The attribute name to look up on a ‘Local’.  Not used
          if a callable is given.

     Changed in version 2.0: Updated proxied attributes and methods to
     reflect the current data model.

     Changed in version 0.6.1: The class can be instantiated with a
     callable.

      -- Method: _get_current_object ()

          Return the current object.  This is useful if you want the
          real object behind the proxy at a time for performance reasons
          or because you want to pass the object into a different
          context.

          Return type: Any

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/constants.html#None

   (2) https://docs.python.org/3/library/constants.html#None

   (3) https://docs.python.org/3/library/constants.html#None

   (4) https://docs.python.org/3/library/constants.html#None

   (5) https://docs.python.org/3/library/functions.html#int

   (6) https://docs.python.org/3/library/constants.html#None

   (7) https://docs.python.org/3/library/exceptions.html#RuntimeError

3.10 Middleware
===============

A WSGI middleware is a WSGI application that wraps another application
in order to observe or change its behavior.  Werkzeug provides some
middleware for common use cases.

3.10.1 X-Forwarded-For Proxy Fix
--------------------------------

This module provides a middleware that adjusts the WSGI environ based on
‘X-Forwarded-’ headers that proxies in front of an application may set.

When an application is running behind a proxy server, WSGI may see the
request as coming from that server rather than the real client.  Proxies
set various headers to track where the request actually came from.

This middleware should only be used if the application is actually
behind such a proxy, and should be configured with the number of proxies
that are chained in front of it.  Not all proxies set all the headers.
Since incoming headers can be faked, you must set how many proxies are
setting each header so the middleware knows what to trust.

 -- Class: werkzeug.middleware.proxy_fix.ProxyFix (app, x_for=1,
          x_proto=1, x_host=0, x_port=0, x_prefix=0)

     Adjust the WSGI environ based on ‘X-Forwarded-’ that proxies in
     front of the application may set.

        - ‘X-Forwarded-For’ sets ‘REMOTE_ADDR’.

        - ‘X-Forwarded-Proto’ sets ‘wsgi.url_scheme’.

        - ‘X-Forwarded-Host’ sets ‘HTTP_HOST’, ‘SERVER_NAME’, and
          ‘SERVER_PORT’.

        - ‘X-Forwarded-Port’ sets ‘HTTP_HOST’ and ‘SERVER_PORT’.

        - ‘X-Forwarded-Prefix’ sets ‘SCRIPT_NAME’.

     You must tell the middleware how many proxies set each header so it
     knows what values to trust.  It is a security issue to trust values
     that came from the client rather than a proxy.

     The original values of the headers are stored in the WSGI environ
     as ‘werkzeug.proxy_fix.orig’, a dict.

     Parameters:

        * ‘app’ (‘WSGIApplication’) – The WSGI application to wrap.

        * ‘x_for’ (int(1)) – Number of values to trust for
          ‘X-Forwarded-For’.

        * ‘x_proto’ (int(2)) – Number of values to trust for
          ‘X-Forwarded-Proto’.

        * ‘x_host’ (int(3)) – Number of values to trust for
          ‘X-Forwarded-Host’.

        * ‘x_port’ (int(4)) – Number of values to trust for
          ‘X-Forwarded-Port’.

        * ‘x_prefix’ (int(5)) – Number of values to trust for
          ‘X-Forwarded-Prefix’.

     Return type: None(6)

          from werkzeug.middleware.proxy_fix import ProxyFix
          # App is behind one proxy that sets the -For and -Host headers.
          app = ProxyFix(app, x_for=1, x_host=1)

     Changed in version 1.0: Deprecated code has been removed:

        * The ‘num_proxies’ argument and attribute.

        * The ‘get_remote_addr’ method.

        * The environ keys ‘orig_remote_addr’, ‘orig_wsgi_url_scheme’,
          and ‘orig_http_host’.

     Changed in version 0.15: All headers support multiple values.  The
     ‘num_proxies’ argument is deprecated.  Each header is configured
     with a separate number of trusted proxies.

     Changed in version 0.15: Original WSGI environ values are stored in
     the ‘werkzeug.proxy_fix.orig’ dict.  ‘orig_remote_addr’,
     ‘orig_wsgi_url_scheme’, and ‘orig_http_host’ are deprecated and
     will be removed in 1.0.

     Changed in version 0.15: Support ‘X-Forwarded-Port’ and
     ‘X-Forwarded-Prefix’.

     Changed in version 0.15: ‘X-Forwarded-Host’ and ‘X-Forwarded-Port’
     modify ‘SERVER_NAME’ and ‘SERVER_PORT’.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/functions.html#int

   (2) https://docs.python.org/3/library/functions.html#int

   (3) https://docs.python.org/3/library/functions.html#int

   (4) https://docs.python.org/3/library/functions.html#int

   (5) https://docs.python.org/3/library/functions.html#int

   (6) https://docs.python.org/3/library/constants.html#None

3.10.2 Serve Shared Static Files
--------------------------------

 -- Class: werkzeug.middleware.shared_data.SharedDataMiddleware (app,
          exports, disallow=None, cache=True, cache_timeout=43200,
          fallback_mimetype='application/octet-stream')

     A WSGI middleware which provides static content for development
     environments or simple server setups.  Its usage is quite simple:

          import os
          from werkzeug.middleware.shared_data import SharedDataMiddleware

          app = SharedDataMiddleware(app, {
              '/shared': os.path.join(os.path.dirname(__file__), 'shared')
          })

     The contents of the folder ‘./shared’ will now be available on
     ‘http://example.com/shared/’.  This is pretty useful during
     development because a standalone media server is not required.
     Files can also be mounted on the root folder and still continue to
     use the application because the shared data middleware forwards all
     unhandled requests to the application, even if the requests are
     below one of the shared folders.

     If ‘pkg_resources’ is available you can also tell the middleware to
     serve files from package data:

          app = SharedDataMiddleware(app, {
              '/static': ('myapplication', 'static')
          })

     This will then serve the ‘static’ folder in the ‘myapplication’
     Python package.

     The optional ‘disallow’ parameter can be a list of fnmatch()(1)
     rules for files that are not accessible from the web.  If ‘cache’
     is set to ‘False’ no caching headers are sent.

     Currently the middleware does not support non-ASCII filenames.  If
     the encoding on the file system happens to match the encoding of
     the URI it may work but this could also be by accident.  We
     strongly suggest using ASCII only file names for static files.

     The middleware will guess the mimetype using the Python ‘mimetype’
     module.  If it’s unable to figure out the charset it will fall back
     to ‘fallback_mimetype’.

     Parameters:

        * ‘app’ (‘WSGIApplication’) – the application to wrap.  If you
          don’t want to wrap an application you can pass it ‘NotFound’.

        * ‘exports’ (‘Union’‘[’‘Dict’‘[’str(2)‘, ’‘Union’‘[’str(3)‘,
          ’‘Tuple’‘[’str(4)‘, ’str(5)‘]’‘]’‘]’‘,
          ’‘Iterable’‘[’‘Tuple’‘[’str(6)‘, ’‘Union’‘[’str(7)‘,
          ’‘Tuple’‘[’str(8)‘, ’str(9)‘]’‘]’‘]’‘]’‘]’) – a list or dict
          of exported files and folders.

        * ‘disallow’ (None(10)) – a list of fnmatch()(11) rules.

        * ‘cache’ (bool(12)) – enable or disable caching headers.

        * ‘cache_timeout’ (int(13)) – the cache timeout in seconds for
          the headers.

        * ‘fallback_mimetype’ (str(14)) – The fallback mimetype for
          unknown files.

     Return type: None(15)

     Changed in version 1.0: The default ‘fallback_mimetype’ is
     ‘application/octet-stream’.  If a filename looks like a text
     mimetype, the ‘utf-8’ charset is added to it.

     New in version 0.6: Added ‘fallback_mimetype’.

     Changed in version 0.5: Added ‘cache_timeout’.

      -- Method: is_allowed (filename)

          Subclasses can override this method to disallow the access to
          certain files.  However by providing ‘disallow’ in the
          constructor this method is overwritten.

          Parameters: ‘filename’ (str(16)) –

          Return type: bool(17)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/fnmatch.html#fnmatch.fnmatch

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/stdtypes.html#str

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/stdtypes.html#str

   (9) https://docs.python.org/3/library/stdtypes.html#str

   (10) https://docs.python.org/3/library/constants.html#None

   (11) https://docs.python.org/3/library/fnmatch.html#fnmatch.fnmatch

   (12) https://docs.python.org/3/library/functions.html#bool

   (13) https://docs.python.org/3/library/functions.html#int

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/constants.html#None

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/functions.html#bool

3.10.3 Application Dispatcher
-----------------------------

This middleware creates a single WSGI application that dispatches to
multiple other WSGI applications mounted at different URL paths.

A common example is writing a Single Page Application, where you have a
backend API and a frontend written in JavaScript that does the routing
in the browser rather than requesting different pages from the server.
The frontend is a single HTML and JS file that should be served for any
path besides “/api”.

This example dispatches to an API app under “/api”, an admin app under
“/admin”, and an app that serves frontend files for all other requests:

     app = DispatcherMiddleware(serve_frontend, {
         '/api': api_app,
         '/admin': admin_app,
     })

In production, you might instead handle this at the HTTP server level,
serving files or proxying to application servers based on location.  The
API and admin apps would each be deployed with a separate WSGI server,
and the static files would be served directly by the HTTP server.

 -- Class: werkzeug.middleware.dispatcher.DispatcherMiddleware (app,
          mounts=None)

     Combine multiple applications as a single WSGI application.
     Requests are dispatched to an application based on the path it is
     mounted under.

     Parameters:

        * ‘app’ (‘WSGIApplication’) – The WSGI application to dispatch
          to if the request doesn’t match a mounted path.

        * ‘mounts’ (‘Optional’‘[’‘Dict’‘[’str(1)‘,
          ’‘WSGIApplication’‘]’‘]’) – Maps path prefixes to applications
          for dispatching.

     Return type: None(2)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/constants.html#None

3.10.4 Basic HTTP Proxy
-----------------------

 -- Class: werkzeug.middleware.http_proxy.ProxyMiddleware (app, targets,
          chunk_size=16384, timeout=10)

     Proxy requests under a path to an external server, routing other
     requests to the app.

     This middleware can only proxy HTTP requests, as HTTP is the only
     protocol handled by the WSGI server.  Other protocols, such as
     WebSocket requests, cannot be proxied at this layer.  This should
     only be used for development, in production a real proxy server
     should be used.

     The middleware takes a dict mapping a path prefix to a dict
     describing the host to be proxied to:

          app = ProxyMiddleware(app, {
              "/static/": {
                  "target": "http://127.0.0.1:5001/",
              }
          })

     Each host has the following options:

     ‘target’:

          The target URL to dispatch to.  This is required.

     ‘remove_prefix’:

          Whether to remove the prefix from the URL before dispatching
          it to the target.  The default is ‘False’.

     ‘host’:

          ‘"<auto>"’ (default):

               The host header is automatically rewritten to the URL of
               the target.

          ‘None’:

               The host header is unmodified from the client request.

          Any other value:

               The host header is overwritten with the value.

     ‘headers’:

          A dictionary of headers to be sent with the request to the
          target.  The default is ‘{}’.

     ‘ssl_context’:

          A ssl.SSLContext(1) defining how to verify requests if the
          target is HTTPS. The default is ‘None’.

     In the example above, everything under ‘"/static/"’ is proxied to
     the server on port 5001.  The host header is rewritten to the
     target, and the ‘"/static/"’ prefix is removed from the URLs.

     Parameters:

        * ‘app’ (‘WSGIApplication’) – The WSGI application to wrap.

        * ‘targets’ (‘Mapping’‘[’str(2)‘, ’‘Dict’‘[’str(3)‘,
          ’‘Any’‘]’‘]’) – Proxy target configurations.  See description
          above.

        * ‘chunk_size’ (int(4)) – Size of chunks to read from input
          stream and write to target.

        * ‘timeout’ (int(5)) – Seconds before an operation to a target
          fails.

     Return type: None(6)

     New in version 0.14.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/ssl.html#ssl.SSLContext

   (2) https://docs.python.org/3/library/stdtypes.html#str

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/functions.html#int

   (5) https://docs.python.org/3/library/functions.html#int

   (6) https://docs.python.org/3/library/constants.html#None

3.10.5 WSGI Protocol Linter
---------------------------

This module provides a middleware that performs sanity checks on the
behavior of the WSGI server and application.  It checks that the PEP
3333(1) WSGI spec is properly implemented.  It also warns on some common
HTTP errors such as non-empty responses for 304 status codes.

 -- Class: werkzeug.middleware.lint.LintMiddleware (app)

     Warns about common errors in the WSGI and HTTP behavior of the
     server and wrapped application.  Some of the issues it checks are:

        - invalid status codes

        - non-bytes sent to the WSGI server

        - strings returned from the WSGI application

        - non-empty conditional responses

        - unquoted etags

        - relative URLs in the Location header

        - unsafe calls to wsgi.input

        - unclosed iterators

     Error information is emitted using the warnings(2) module.

     Parameters: ‘app’ (‘WSGIApplication’) – The WSGI application to
     wrap.

     Return type: None(3)

          from werkzeug.middleware.lint import LintMiddleware
          app = LintMiddleware(app)

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-3333

   (2) https://docs.python.org/3/library/warnings.html#module-warnings

   (3) https://docs.python.org/3/library/constants.html#None

3.10.6 Application Profiler
---------------------------

This module provides a middleware that profiles each request with the
cProfile(1) module.  This can help identify bottlenecks in your code
that may be slowing down your application.

 -- Class: werkzeug.middleware.profiler.ProfilerMiddleware (app,
          stream=<_io.TextIOWrapper name='<stdout>' mode='w'
          encoding='utf-8'>, sort_by=('time', 'calls'), restrictions=(),
          profile_dir=None,
          filename_format='{method}.{path}.{elapsed:.0f}ms.{time:.0f}.prof')

     Wrap a WSGI application and profile the execution of each request.
     Responses are buffered so that timings are more exact.

     If ‘stream’ is given, pstats.Stats(2) are written to it after each
     request.  If ‘profile_dir’ is given, cProfile(3) data files are
     saved to that directory, one file per request.

     The filename can be customized by passing ‘filename_format’.  If it
     is a string, it will be formatted using str.format()(4) with the
     following fields available:

        - ‘{method}’ - The request method; GET, POST, etc.

        - ‘{path}’ - The request path or ‘root’ should one not exist.

        - ‘{elapsed}’ - The elapsed time of the request.

        - ‘{time}’ - The time of the request.

     If it is a callable, it will be called with the WSGI ‘environ’ dict
     and should return a filename.

     Parameters:

        * ‘app’ (‘WSGIApplication’) – The WSGI application to wrap.

        * ‘stream’ (‘IO’‘[’str(5)‘]’) – Write stats to this stream.
          Disable with ‘None’.

        * ‘sort_by’ (‘Iterable’‘[’str(6)‘]’) – A tuple of columns to
          sort stats by.  See pstats.Stats.sort_stats()(7).

        * ‘restrictions’ (‘Iterable’‘[’‘Union’‘[’str(8)‘, ’int(9)‘,
          ’float(10)‘]’‘]’) – A tuple of restrictions to filter stats
          by.  See pstats.Stats.print_stats()(11).

        * ‘profile_dir’ (‘Optional’‘[’str(12)‘]’) – Save profile data
          files to this directory.

        * ‘filename_format’ (str(13)) – Format string for profile data
          file names, or a callable returning a name.  See explanation
          above.

     Return type: None(14)

          from werkzeug.middleware.profiler import ProfilerMiddleware
          app = ProfilerMiddleware(app)

     Changed in version 0.15: Stats are written even if ‘profile_dir’ is
     given, and can be disable by passing ‘stream=None’.

     New in version 0.15: Added ‘filename_format’.

     New in version 0.9: Added ‘restrictions’ and ‘profile_dir’.

The interactive debugger is also a middleware that can be
applied manually, although it is typically used automatically with the
development server.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/profile.html#module-cProfile

   (2) https://docs.python.org/3/library/profile.html#pstats.Stats

   (3) https://docs.python.org/3/library/profile.html#module-cProfile

   (4) https://docs.python.org/3/library/stdtypes.html#str.format

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/stdtypes.html#str

   (7)
https://docs.python.org/3/library/profile.html#pstats.Stats.sort_stats

   (8) https://docs.python.org/3/library/stdtypes.html#str

   (9) https://docs.python.org/3/library/functions.html#int

   (10) https://docs.python.org/3/library/functions.html#float

   (11)
https://docs.python.org/3/library/profile.html#pstats.Stats.print_stats

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/stdtypes.html#str

   (14) https://docs.python.org/3/library/constants.html#None

3.11 HTTP Exceptions
====================

Implements a number of Python exceptions which can be raised from within
a view to trigger a standard HTTP non-200 response.

3.11.1 Usage Example
--------------------

     from werkzeug.wrappers.request import Request
     from werkzeug.exceptions import HTTPException, NotFound

     def view(request):
         raise NotFound()

     @Request.application
     def application(request):
         try:
             return view(request)
         except HTTPException as e:
             return e

As you can see from this example those exceptions are callable WSGI
applications.  However, they are not Werkzeug response objects.  You can
get a response object by calling ‘get_response()’ on a HTTP exception.

Keep in mind that you may have to pass an environ (WSGI) or scope (ASGI)
to ‘get_response()’ because some errors fetch additional information
relating to the request.

If you want to hook in a different exception page to say, a 404 status
code, you can add a second except for a specific subclass of an error:

     @Request.application
     def application(request):
         try:
             return view(request)
         except NotFound as e:
             return not_found(request)
         except HTTPException as e:
             return e

3.11.2 Error Classes
--------------------

The following error classes exist in Werkzeug:

 -- Exception: werkzeug.exceptions.BadRequest (description=None,
          response=None)

     `400' ‘Bad Request’

     Raise if the browser sends something to the application the
     application or server cannot handle.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(1)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(2)

 -- Exception: werkzeug.exceptions.Unauthorized (description=None,
          response=None, www_authenticate=None)

     `401' ‘Unauthorized’

     Raise if the user is not authorized to access a resource.

     The ‘www_authenticate’ argument should be used to set the
     ‘WWW-Authenticate’ header.  This is used for HTTP basic auth and
     other schemes.  Use WWWAuthenticate to create correctly
     formatted values.  Strictly speaking a 401 response is invalid if
     it doesn’t provide at least one value for this header, although
     real clients typically don’t care.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(3)‘]’) – Override the default
          message used for the body of the response.

        * ‘www-authenticate’ – A single value, or list of values, for
          the WWW-Authenticate header(s).

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

        * ‘www_authenticate’ (‘Optional’‘[’‘Union’‘[’
          WWWAuthenticate.‘, ’‘Iterable’‘[’WWWAuthenticate.
          ‘]’‘]’‘]’) –

     Return type: None(4)

     Changed in version 2.0: Serialize multiple ‘www_authenticate’ items
     into multiple ‘WWW-Authenticate’ headers, rather than joining them
     into a single value, for better interoperability.

     Changed in version 0.15.3: If the ‘www_authenticate’ argument is
     not set, the ‘WWW-Authenticate’ header is not set.

     Changed in version 0.15.3: The ‘response’ argument was restored.

     Changed in version 0.15.1: ‘description’ was moved back as the
     first argument, restoring its previous position.

     Changed in version 0.15.0: ‘www_authenticate’ was added as the
     first argument, ahead of ‘description’.

 -- Exception: werkzeug.exceptions.Forbidden (description=None,
          response=None)

     `403' ‘Forbidden’

     Raise if the user doesn’t have the permission for the requested
     resource but was authenticated.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(5)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(6)

 -- Exception: werkzeug.exceptions.NotFound (description=None,
          response=None)

     `404' ‘Not Found’

     Raise if a resource does not exist and never existed.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(7)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(8)

 -- Exception: werkzeug.exceptions.MethodNotAllowed (valid_methods=None,
          description=None, response=None)

     `405' ‘Method Not Allowed’

     Raise if the server used a method the resource does not handle.
     For example ‘POST’ if the resource is view only.  Especially useful
     for REST.

     The first argument for this exception should be a list of allowed
     methods.  Strictly speaking the response would be invalid if you
     don’t provide valid methods in the header which you can do with
     that list.

     Takes an optional list of valid http methods starting with werkzeug
     0.3 the list will be mandatory.

     Parameters:

        * ‘valid_methods’ (‘Optional’‘[’‘Iterable’‘[’str(9)‘]’‘]’) –

        * ‘description’ (‘Optional’‘[’str(10)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(11)

 -- Exception: werkzeug.exceptions.NotAcceptable (description=None,
          response=None)

     `406' ‘Not Acceptable’

     Raise if the server can’t return any content conforming to the
     ‘Accept’ headers of the client.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(12)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(13)

 -- Exception: werkzeug.exceptions.RequestTimeout (description=None,
          response=None)

     `408' ‘Request Timeout’

     Raise to signalize a timeout.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(14)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(15)

 -- Exception: werkzeug.exceptions.Conflict (description=None,
          response=None)

     `409' ‘Conflict’

     Raise to signal that a request cannot be completed because it
     conflicts with the current state on the server.

     New in version 0.7.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(16)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(17)

 -- Exception: werkzeug.exceptions.Gone (description=None,
          response=None)

     `410' ‘Gone’

     Raise if a resource existed previously and went away without new
     location.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(18)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(19)

 -- Exception: werkzeug.exceptions.LengthRequired (description=None,
          response=None)

     `411' ‘Length Required’

     Raise if the browser submitted data but no ‘Content-Length’ header
     which is required for the kind of processing the server does.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(20)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(21)

 -- Exception: werkzeug.exceptions.PreconditionFailed (description=None,
          response=None)

     `412' ‘Precondition Failed’

     Status code used in combination with ‘If-Match’, ‘If-None-Match’,
     or ‘If-Unmodified-Since’.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(22)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(23)

 -- Exception: werkzeug.exceptions.RequestEntityTooLarge
          (description=None, response=None)

     `413' ‘Request Entity Too Large’

     The status code one should return if the data submitted exceeded a
     given limit.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(24)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(25)

 -- Exception: werkzeug.exceptions.RequestURITooLarge (description=None,
          response=None)

     `414' ‘Request URI Too Large’

     Like `413' but for too long URLs.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(26)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(27)

 -- Exception: werkzeug.exceptions.UnsupportedMediaType
          (description=None, response=None)

     `415' ‘Unsupported Media Type’

     The status code returned if the server is unable to handle the
     media type the client transmitted.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(28)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(29)

 -- Exception: werkzeug.exceptions.RequestedRangeNotSatisfiable
          (length=None, units='bytes', description=None, response=None)

     `416' ‘Requested Range Not Satisfiable’

     The client asked for an invalid part of the file.

     New in version 0.7.

     Takes an optional ‘Content-Range’ header value based on ‘length’
     parameter.

     Parameters:

        * ‘length’ (‘Optional’‘[’int(30)‘]’) –

        * ‘units’ (str(31)) –

        * ‘description’ (‘Optional’‘[’str(32)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(33)

 -- Exception: werkzeug.exceptions.ExpectationFailed (description=None,
          response=None)

     `417' ‘Expectation Failed’

     The server cannot meet the requirements of the Expect
     request-header.

     New in version 0.7.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(34)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(35)

 -- Exception: werkzeug.exceptions.ImATeapot (description=None,
          response=None)

     `418' ‘I’m a teapot’

     The server should return this if it is a teapot and someone
     attempted to brew coffee with it.

     New in version 0.7.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(36)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(37)

 -- Exception: werkzeug.exceptions.UnprocessableEntity
          (description=None, response=None)

     `422' ‘Unprocessable Entity’

     Used if the request is well formed, but the instructions are
     otherwise incorrect.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(38)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(39)

 -- Exception: werkzeug.exceptions.Locked (description=None,
          response=None)

     `423' ‘Locked’

     Used if the resource that is being accessed is locked.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(40)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(41)

 -- Exception: werkzeug.exceptions.FailedDependency (description=None,
          response=None)

     `424' ‘Failed Dependency’

     Used if the method could not be performed on the resource because
     the requested action depended on another action and that action
     failed.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(42)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(43)

 -- Exception: werkzeug.exceptions.PreconditionRequired
          (description=None, response=None)

     `428' ‘Precondition Required’

     The server requires this request to be conditional, typically to
     prevent the lost update problem, which is a race condition between
     two or more clients attempting to update a resource through PUT or
     DELETE. By requiring each client to include a conditional header
     (“If-Match” or “If-Unmodified- Since”) with the proper value
     retained from a recent GET request, the server ensures that each
     client has at least seen the previous revision of the resource.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(44)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(45)

 -- Exception: werkzeug.exceptions.TooManyRequests (description=None,
          response=None, retry_after=None)

     `429' ‘Too Many Requests’

     The server is limiting the rate at which this user receives
     responses, and this request exceeds that rate.  (The server may use
     any convenient method to identify users and their request rates).
     The server may include a “Retry-After” header to indicate how long
     the user should wait before retrying.

     Parameters:

        * ‘retry_after’ (‘Optional’‘[’‘Union’‘[’datetime.datetime(46)‘,
          ’int(47)‘]’‘]’) – If given, set the ‘Retry-After’ header to
          this value.  May be an int(48) number of seconds or a
          datetime(49).

        * ‘description’ (‘Optional’‘[’str(50)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(51)

     Changed in version 1.0: Added ‘retry_after’ parameter.

 -- Exception: werkzeug.exceptions.RequestHeaderFieldsTooLarge
          (description=None, response=None)

     `431' ‘Request Header Fields Too Large’

     The server refuses to process the request because the header fields
     are too large.  One or more individual fields may be too large, or
     the set of all headers is too large.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(52)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(53)

 -- Exception: werkzeug.exceptions.UnavailableForLegalReasons
          (description=None, response=None)

     `451' ‘Unavailable For Legal Reasons’

     This status code indicates that the server is denying access to the
     resource as a consequence of a legal demand.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(54)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(55)

 -- Exception: werkzeug.exceptions.InternalServerError
          (description=None, response=None, original_exception=None)

     `500' ‘Internal Server Error’

     Raise if an internal server error occurred.  This is a good
     fallback if an unknown error occurred in the dispatcher.

     Changed in version 1.0.0: Added the original_exception.
     attribute.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(56)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

        * ‘original_exception’ (‘Optional’‘[’BaseException(57)‘]’) –

     Return type: None(58)

      -- Attribute: original_exception

          The original exception that caused this 500 error.  Can be
          used by frameworks to provide context when handling unexpected
          errors.

 -- Exception: werkzeug.exceptions.NotImplemented (description=None,
          response=None)

     `501' ‘Not Implemented’

     Raise if the application does not support the action requested by
     the browser.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(59)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(60)

 -- Exception: werkzeug.exceptions.BadGateway (description=None,
          response=None)

     `502' ‘Bad Gateway’

     If you do proxying in your application you should return this
     status code if you received an invalid response from the upstream
     server it accessed in attempting to fulfill the request.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(61)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(62)

 -- Exception: werkzeug.exceptions.ServiceUnavailable (description=None,
          response=None, retry_after=None)

     `503' ‘Service Unavailable’

     Status code you should return if a service is temporarily
     unavailable.

     Parameters:

        * ‘retry_after’ (‘Optional’‘[’‘Union’‘[’datetime.datetime(63)‘,
          ’int(64)‘]’‘]’) – If given, set the ‘Retry-After’ header to
          this value.  May be an int(65) number of seconds or a
          datetime(66).

        * ‘description’ (‘Optional’‘[’str(67)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(68)

     Changed in version 1.0: Added ‘retry_after’ parameter.

 -- Exception: werkzeug.exceptions.GatewayTimeout (description=None,
          response=None)

     `504' ‘Gateway Timeout’

     Status code you should return if a connection to an upstream server
     times out.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(69)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(70)

 -- Exception: werkzeug.exceptions.HTTPVersionNotSupported
          (description=None, response=None)

     `505' ‘HTTP Version Not Supported’

     The server does not support the HTTP protocol version used in the
     request.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(71)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(72)

 -- Exception: werkzeug.exceptions.ClientDisconnected (description=None,
          response=None)

     Internal exception that is raised if Werkzeug detects a
     disconnected client.  Since the client is already gone at that
     point attempting to send the error message to the client might not
     work and might ultimately result in another exception in the
     server.  Mainly this is here so that it is silenced by default as
     far as Werkzeug is concerned.

     Since disconnections cannot be reliably detected and are
     unspecified by WSGI to a large extent this might or might not be
     raised if a client is gone.

     New in version 0.8.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(73)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(74)

 -- Exception: werkzeug.exceptions.SecurityError (description=None,
          response=None)

     Raised if something triggers a security error.  This is otherwise
     exactly like a bad request error.

     New in version 0.9.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(75)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(76)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/constants.html#None

   (3) https://docs.python.org/3/library/stdtypes.html#str

   (4) https://docs.python.org/3/library/constants.html#None

   (5) https://docs.python.org/3/library/stdtypes.html#str

   (6) https://docs.python.org/3/library/constants.html#None

   (7) https://docs.python.org/3/library/stdtypes.html#str

   (8) https://docs.python.org/3/library/constants.html#None

   (9) https://docs.python.org/3/library/stdtypes.html#str

   (10) https://docs.python.org/3/library/stdtypes.html#str

   (11) https://docs.python.org/3/library/constants.html#None

   (12) https://docs.python.org/3/library/stdtypes.html#str

   (13) https://docs.python.org/3/library/constants.html#None

   (14) https://docs.python.org/3/library/stdtypes.html#str

   (15) https://docs.python.org/3/library/constants.html#None

   (16) https://docs.python.org/3/library/stdtypes.html#str

   (17) https://docs.python.org/3/library/constants.html#None

   (18) https://docs.python.org/3/library/stdtypes.html#str

   (19) https://docs.python.org/3/library/constants.html#None

   (20) https://docs.python.org/3/library/stdtypes.html#str

   (21) https://docs.python.org/3/library/constants.html#None

   (22) https://docs.python.org/3/library/stdtypes.html#str

   (23) https://docs.python.org/3/library/constants.html#None

   (24) https://docs.python.org/3/library/stdtypes.html#str

   (25) https://docs.python.org/3/library/constants.html#None

   (26) https://docs.python.org/3/library/stdtypes.html#str

   (27) https://docs.python.org/3/library/constants.html#None

   (28) https://docs.python.org/3/library/stdtypes.html#str

   (29) https://docs.python.org/3/library/constants.html#None

   (30) https://docs.python.org/3/library/functions.html#int

   (31) https://docs.python.org/3/library/stdtypes.html#str

   (32) https://docs.python.org/3/library/stdtypes.html#str

   (33) https://docs.python.org/3/library/constants.html#None

   (34) https://docs.python.org/3/library/stdtypes.html#str

   (35) https://docs.python.org/3/library/constants.html#None

   (36) https://docs.python.org/3/library/stdtypes.html#str

   (37) https://docs.python.org/3/library/constants.html#None

   (38) https://docs.python.org/3/library/stdtypes.html#str

   (39) https://docs.python.org/3/library/constants.html#None

   (40) https://docs.python.org/3/library/stdtypes.html#str

   (41) https://docs.python.org/3/library/constants.html#None

   (42) https://docs.python.org/3/library/stdtypes.html#str

   (43) https://docs.python.org/3/library/constants.html#None

   (44) https://docs.python.org/3/library/stdtypes.html#str

   (45) https://docs.python.org/3/library/constants.html#None

   (46)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (47) https://docs.python.org/3/library/functions.html#int

   (48) https://docs.python.org/3/library/functions.html#int

   (49)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (50) https://docs.python.org/3/library/stdtypes.html#str

   (51) https://docs.python.org/3/library/constants.html#None

   (52) https://docs.python.org/3/library/stdtypes.html#str

   (53) https://docs.python.org/3/library/constants.html#None

   (54) https://docs.python.org/3/library/stdtypes.html#str

   (55) https://docs.python.org/3/library/constants.html#None

   (56) https://docs.python.org/3/library/stdtypes.html#str

   (57) https://docs.python.org/3/library/exceptions.html#BaseException

   (58) https://docs.python.org/3/library/constants.html#None

   (59) https://docs.python.org/3/library/stdtypes.html#str

   (60) https://docs.python.org/3/library/constants.html#None

   (61) https://docs.python.org/3/library/stdtypes.html#str

   (62) https://docs.python.org/3/library/constants.html#None

   (63)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (64) https://docs.python.org/3/library/functions.html#int

   (65) https://docs.python.org/3/library/functions.html#int

   (66)
https://docs.python.org/3/library/datetime.html#datetime.datetime

   (67) https://docs.python.org/3/library/stdtypes.html#str

   (68) https://docs.python.org/3/library/constants.html#None

   (69) https://docs.python.org/3/library/stdtypes.html#str

   (70) https://docs.python.org/3/library/constants.html#None

   (71) https://docs.python.org/3/library/stdtypes.html#str

   (72) https://docs.python.org/3/library/constants.html#None

   (73) https://docs.python.org/3/library/stdtypes.html#str

   (74) https://docs.python.org/3/library/constants.html#None

   (75) https://docs.python.org/3/library/stdtypes.html#str

   (76) https://docs.python.org/3/library/constants.html#None

3.11.3 Baseclass
----------------

All the exceptions implement this common interface:

 -- Exception: werkzeug.exceptions.HTTPException (description=None,
          response=None)

     The base class for all HTTP exceptions.  This exception can be
     called as a WSGI application to render a default error page or you
     can catch the subclasses of it independently and render nicer error
     messages.

     Parameters:

        * ‘description’ (‘Optional’‘[’str(1)‘]’) –

        * ‘response’ (‘Optional’‘[’Response.‘]’) –

     Return type: None(2)

      -- Method: __call__ (environ, start_response)

          Call the exception as WSGI application.

          Parameters:

             * ‘environ’ (‘WSGIEnvironment’) – the WSGI environment.

             * ‘start_response’ (‘StartResponse’) – the response
               callable provided by the WSGI server.

          Return type: Iterable[bytes(3)]

      -- Method: get_response (environ=None, scope=None)

          Get a response object.  If one was passed to the exception
          it’s returned directly.

          Parameters:

             * ‘environ’ (‘Optional’‘[’‘WSGIEnvironment’‘]’) – the
               optional environ for the request.  This can be used to
               modify the response depending on how the request looked
               like.

             * ‘scope’ (‘Optional’‘[’dict(4)‘]’) –

          Returns: a ‘Response’ object or a subclass thereof.

          Return type: Response.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str

   (2) https://docs.python.org/3/library/constants.html#None

   (3) https://docs.python.org/3/library/stdtypes.html#bytes

   (4) https://docs.python.org/3/library/stdtypes.html#dict

3.11.4 Special HTTP Exceptions
------------------------------

Starting with Werkzeug 0.3 some of the builtin classes raise exceptions
that look like regular python exceptions (eg KeyError(1)) but are
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 KeyError(2) but also a BadRequest
exception.

 -- Exception: werkzeug.exceptions.BadRequestKeyError (arg=None, *args,
          **kwargs)

     An exception that is used to signal both a KeyError(3) and a
     BadRequest.  Used by many of the datastructures.

     Parameters:

        * ‘arg’ (‘Optional’‘[’str(4)‘]’) –

        * ‘args’ (‘Any’) –

        * ‘kwargs’ (‘Any’) –

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/exceptions.html#KeyError

   (2) https://docs.python.org/3/library/exceptions.html#KeyError

   (3) https://docs.python.org/3/library/exceptions.html#KeyError

   (4) https://docs.python.org/3/library/stdtypes.html#str

3.11.5 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 abort() function.

 -- Function: werkzeug.exceptions.abort (status, *args, **kwargs)

     Raises an HTTPException for the given status code or
     WSGI application.

     If a status code is given, it will be looked up in the list of
     exceptions and will raise that exception.  If passed a WSGI
     application, it will wrap it in a proxy WSGI exception and raise
     that:

          abort(404)  # 404 Not Found
          abort(Response('Hello World'))

     Parameters:

        * ‘status’ (‘Union’‘[’int(1)‘, ’Response.‘]’) –

        * ‘args’ (‘Any’) –

        * ‘kwargs’ (‘Any’) –

     Return type: te.NoReturn

If you want to use this functionality with custom exceptions you can
create an instance of the aborter class:

 -- Class: werkzeug.exceptions.Aborter (mapping=None, extra=None)

     When passed a dict of code -> exception items it can be used as
     callable that raises exceptions.  If the first argument to the
     callable is an integer it will be looked up in the mapping, if it’s
     a WSGI application it will be raised in a proxy exception.

     The rest of the arguments are forwarded to the exception
     constructor.

     Parameters:

        * ‘mapping’ (‘Optional’‘[’‘Dict’‘[’int(2)‘, ’‘Type’‘[’
          werkzeug.exceptions.HTTPException.‘]’‘]’‘]’) –

        * ‘extra’ (‘Optional’‘[’‘Dict’‘[’int(3)‘, ’‘Type’‘[’
          werkzeug.exceptions.HTTPException.‘]’‘]’‘]’) –

     Return type: None(4)

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/functions.html#int

   (2) https://docs.python.org/3/library/functions.html#int

   (3) https://docs.python.org/3/library/functions.html#int

   (4) https://docs.python.org/3/library/constants.html#None

3.11.6 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
‘redirect()’ function from the utilities.

If you want to add an error yourself you can subclass
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
‘get_description()’, ‘get_body()’, ‘get_headers()’ and
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:

     raise BadRequest(description='Request failed because X was not present')

4 Deployment
************

4.1 Application Deployment
==========================

This section covers running your application in production on a web
server such as Apache or lighttpd.

4.1.1 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(1), there however the execution does happen in a CGI-like
environment.  The application’s performance is unaffected because of
that.

   ---------- Footnotes ----------

   (1) https://cloud.google.com/appengine/

4.1.1.1 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)

4.1.1.2 Server Setup
....................

Usually there are two ways to configure the server.  Either just copy
the ‘.cgi’ into a ‘cgi-bin’ (and use ‘mod_rewrite’ or something similar
to rewrite the URL) or let the server point to the file directly.

In Apache for example you can put something like this into the config:

     ScriptAlias /app /path/to/the/application.cgi

For more information consult the documentation of your webserver.

4.1.2 ‘mod_wsgi’ (Apache)
-------------------------

If you are using the Apache(1) webserver you should consider using
mod_wsgi(2).

   ---------- Footnotes ----------

   (1) https://httpd.apache.org/

   (2) https://modwsgi.readthedocs.io/en/develop/

4.1.2.1 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(1) 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.

   ---------- Footnotes ----------

   (1) https://modwsgi.readthedocs.io/en/develop/installation.html

4.1.2.2 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(1)
instance.

   ---------- Footnotes ----------

   (1) https://pypi.org/project/virtualenv/

4.1.2.3 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:

     <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>

4.1.3 FastCGI
-------------

A very popular deployment setup on servers like lighttpd(1) and nginx(2)
is FastCGI. To use your WSGI application with any of them you will need
a FastCGI server first.

The most popular one is flup(3) which we will use for this guide.  Make
sure to have it installed.

   ---------- Footnotes ----------

   (1) https://www.lighttpd.net/

   (2) https://nginx.org/

   (3) https://pypi.org/project/flup/

4.1.3.1 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 ‘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

4.1.3.2 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’.

See the Lighty docs for more information on FastCGI and Python(1).

   ---------- Footnotes ----------

   (1)
https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModFastCGI

4.1.3.3 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

4.1.3.4 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.

4.1.4 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.

4.1.4.1 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 ProxyFix middleware.

4.1.4.2 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

5 Additional Information
************************

5.1 Important Terms
===================

This page covers important terms used in the documentation and Werkzeug
itself.

5.1.1 WSGI
----------

WSGI a specification for Python web applications Werkzeug follows.  It
was specified in the PEP 3333(1) and is widely supported.  Unlike
previous solutions it guarantees that web applications, servers and
utilities can work together.

   ---------- Footnotes ----------

   (1) https://www.python.org/dev/peps/pep-3333

5.1.2 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 ‘Response’ class or a
subclass thereof.

For example Pylons/webob provide a very similar response class that can
be used as well (‘webob.Response’).

5.1.3 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.

5.2 Unicode
===========

Werkzeug uses strings internally everwhere text data is assumed, even if
the HTTP standard is not Unicode aware.  Basically all incoming data is
decoded from the charset (UTF-8 by default) so that you don’t work with
bytes directly.  Outgoing data is encoded into the target charset.

5.2.1 Unicode in Python
-----------------------

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 different when encoded:

     >>> "ö".encode("latin1")
     b'\xf6'
     >>> "ö".encode("utf-8")
     b'\xc3\xb6'

An ‘ö’ looks different depending on the encoding which makes it hard to
work with it as bytes.  Instead, Python treats strings as Unicode text
and stores the information ‘LATIN SMALL LETTER O WITH DIAERESIS’ instead
of the bytes for ‘ö’ in a specific encoding.  The length of a string
with 1 character will be 1, where the length of the bytes might be some
other value.

5.2.2 Unicode in HTTP
---------------------

However, the HTTP spec was written in a time where ASCII bytes were the
common way data was represented.  To work around this for the modern
web, Werkzeug decodes and encodes incoming and outgoing data
automatically.  Data sent from the browser to the web application is
decoded from UTF-8 bytes into a string.  Data sent from the application
back to the browser is encoded back to UTF-8.

5.2.3 Error Handling
--------------------

Functions that do internal encoding or decoding accept an ‘errors’
keyword argument that is passed to ‘str.decode()’ and str.encode()(1).
The default is ‘'replace'’ so that errors are easy to spot.  It might be
useful to set it to ‘'strict'’ in order to catch the error and report
the bad data to the client.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/stdtypes.html#str.encode

5.2.4 Request and Response Objects
----------------------------------

In most cases, you should stick with Werkzeug’s default encoding of
UTF-8.  If you have a specific reason to, you can subclass
wrappers.Request and wrappers.Response to change the
encoding and error handling.

     from werkzeug.wrappers.request import Request
     from werkzeug.wrappers.response import Response

     class Latin1Request(Request):
         charset = "latin1"
         encoding_errors = "strict"

     class Latin1Response(Response):
         charset = "latin1"

The error handling can only be changed for the request.  Werkzeug will
always raise errors when encoding to bytes in the response.  It’s your
responsibility to not create data that is not present in the target
charset.  This is not an issue for UTF-8.

5.3 The Filesystem
==================

Changed in version 0.11.

Several bug reports against Werkzeug have shown that the value of
sys.getfilesystemencoding()(1) cannot be trusted under traditional UNIX
systems.  Usually this occurs due to a misconfigured system where ‘LANG’
and similar environment variables are not set.  In such cases, Python
defaults to ASCII as the filesystem encoding, a very conservative
default that is usually wrong and causes more problems than it avoids.

If Werkzeug detects it’s running in a misconfigured environment, it will
assume the filesystem encoding is ‘UTF-8’ and issue a warning.

See werkzeug.filesystem.

   ---------- Footnotes ----------

   (1)
https://docs.python.org/3/library/sys.html#sys.getfilesystemencoding

5.4 Dealing with Request Data
=============================

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.

5.4.1 Missing EOF Marker on Input Stream
----------------------------------------

The input stream has no end-of-file marker.  If you would call the
‘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 ‘LimitedStream’.  The input stream is exposed on the
request objects as ‘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.

5.4.2 When does Werkzeug Parse?
-------------------------------

Werkzeug parses the incoming data under the following situations:

   - you access either ‘form’, ‘files’, or ‘stream’ and the request
     method was ‘POST’ or ‘PUT’.

   - if you call ‘parse_form_data()’.

These calls are not interchangeable.  If you invoke ‘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.

5.4.3 How does it Parse?
------------------------

The standard Werkzeug parsing behavior handles three cases:

   - input content type was ‘multipart/form-data’.  In this situation
     the ‘stream’ will be empty and ‘form’ will contain the regular
     ‘POST’ / ‘PUT’ data, ‘files’ will contain the uploaded files as
     ‘FileStorage’ objects.

   - input content type was ‘application/x-www-form-urlencoded’.  Then
     the ‘stream’ will be empty and ‘form’ will contain the regular
     ‘POST’ / ‘PUT’ data and ‘files’ will be empty.

   - the input content type was neither of them, ‘stream’ points to a
     ‘LimitedStream’ with the input data for further processing.

Special note on the ‘get_data’ method: Calling this loads the full
request data into memory.  This is only safe to do if the
‘max_content_length’ is set.  Also you can `either' read the stream `or'
call ‘get_data()’.

5.4.4 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 ‘Request’ class
has two attributes for that: ‘max_content_length’ and
‘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
‘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.

5.4.5 How to extend Parsing?
----------------------------

Modern web applications transmit a lot more than multipart form data or
url encoded data.  To extend the capabilities, subclass ‘Request’ or
‘Request’ and add or extend methods.

5.5 BSD-3-Clause License
========================

Copyright 2007 Pallets

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

  1. Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

  2. 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.

  3. Neither the name of the copyright holder nor the names of its
     contributors may 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
HOLDER 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.

5.6.1 Version 2.0.2
-------------------

Released 2021-10-05

   - Handle multiple tokens in ‘Connection’ header when routing
     WebSocket requests.  #2131(1)

   - Set the debugger pin cookie secure flag when on https.  #2150(2)

   - Fix type annotation for ‘MultiDict.update’ to accept iterable
     values #2142(3)

   - Prevent double encoding of redirect URL when ‘merge_slash=True’ for
     ‘Rule.match’.  #2157(4)

   - ‘CombinedMultiDict.to_dict’ with ‘flat=False’ considers all
     component dicts when building value lists.  #2189(5)

   - ‘send_file’ only sets a detected ‘Content-Encoding’ if
     ‘as_attachment’ is disabled to avoid browsers saving decompressed
     ‘.tar.gz’ files.  #2149(6)

   - Fix type annotations for ‘TypeConversionDict.get’ to not return an
     ‘Optional’ value if both ‘default’ and ‘type’ are not ‘None’.
     #2169(7)

   - Fix type annotation for routing rule factories to accept
     ‘Iterable[RuleFactory]’ instead of ‘Iterable[Rule]’ for the ‘rules’
     parameter.  #2183(8)

   - Add missing type annotation for ‘FileStorage.__getattr__’ #2155(9)

   - The debugger pin cookie is set with ‘SameSite’ set to ‘Strict’
     instead of ‘None’ to be compatible with modern browser security.
     #2156(10)

   - Type annotations use ‘IO[bytes]’ and ‘IO[str]’ instead of
     ‘BinaryIO’ and ‘TextIO’ for wider type compatibility.  #2130(11)

   - Ad-hoc TLS certs are generated with SAN matching CN. #2158(12)

   - Fix memory usage for locals when using Python 3.6 or pre 0.4.17
     greenlet versions.  #2212(13)

   - Fix type annotation in ‘CallbackDict’, because it is not utilizing
     a bound TypeVar.  #2235(14)

   - Fix setting CSP header options on the response.  #2237(15)

   - Fix an issue with with the interactive debugger where lines would
     not expand on click for very long tracebacks.  #2239(16)

   - The interactive debugger handles displaying an exception that does
     not have a traceback, such as from ‘ProcessPoolExecutor’.
     #2217(17)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/2131

   (2) https://github.com/pallets/werkzeug/pull/2150

   (3) https://github.com/pallets/werkzeug/pull/2142

   (4) https://github.com/pallets/werkzeug/issues/2157

   (5) https://github.com/pallets/werkzeug/issues/2189

   (6) https://github.com/pallets/werkzeug/issues/2149

   (7) https://github.com/pallets/werkzeug/issues/2169

   (8) https://github.com/pallets/werkzeug/issues/2183

   (9) https://github.com/pallets/werkzeug/issues/2155

   (10) https://github.com/pallets/werkzeug/issues/2156

   (11) https://github.com/pallets/werkzeug/issues/2130

   (12) https://github.com/pallets/werkzeug/issues/2158

   (13) https://github.com/pallets/werkzeug/pull/2212

   (14) https://github.com/pallets/werkzeug/issues/2235

   (15) https://github.com/pallets/werkzeug/pull/2237

   (16) https://github.com/pallets/werkzeug/pull/2239

   (17) https://github.com/pallets/werkzeug/issues/2217

5.6.2 Version 2.0.1
-------------------

Released 2021-05-17

   - Fix type annotation for ‘send_file’ ‘max_age’ callable.  Don’t pass
     ‘pathlib.Path’ to ‘max_age’.  #2119(1)

   - Mark top-level names as exported so type checking understands
     imports in user projects.  #2122(2)

   - Fix some types that weren’t available in Python 3.6.0.  #2123(3)

   - ‘cached_property’ is generic over its return type, properties
     decorated with it report the correct type.  #2113(4)

   - Fix multipart parsing bug when boundary contains special regex
     characters.  #2125(5)

   - Type checking understands that calling ‘headers.get’ with a string
     default will always return a string.  #2128(6)

   - If ‘HTTPException.description’ is not a string, ‘get_description’
     will convert it to a string.  #2115(7)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/2119

   (2) https://github.com/pallets/werkzeug/issues/2122

   (3) https://github.com/pallets/werkzeug/issues/2123

   (4) https://github.com/pallets/werkzeug/issues/2113

   (5) https://github.com/pallets/werkzeug/issues/2125

   (6) https://github.com/pallets/werkzeug/issues/2128

   (7) https://github.com/pallets/werkzeug/issues/2115

5.6.3 Version 2.0.0
-------------------

Released 2021-05-11

   - Drop support for Python 2 and 3.5.  #1693(1)

   - Deprecate ‘utils.format_string()’, use string.Template(2) instead.
     #1756(3)

   - Deprecate utils.bind_arguments() and
     utils.validate_arguments(), use ‘Signature.bind()’ and
     inspect.signature()(4) instead.  #1757(5)

   - Deprecate utils.HTMLBuilder.  #1761(6)

   - Deprecate utils.escape() and utils.unescape(),
     use MarkupSafe instead.  #1758(7)

   - Deprecate the undocumented ‘python -m werkzeug.serving’ CLI.
     #1834(8)

   - Deprecate the ‘environ["werkzeug.server.shutdown"]’ function that
     is available when running the development server.  #1752(9)

   - Deprecate the ‘useragents’ module and the built-in user agent
     parser.  Use a dedicated parser library instead by subclassing
     ‘user_agent.UserAgent’ and setting ‘Request.user_agent_class’.
     #2078(10)

   - Remove the unused, internal ‘posixemulation’ module.  #1759(11)

   - All ‘datetime’ values are timezone-aware with
     ‘tzinfo=timezone.utc’.  This applies to anything using
     ‘http.parse_date’: ‘Request.date’, ‘.if_modified_since’,
     ‘.if_unmodified_since’; ‘Response.date’, ‘.expires’,
     ‘.last_modified’, ‘.retry_after’; ‘parse_if_range_header’, and
     ‘IfRange.date’.  When comparing values, the other values must also
     be aware, or these values must be made naive.  When passing
     parameters or setting attributes, naive values are still assumed to
     be in UTC. #2040(12)

   - Merge all request and response wrapper mixin code into single
     ‘Request’ and ‘Response’ classes.  Using the mixin classes is no
     longer necessary and will show a deprecation warning.  Checking
     ‘isinstance’ or ‘issubclass’ against ‘BaseRequest’ and
     ‘BaseResponse’ will show a deprecation warning and check against
     ‘Request’ or ‘Response’ instead.  #1963(13)

   - JSON support no longer uses simplejson if it’s installed.  To use
     another JSON module, override ‘Request.json_module’ and
     ‘Response.json_module’.  #1766(14)

   - ‘Response.get_json()’ no longer caches the result, and the ‘cache’
     parameter is removed.  #1698(15)

   - ‘Response.freeze()’ generates an ‘ETag’ header if one is not set.
     The ‘no_etag’ parameter (which usually wasn’t visible anyway) is no
     longer used.  #1963(16)

   - Add a ‘url_scheme’ argument to build() to override the
     bound scheme.  #1721(17)

   - Passing an empty list as a query string parameter to ‘build()’
     won’t append an unnecessary ‘?’.  Also drop any number of ‘None’
     items in a list.  #1992(18)

   - When passing a ‘Headers’ object to a test client method or
     ‘EnvironBuilder’, multiple values for a key are joined into one
     comma separated value.  This matches the HTTP spec on multi-value
     headers.  #1655(19)

   - Setting ‘Response.status’ and ‘status_code’ uses identical parsing
     and error checking.  #1658(20), #1728(21)

   - ‘MethodNotAllowed’ and ‘RequestedRangeNotSatisfiable’ take a
     ‘response’ kwarg, consistent with other HTTP errors.  #1748(22)

   - The response generated by Unauthorized produces one
     ‘WWW-Authenticate’ header per value in ‘www_authenticate’, rather
     than joining them into a single value, to improve interoperability
     with browsers and other clients.  #1755(23)

   - If ‘parse_authorization_header’ can’t decode the header value, it
     returns ‘None’ instead of raising a ‘UnicodeDecodeError’.
     #1816(24)

   - The debugger no longer uses jQuery.  #1807(25)

   - The test client includes the query string in ‘REQUEST_URI’ and
     ‘RAW_URI’.  #1781(26)

   - Switch the parameter order of ‘default_stream_factory’ to match the
     order used when calling it.  #1085(27)

   - Add ‘send_file’ function to generate a response that serves a file.
     Adapted from Flask’s implementation.  #265(28), #1850(29)

   - Add ‘send_from_directory’ function to safely serve an untrusted
     path within a trusted directory.  Adapted from Flask’s
     implementation.  #1880(30)

   - ‘send_file’ takes ‘download_name’, which is passed even if
     ‘as_attachment=False’ by using ‘Content-Disposition: inline’.
     ‘download_name’ replaces Flask’s ‘attachment_filename’.  #1869(31)

   - ‘send_file’ sets ‘conditional=True’ and ‘max_age=None’ by default.
     ‘Cache-Control’ is set to ‘no-cache’ if ‘max_age’ is not set,
     otherwise ‘public’.  This tells browsers to validate conditional
     requests instead of using a timed cache.  ‘max_age=None’ replaces
     Flask’s ‘cache_timeout=43200’.  #1882(32)

   - ‘send_file’ can be called with ‘etag="string"’ to set a custom ETag
     instead of generating one.  ‘etag’ replaces Flask’s ‘add_etags’.
     #1868(33)

   - ‘send_file’ sets the ‘Content-Encoding’ header if an encoding is
     returned when guessing ‘mimetype’ from ‘download_name’.  #3896(34)

   - Update the defaults used by ‘generate_password_hash’.  Increase
     PBKDF2 iterations to 260000 from 150000.  Increase salt length to
     16 from 8.  Use ‘secrets’ module to generate salt.  #1935(35)

   - The reloader doesn’t crash if ‘sys.stdin’ is somehow ‘None’.
     #1915(36)

   - Add arguments to ‘delete_cookie’ to match ‘set_cookie’ and the
     attributes modern browsers expect.  #1889(37)

   - ‘utils.cookie_date’ is deprecated, use ‘utils.http_date’ instead.
     The value for ‘Set-Cookie expires’ is no longer “-” delimited.
     #2040(38)

   - Use ‘request.headers’ instead of ‘request.environ’ to look up
     header attributes.  #1808(39)

   - The test ‘Client’ request methods (‘client.get’, etc.)  always
     return an instance of ‘TestResponse’.  In addition to the normal
     behavior of ‘Response’, this class provides ‘request’ with the
     request that produced the response, and ‘history’ to track
     intermediate responses when ‘follow_redirects’ is used.
     #763(40)#1894(41)

   - The test ‘Client’ request methods takes an ‘auth’ parameter to add
     an ‘Authorization’ header.  It can be an ‘Authorization’ object or
     a ‘(username, password)’ tuple for ‘Basic’ auth.  #1809(42)

   - Calling ‘response.close()’ on a response from the test ‘Client’
     will close the request input stream.  This matches file behavior
     and can prevent a ‘ResourceWarning’ in some cases.  #1785(43)

   - ‘EnvironBuilder.from_environ’ decodes values encoded for WSGI, to
     avoid double encoding the new values.  #1959(44)

   - The default stat reloader will watch Python files under
     non-system/virtualenv ‘sys.path’ entries, which should contain most
     user code.  It will also watch all Python files under directories
     given in ‘extra_files’.  #1945(45)

   - The reloader ignores ‘__pycache__’ directories again.  #1945(46)

   - ‘run_simple’ takes ‘exclude_patterns’ a list of ‘fnmatch’ patterns
     that will not be scanned by the reloader.  #1333(47)

   - Cookie names are no longer unquoted.  This was against RFC 6265(48)
     and potentially allowed setting ‘__Secure’ prefixed cookies.
     #1965(49)

   - Fix some word matches for user agent platform when the word can be
     a substring.  #1923(50)

   - The development server logs ignored SSL errors.  #1967(51)

   - Temporary files for form data are opened in ‘rb+’ instead of ‘wb+’
     mode for better compatibility with some libraries.  #1961(52)

   - Use SHA-1 instead of MD5 for generating ETags and the debugger pin,
     and in some tests.  MD5 is not available in some environments, such
     as FIPS 140.  This may invalidate some caches since the ETag will
     be different.  #1897(53)

   - Add ‘Cross-Origin-Opener-Policy’ and ‘Cross-Origin-Embedder-Policy’
     response header properties.  #2008(54)

   - ‘run_simple’ tries to show a valid IP address when binding to all
     addresses, instead of ‘0.0.0.0’ or ‘::’.  It also warns about not
     running the development server in production in this case.
     #1964(55)

   - Colors in the development server log are displayed if Colorama is
     installed on Windows.  For all platforms, style support no longer
     requires Click.  #1832(56)

   - A range request for an empty file (or other data with length 0)
     will return a 200 response with the empty file instead of a 416
     error.  #1937(57)

   - New sans-IO base classes for ‘Request’ and ‘Response’ have been
     extracted to contain all the behavior that is not WSGI or IO
     dependent.  These are not a public API, they are part of an ongoing
     refactor to let ASGI frameworks use Werkzeug.  #2005(58)

   - Parsing ‘multipart/form-data’ has been refactored to use sans-io
     patterns.  This should also make parsing forms with large binary
     file uploads significantly faster.  #1788(59)#875(60)

   - ‘LocalProxy’ matches the current Python data model special methods,
     including all r-ops, in-place ops, and async.  ‘__class__’ is
     proxied, so the proxy will look like the object in more cases,
     including ‘isinstance’.  Use ‘issubclass(type(obj), LocalProxy)’ to
     check if an object is actually a proxy.  #1754(61)

   - ‘Local’ uses ‘ContextVar’ on Python 3.7+ instead of
     ‘threading.local’.  #1778(62)

   - ‘request.values’ does not include ‘form’ for GET requests (even
     though GET bodies are undefined).  This prevents bad caching
     proxies from caching form data instead of query strings.  #2037(63)

   - The development server adds the underlying socket to ‘environ’ as
     ‘werkzeug.socket’.  This is non-standard and specific to the dev
     server, other servers may expose this under their own key.  It is
     useful for handling a WebSocket upgrade request.  #2052(64)

   - URL matching assumes ‘websocket=True’ mode for WebSocket upgrade
     requests.  #2052(65)

   - Updated ‘UserAgentParser’ to handle more cases.  #1971(66)

   - ‘werzeug.DechunkedInput.readinto’ will not read beyond the size of
     the buffer.  #2021(67)

   - Fix connection reset when exceeding max content size.  #2051(68)

   - ‘pbkdf2_hex’, ‘pbkdf2_bin’, and ‘safe_str_cmp’ are deprecated.
     ‘hashlib’ and ‘hmac’ provide equivalents.  #2083(69)

   - ‘invalidate_cached_property’ is deprecated.  Use ‘del obj.name’
     instead.  #2084(70)

   - ‘Href’ is deprecated.  Use ‘werkzeug.routing’ instead.  #2085(71)

   - ‘Request.disable_data_descriptor’ is deprecated.  Create the
     request with ‘shallow=True’ instead.  #2085(72)

   - ‘HTTPException.wrap’ is deprecated.  Create a subclass manually
     instead.  #2085(73)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/pull/1693

   (2) https://docs.python.org/3/library/string.html#string.Template

   (3) https://github.com/pallets/werkzeug/issues/1756

   (4) https://docs.python.org/3/library/inspect.html#inspect.signature

   (5) https://github.com/pallets/werkzeug/issues/1757

   (6) https://github.com/pallets/werkzeug/issues/1761

   (7) https://github.com/pallets/werkzeug/issues/1758

   (8) https://github.com/pallets/werkzeug/issues/1834

   (9) https://github.com/pallets/werkzeug/issues/1752

   (10) https://github.com/pallets/werkzeug/issues/2078

   (11) https://github.com/pallets/werkzeug/issues/1759

   (12) https://github.com/pallets/werkzeug/pull/2040

   (13) https://github.com/pallets/werkzeug/issues/1963

   (14) https://github.com/pallets/werkzeug/pull/1766

   (15) https://github.com/pallets/werkzeug/issues/1698

   (16) https://github.com/pallets/werkzeug/issues/1963

   (17) https://github.com/pallets/werkzeug/pull/1721

   (18) https://github.com/pallets/werkzeug/issues/1992

   (19) https://github.com/pallets/werkzeug/issues/1655

   (20) https://github.com/pallets/werkzeug/issues/1658

   (21) https://github.com/pallets/werkzeug/pull/1728

   (22) https://github.com/pallets/werkzeug/pull/1748

   (23) https://github.com/pallets/werkzeug/pull/1755

   (24) https://github.com/pallets/werkzeug/issues/1816

   (25) https://github.com/pallets/werkzeug/issues/1807

   (26) https://github.com/pallets/werkzeug/issues/1781

   (27) https://github.com/pallets/werkzeug/pull/1085

   (28) https://github.com/pallets/werkzeug/issues/265

   (29) https://github.com/pallets/werkzeug/pull/1850

   (30) https://github.com/pallets/werkzeug/issues/1880

   (31) https://github.com/pallets/werkzeug/issues/1869

   (32) https://github.com/pallets/werkzeug/issues/1882

   (33) https://github.com/pallets/werkzeug/issues/1868

   (34) https://github.com/pallets/werkzeug/pull/3896

   (35) https://github.com/pallets/werkzeug/pull/1935

   (36) https://github.com/pallets/werkzeug/pull/1915

   (37) https://github.com/pallets/werkzeug/pull/1889

   (38) https://github.com/pallets/werkzeug/pull/2040

   (39) https://github.com/pallets/werkzeug/pull/1808

   (40) https://github.com/pallets/werkzeug/issues/763

   (41) https://github.com/pallets/werkzeug/issues/1894

   (42) https://github.com/pallets/werkzeug/pull/1809

   (43) https://github.com/pallets/werkzeug/issues/1785

   (44) https://github.com/pallets/werkzeug/pull/1959

   (45) https://github.com/pallets/werkzeug/pull/1945

   (46) https://github.com/pallets/werkzeug/pull/1945

   (47) https://github.com/pallets/werkzeug/issues/1333

   (48) https://tools.ietf.org/html/rfc6265.html

   (49) https://github.com/pallets/werkzeug/pull/1965

   (50) https://github.com/pallets/werkzeug/issues/1923

   (51) https://github.com/pallets/werkzeug/pull/1967

   (52) https://github.com/pallets/werkzeug/issues/1961

   (53) https://github.com/pallets/werkzeug/issues/1897

   (54) https://github.com/pallets/werkzeug/pull/2008

   (55) https://github.com/pallets/werkzeug/issues/1964

   (56) https://github.com/pallets/werkzeug/issues/1832

   (57) https://github.com/pallets/werkzeug/issues/1937

   (58) https://github.com/pallets/werkzeug/pull/2005

   (59) https://github.com/pallets/werkzeug/issues/1788

   (60) https://github.com/pallets/werkzeug/issues/875

   (61) https://github.com/pallets/werkzeug/issues/1754

   (62) https://github.com/pallets/werkzeug/pull/1778

   (63) https://github.com/pallets/werkzeug/pull/2037

   (64) https://github.com/pallets/werkzeug/issues/2052

   (65) https://github.com/pallets/werkzeug/issues/2052

   (66) https://github.com/pallets/werkzeug/issues/1971

   (67) https://github.com/pallets/werkzeug/issues/2021

   (68) https://github.com/pallets/werkzeug/pull/2051

   (69) https://github.com/pallets/werkzeug/pull/2083

   (70) https://github.com/pallets/werkzeug/pull/2084

   (71) https://github.com/pallets/werkzeug/pull/2085

   (72) https://github.com/pallets/werkzeug/pull/2085

   (73) https://github.com/pallets/werkzeug/pull/2085

5.6.4 Version 1.0.1
-------------------

Released 2020-03-31

   - Make the argument to ‘RequestRedirect.get_response’ optional.
     #1718(1)

   - Only allow a single access control allow origin value.  #1723(2)

   - Fix crash when trying to parse a non-existent Content Security
     Policy header.  #1731(3)

   - ‘http_date’ zero fills years < 1000 to always output four digits.
     #1739(4)

   - Fix missing local variables in interactive debugger console.
     #1746(5)

   - Fix passing file-like objects like ‘io.BytesIO’ to
     ‘FileStorage.save’.  #1733(6)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1718

   (2) https://github.com/pallets/werkzeug/pull/1723

   (3) https://github.com/pallets/werkzeug/pull/1731

   (4) https://github.com/pallets/werkzeug/issues/1739

   (5) https://github.com/pallets/werkzeug/issues/1746

   (6) https://github.com/pallets/werkzeug/issues/1733

5.6.5 Version 1.0.0
-------------------

Released 2020-02-06

   - Drop support for Python 3.4.  (#1478(1))

   - Remove code that issued deprecation warnings in version 0.15.
     (#1477(2))

   - Remove most top-level attributes provided by the ‘werkzeug’ module
     in favor of direct imports.  For example, instead of ‘import
     werkzeug; werkzeug.url_quote’, do ‘from werkzeug.urls import
     url_quote’.  Install version 0.16 first to see deprecation warnings
     while upgrading.  #2(3), #1640(4)

   - Added ‘utils.invalidate_cached_property()’ to invalidate cached
     properties.  (#1474(5))

   - Directive keys for the ‘Set-Cookie’ response header are not ignored
     when parsing the ‘Cookie’ request header.  This allows cookies with
     names such as “expires” and “version”.  (#1495(6))

   - Request cookies are parsed into a ‘MultiDict’ to capture all values
     for cookies with the same key.  ‘cookies[key]’ returns the first
     value rather than the last.  Use ‘cookies.getlist(key)’ to get all
     values.  ‘parse_cookie’ also defaults to a ‘MultiDict’.  #1562(7),
     #1458(8)

   - Add ‘charset=utf-8’ to an HTTP exception response’s ‘CONTENT_TYPE’
     header.  (#1526(9))

   - The interactive debugger handles outer variables in nested scopes
     such as lambdas and comprehensions.  #913(10), #1037(11), #1532(12)

   - The user agent for Opera 60 on Mac is correctly reported as “opera”
     instead of “chrome”.  #1556(13)

   - The platform for Crosswalk on Android is correctly reported as
     “android” instead of “chromeos”.  (#1572(14))

   - Issue a warning when the current server name does not match the
     configured server name.  #760(15)

   - A configured server name with the default port for a scheme will
     match the current server name without the port if the current
     scheme matches.  #1584(16)

   - InternalServerError has a ‘original_exception’
     attribute that frameworks can use to track the original cause of
     the error.  #1590(17)

   - Headers are tested for equality independent of the header key case,
     such that ‘X-Foo’ is the same as ‘x-foo’.  #1605(18)

   - http.dump_cookie() accepts ‘'None'’ as a value for
     ‘samesite’.  #1549(19)

   - set_cookie() accepts a ‘samesite’ argument.  #1705(20)

   - Support the Content Security Policy header through the
     ‘Response.content_security_policy’ data structure.  #1617(21)

   - ‘LanguageAccept’ will fall back to matching “en” for “en-US” or
     “en-US” for “en” to better support clients or translations that
     only match at the primary language tag.  #450(22), #1507(23)

   - ‘MIMEAccept’ uses MIME parameters for specificity when matching.
     #458(24), #1574(25)

   - If the development server is started with an ‘SSLContext’
     configured to verify client certificates, the certificate in PEM
     format will be available as ‘environ["SSL_CLIENT_CERT"]’.
     #1469(26)

   - ‘is_resource_modified’ will run for methods other than ‘GET’ and
     ‘HEAD’, rather than always returning ‘False’.  #409(27)

   - ‘SharedDataMiddleware’ returns 404 rather than 500 when trying to
     access a directory instead of a file with the package loader.  The
     dependency on setuptools and pkg_resources is removed.  #1599(28)

   - Add a ‘response.cache_control.immutable’ flag.  Keep in mind that
     browser support for this ‘Cache-Control’ header option is still
     experimental and may not be implemented.  #1185(29)

   - Optional request log highlighting with the development server is
     handled by Click instead of termcolor.  #1235(30)

   - Optional ad-hoc TLS support for the development server is handled
     by cryptography instead of pyOpenSSL. #1555(31)

   - ‘FileStorage.save()’ supports ‘pathlib’ and PEP 519(32) ‘PathLike’
     objects.  #1653(33)

   - The debugger security pin is unique in containers managed by
     Podman.  #1661(34)

   - Building a URL when ‘host_matching’ is enabled takes into account
     the current host when there are duplicate endpoints with different
     hosts.  #488(35)

   - The ‘429 TooManyRequests’ and ‘503 ServiceUnavailable’ HTTP
     exceptions takes a ‘retry_after’ parameter to set the ‘Retry-After’
     header.  #1657(36)

   - ‘Map’ and ‘Rule’ have a ‘merge_slashes’ option to collapse multiple
     slashes into one, similar to how many HTTP servers behave.  This is
     enabled by default.  #1286(37)#1694(38)

   - Add HTTP 103, 208, 306, 425, 506, 508, and 511 to the list of
     status codes.  #1678(39)

   - Add ‘update’, ‘setlist’, and ‘setlistdefault’ methods to the
     ‘Headers’ data structure.  ‘extend’ method can take ‘MultiDict’ and
     kwargs.  #1687(40)#1697(41)

   - The development server accepts paths that start with two slashes,
     rather than stripping off the first path segment.  #491(42)

   - Add access control (Cross Origin Request Sharing, CORS) header
     properties to the ‘Request’ and ‘Response’ wrappers.  #1699(43)

   - ‘Accept’ values are no longer ordered alphabetically for equal
     quality tags.  Instead the initial order is preserved.  #1686(44)

   - Added ‘Map.lock_class’ attribute for alternative implementations.
     #1702(45)

   - Support matching and building WebSocket rules in the routing
     system, for use by async frameworks.  #1709(46)

   - Range requests that span an entire file respond with 206 instead of
     200, to be more compliant with RFC 7233(47).  This may help serving
     media to older browsers.  #410(48)#1704(49)

   - The SharedDataMiddleware default ‘fallback_mimetype’ is
     ‘application/octet-stream’.  If a filename looks like a text
     mimetype, the ‘utf-8’ charset is added to it.  This matches the
     behavior of ‘BaseResponse’ and Flask’s ‘send_file()’.  #1689(50)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1478

   (2) https://github.com/pallets/werkzeug/issues/1477

   (3) https://github.com/pallets/werkzeug/issues/2

   (4) https://github.com/pallets/werkzeug/pull/1640

   (5) https://github.com/pallets/werkzeug/pull/1474

   (6) https://github.com/pallets/werkzeug/issues/1495

   (7) https://github.com/pallets/werkzeug/issues/1562

   (8) https://github.com/pallets/werkzeug/pull/1458

   (9) https://github.com/pallets/werkzeug/pull/1526

   (10) https://github.com/pallets/werkzeug/issues/913

   (11) https://github.com/pallets/werkzeug/issues/1037

   (12) https://github.com/pallets/werkzeug/pull/1532

   (13) https://github.com/pallets/werkzeug/issues/1556

   (14) https://github.com/pallets/werkzeug/pull/1572

   (15) https://github.com/pallets/werkzeug/issues/760

   (16) https://github.com/pallets/werkzeug/pull/1584

   (17) https://github.com/pallets/werkzeug/pull/1590

   (18) https://github.com/pallets/werkzeug/pull/1605

   (19) https://github.com/pallets/werkzeug/issues/1549

   (20) https://github.com/pallets/werkzeug/pull/1705

   (21) https://github.com/pallets/werkzeug/pull/1617

   (22) https://github.com/pallets/werkzeug/issues/450

   (23) https://github.com/pallets/werkzeug/pull/1507

   (24) https://github.com/pallets/werkzeug/issues/458

   (25) https://github.com/pallets/werkzeug/pull/1574

   (26) https://github.com/pallets/werkzeug/pull/1469

   (27) https://github.com/pallets/werkzeug/issues/409

   (28) https://github.com/pallets/werkzeug/issues/1599

   (29) https://github.com/pallets/werkzeug/issues/1185

   (30) https://github.com/pallets/werkzeug/issues/1235

   (31) https://github.com/pallets/werkzeug/pull/1555

   (32) https://www.python.org/dev/peps/pep-0519

   (33) https://github.com/pallets/werkzeug/issues/1653

   (34) https://github.com/pallets/werkzeug/issues/1661

   (35) https://github.com/pallets/werkzeug/issues/488

   (36) https://github.com/pallets/werkzeug/issues/1657

   (37) https://github.com/pallets/werkzeug/pull/1286

   (38) https://github.com/pallets/werkzeug/pull/1694

   (39) https://github.com/pallets/werkzeug/pull/1678

   (40) https://github.com/pallets/werkzeug/pull/1687

   (41) https://github.com/pallets/werkzeug/pull/1697

   (42) https://github.com/pallets/werkzeug/issues/491

   (43) https://github.com/pallets/werkzeug/pull/1699

   (44) https://github.com/pallets/werkzeug/issues/1686

   (45) https://github.com/pallets/werkzeug/pull/1702

   (46) https://github.com/pallets/werkzeug/pull/1709

   (47) https://tools.ietf.org/html/rfc7233.html

   (48) https://github.com/pallets/werkzeug/issues/410

   (49) https://github.com/pallets/werkzeug/issues/1704

   (50) https://github.com/pallets/werkzeug/issues/1689

5.6.6 Version 0.16.1
--------------------

Released 2020-01-27

   - Fix import location in deprecation messages for subpackages.
     #1663(1)

   - Fix an SSL error on Python 3.5 when the dev server responds with no
     content.  #1659(2)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1663

   (2) https://github.com/pallets/werkzeug/issues/1659

5.6.7 Version 0.16.0
--------------------

Released 2019-09-19

   - Deprecate most top-level attributes provided by the ‘werkzeug’
     module in favor of direct imports.  The deprecated imports will be
     removed in version 1.0.

     For example, instead of ‘import werkzeug; werkzeug.url_quote’, do
     ‘from werkzeug.urls import url_quote’.  A deprecation warning will
     show the correct import to use.  ‘werkzeug.exceptions’ and
     ‘werkzeug.routing’ should also be imported instead of accessed, but
     for technical reasons can’t show a warning.

     #2(1), #1640(2)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/2

   (2) https://github.com/pallets/werkzeug/pull/1640

5.6.8 Version 0.15.6
--------------------

Released 2019-09-04

   - Work around a bug in pip that caused the reloader to fail on
     Windows when the script was an entry point.  This fixes the issue
     with Flask’s ‘flask run’ command failing with “No module named
     Scriptsflask”.  #1614(1)

   - ‘ProxyFix’ trusts the ‘X-Forwarded-Proto’ header by default.
     #1630(2)

   - The deprecated ‘num_proxies’ argument to ‘ProxyFix’ sets ‘x_for’,
     ‘x_proto’, and ‘x_host’ to match 0.14 behavior.  This is intended
     to make intermediate upgrades less disruptive, but the argument
     will still be removed in 1.0.  #1630(3)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1614

   (2) https://github.com/pallets/werkzeug/issues/1630

   (3) https://github.com/pallets/werkzeug/issues/1630

5.6.9 Version 0.15.5
--------------------

Released 2019-07-17

   - Fix a ‘TypeError’ due to changes to ‘ast.Module’ in Python 3.8.
     #1551(1)

   - Fix a C assertion failure in debug builds of some Python 2.7
     releases.  #1553(2)

   - BadRequestKeyError adds the ‘KeyError’ message to the
     description if ‘e.show_exception’ is set to ‘True’.  This is a more
     secure default than the original 0.15.0 behavior and makes it
     easier to control without losing information.  #1592(3)

   - Upgrade the debugger to jQuery 3.4.1.  #1581(4)

   - Work around an issue in some external debuggers that caused the
     reloader to fail.  #1607(5)

   - Work around an issue where the reloader couldn’t introspect a
     setuptools script installed as an egg.  #1600(6)

   - The reloader will use ‘sys.executable’ even if the script is marked
     executable, reverting a behavior intended for NixOS introduced in
     0.15.  The reloader should no longer cause ‘OSError: [Errno 8] Exec
     format error’.  #1482(7), #1580(8)

   - ‘SharedDataMiddleware’ safely handles paths with Windows drive
     names.  #1589(9)

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1551

   (2) https://github.com/pallets/werkzeug/issues/1553

   (3) https://github.com/pallets/werkzeug/pull/1592

   (4) https://github.com/pallets/werkzeug/issues/1581

   (5) https://github.com/pallets/werkzeug/issues/1607

   (6) https://github.com/pallets/werkzeug/issues/1600

   (7) https://github.com/pallets/werkzeug/issues/1482

   (8) https://github.com/pallets/werkzeug/issues/1580

   (9) https://github.com/pallets/werkzeug/issues/1589

5.6.10 Version 0.15.4
---------------------

Released 2019-05-14

   - Fix a ‘SyntaxError’ on Python 2.7.5.  (#1544(1))

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1544

5.6.11 Version 0.15.3
---------------------

Released 2019-05-14

   - Properly handle multi-line header folding in development server in
     Python 2.7.  (#1080(1))

   - Restore the ‘response’ argument to Unauthorized.
     (#1527(2))

   - Unauthorized doesn’t add the ‘WWW-Authenticate’ header
     if ‘www_authenticate’ is not given.  (#1516(3))

   - The default URL converter correctly encodes bytes to string rather
     than representing them with ‘b''’.  (#1502(4))

   - Fix the filename format string in ProfilerMiddleware to
     correctly handle float values.  (#1511(5))

   - Update LintMiddleware to work on Python 3.  (#1510(6))

   - The debugger detects cycles in chained exceptions and does not time
     out in that case.  (#1536(7))

   - When running the development server in Docker, the debugger
     security pin is now unique per container.

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1080

   (2) https://github.com/pallets/werkzeug/pull/1527

   (3) https://github.com/pallets/werkzeug/issues/1516

   (4) https://github.com/pallets/werkzeug/issues/1502

   (5) https://github.com/pallets/werkzeug/issues/1511

   (6) https://github.com/pallets/werkzeug/issues/1510

   (7) https://github.com/pallets/werkzeug/issues/1536

5.6.12 Version 0.15.2
---------------------

Released 2019-04-02

   - ‘Rule’ code generation uses a filename that coverage will ignore.
     The previous value, “generated”, was causing coverage to fail.
     (#1487(1))

   - The test client removes the cookie header if there are no persisted
     cookies.  This fixes an issue introduced in 0.15.0 where the
     cookies from the original request were used for redirects, causing
     functions such as logout to fail.  (#1491(2))

   - The test client copies the environ before passing it to the app, to
     prevent in-place modifications from affecting redirect requests.
     (#1498(3))

   - The ‘"werkzeug"’ logger only adds a handler if there is no handler
     configured for its level in the logging chain.  This avoids double
     logging if other code configures logging first.  (#1492(4))

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1487

   (2) https://github.com/pallets/werkzeug/issues/1491

   (3) https://github.com/pallets/werkzeug/issues/1498

   (4) https://github.com/pallets/werkzeug/issues/1492

5.6.13 Version 0.15.1
---------------------

Released 2019-03-21

   - Unauthorized takes ‘description’ as the first argument,
     restoring previous behavior.  The new ‘www_authenticate’ argument
     is listed second.  (#1483(1))

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/issues/1483

5.6.14 Version 0.15.0
---------------------

Released 2019-03-19

   - Building URLs is ~7x faster.  Each Rule compiles an
     optimized function for building itself.  (#1281(1))

   - MapAdapter.build() can be passed a MultiDict.
     to represent multiple values for a key.  It already did this when
     passing a dict with a list value.  (#724(2))

   - ‘path_info’ defaults to ‘'/'’ for Map.bind().  (#740(3),
     #768(4), #1316(5))

   - Change ‘RequestRedirect’ code from 301 to 308, preserving the verb
     and request body (form data) during redirect.  (#1342(6))

   - ‘int’ and ‘float’ converters in URL rules will handle negative
     values if passed the ‘signed=True’ parameter.  For example,
     ‘/jump/<int(signed=True):count>’.  (#1355(7))

   - ‘Location’ autocorrection in ‘Response.get_wsgi_headers()’ is
     relative to the current path rather than the root path.  (#693(8),
     #718(9), #1315(10))

   - 412 responses once again include entity headers and an error
     message in the body.  They were originally omitted when
     implementing ‘If-Match’ (#1233(11)), but the spec doesn’t seem to
     disallow it.  (#1231(12), #1255(13))

   - The Content-Length header is removed for 1xx and 204 responses.
     This fixes a previous change where no body would be sent, but the
     header would still be present.  The new behavior matches RFC 7230.
     (#1294(14))

   - Unauthorized takes a ‘www_authenticate’ parameter to
     set the ‘WWW-Authenticate’ header for the response, which is
     technically required for a valid 401 response.  (#772(15),
     #795(16))

   - Add support for status code 424 FailedDependency.
     (#1358(17))

   - http.parse_cookie() ignores empty segments rather than
     producing a cookie with no key or value.  (#1245(18), #1301(19))

   - parse_authorization_header(). (and Authorization,
     see authorization) treats the authorization header as
     UTF-8.  On Python 2, basic auth username and password are
     ‘unicode’.  (#1325(20))

   - parse_options_header() understands RFC 2231(21)
     parameter continuations.  (#1417(22))

   - uri_to_iri() does not unquote ASCII characters in the
     unreserved class, such as space, and leaves invalid bytes quoted
     when decoding.  iri_to_uri() does not quote reserved
     characters.  See RFC 3987(23) for these character classes.
     (#1433(24))

   - ‘get_content_type’ appends a charset for any mimetype that ends
     with ‘+xml’, not just those that start with ‘application/’.  Known
     text types such as ‘application/javascript’ are also given
     charsets.  (#1439(25))

   - Clean up ‘werkzeug.security’ module, remove outdated hashlib
     support.  (#1282(26))

   - In generate_password_hash(), PBKDF2 uses 150000
     iterations by default, increased from 50000.  (#1377(27))

   - ClosingIterator calls ‘close’ on the wrapped
     `iterable', not the internal iterator.  This doesn’t affect objects
     where ‘__iter__’ returned ‘self’.  For other objects, the method
     was not called before.  (#1259(28), #1260(29))

   - Bytes may be used as keys in Headers, they will be
     decoded as Latin-1 like values are.  (#1346(30))

   - Range validates that list of range tuples passed to it
     would produce a valid ‘Range’ header.  (#1412(31))

   - FileStorage looks up attributes on ‘stream._file’ if
     they don’t exist on ‘stream’, working around an issue where
     tempfile.SpooledTemporaryFile()(32) didn’t implement all of
     io.IOBase(33).  See ‘https://github.com/python/cpython/pull/3249’.
     (#1409(34))

   - CombinedMultiDict.copy() returns a shallow mutable copy
     as a MultiDict.  The copy no longer reflects changes to
     the combined dicts, but is more generally useful.  (#1420(35))

   - The version of jQuery used by the debugger is updated to 3.3.1.
     (#1390(36))

   - The debugger correctly renders long ‘markupsafe.Markup’ instances.
     (#1393(37))

   - The debugger can serve resources when Werkzeug is installed as a
     zip file.  ‘DebuggedApplication.get_resource’ uses
     ‘pkgutil.get_data’.  (#1401(38))

   - The debugger and server log support Python 3’s chained exceptions.
     (#1396(39))

   - The interactive debugger highlights frames that come from user code
     to make them easy to pick out in a long stack trace.  Note that if
     an env was created with virtualenv instead of venv, the debugger
     may incorrectly classify some frames.  (#1421(40))

   - Clicking the error message at the top of the interactive debugger
     will jump down to the bottom of the traceback.  (#1422(41))

   - When generating a PIN, the debugger will ignore a ‘KeyError’ raised
     when the current UID doesn’t have an associated username, which can
     happen in Docker.  (#1471(42))

   - BadRequestKeyError adds the ‘KeyError’ message to the
     description, making it clearer what caused the 400 error.
     Frameworks like Flask can omit this information in production by
     setting ‘e.args = ()’.  (#1395(43))

   - If a nested ‘ImportError’ occurs from import_string().
     the traceback mentions the nested import.  Removes an untested code
     path for handling “modules not yet set up by the parent.”
     (#735(44))

   - Triggering a reload while using a tool such as PDB no longer hides
     input.  (#1318(45))

   - The reloader will not prepend the Python executable to the command
     line if the Python file is marked executable.  This allows the
     reloader to work on NixOS. (#1242(46))

   - Fix an issue where ‘sys.path’ would change between reloads when
     running with ‘python -m app’.  The reloader can detect that a
     module was run with “-m” and reconstructs that instead of the file
     path in ‘sys.argv’ when reloading.  (#1416(47))

   - The dev server can bind to a Unix socket by passing a hostname like
     ‘unix://app.socket’.  (#209(48), #1019(49))

   - Server uses ‘IPPROTO_TCP’ constant instead of ‘SOL_TCP’ for Jython
     compatibility.  (#1375(50))

   - When using an adhoc SSL cert with run_simple(), the cert
     is shown as self-signed rather than signed by an invalid authority.
     (#1430(51))

   - The development server logs the unquoted IRI rather than the raw
     request line, to make it easier to work with Unicode in request
     paths during development.  (#1115(52))

   - The development server recognizes ‘ConnectionError’ on Python 3 to
     silence client disconnects, and does not silence other ‘OSErrors’
     that may have been raised inside the application.  (#1418(53))

   - The environ keys ‘REQUEST_URI’ and ‘RAW_URI’ contain the raw path
     before it was percent-decoded.  This is non-standard, but many WSGI
     servers add them.  Middleware could replace ‘PATH_INFO’ with this
     to route based on the raw value.  (#1419(54))

   - EnvironBuilder doesn’t set ‘CONTENT_TYPE’ or
     ‘CONTENT_LENGTH’ in the environ if they aren’t set.  Previously
     these used default values if they weren’t set.  Now it’s possible
     to distinguish between empty and unset values.  (#1308(55))

   - The test client raises a ‘ValueError’ if a query string argument
     would overwrite a query string in the path.  (#1338(56))

   - test.EnvironBuilder and test.Client take a
     ‘json’ argument instead of manually passing ‘data’ and
     ‘content_type’.  This is serialized using the
     test.EnvironBuilder.json_dumps() method.  (#1404(57))

   - test.Client redirect handling is rewritten.  (#1402(58))

        - The redirect environ is copied from the initial request
          environ.

        - Script root and path are correctly distinguished when
          redirecting to a path under the root.

        - The HEAD method is not changed to GET.

        - 307 and 308 codes preserve the method and body.  All others
          ignore the body and related headers.

        - Headers are passed to the new request for all codes, following
          what browsers do.

        - test.EnvironBuilder sets the content type and
          length headers in addition to the WSGI keys when detecting
          them from the data.

        - Intermediate response bodies are iterated over even when
          ‘buffered=False’ to ensure iterator middleware can run cleanup
          code safely.  Only the last response is not buffered.
          (#988(59))

   - EnvironBuilder, FileStorage, and
     wsgi.get_input_stream() no longer share a global
     ‘_empty_stream’ instance.  This improves test isolation by
     preventing cases where closing the stream in one request would
     affect other usages.  (#1340(60))

   - The default ‘SecureCookie.serialization_method’ will change from
     pickle(61) to json(62) in 1.0.  To upgrade existing tokens,
     override ‘unquote()’ to try ‘pickle’ if ‘json’ fails.  (#1413(63))

   - ‘CGIRootFix’ no longer modifies ‘PATH_INFO’ for very old versions
     of Lighttpd.  ‘LighttpdCGIRootFix’ was renamed to ‘CGIRootFix’ in
     0.9.  Both are deprecated and will be removed in version 1.0.
     (#1141(64))

   - ‘werkzeug.wrappers.json.JSONMixin’ has been replaced with Flask’s
     implementation.  Check the docs for the full API. (#1445(65))

   - The contrib modules are deprecated and will either be moved into
     ‘werkzeug’ core or removed completely in version 1.0.  Some modules
     that already issued deprecation warnings have been removed.  Be
     sure to run or test your code with ‘python -W
     default::DeprecationWarning’ to catch any deprecated code you’re
     using.  (#4(66))

        - ‘LintMiddleware’ has moved to werkzeug.middleware.lint.

        - ‘ProfilerMiddleware’ has moved to
          werkzeug.middleware.profiler.

        - ‘ProxyFix’ has moved to werkzeug.middleware.proxy_fix.

        - ‘JSONRequestMixin’ has moved to ‘werkzeug.wrappers.json’.

        - ‘cache’ has been extracted into a separate project,
          cachelib(67).  The version in Werkzeug is deprecated.

        - ‘securecookie’ and ‘sessions’ have been extracted into a
          separate project, secure-cookie(68).  The version in Werkzeug
          is deprecated.

        - Everything in ‘fixers’, except ‘ProxyFix’, is deprecated.

        - Everything in ‘wrappers’, except ‘JSONMixin’, is deprecated.

        - ‘atom’ is deprecated.  This did not fit in with the rest of
          Werkzeug, and is better served by a dedicated library in the
          community.

        - ‘jsrouting’ is removed.  Set URLs when rendering templates or
          JSON responses instead.

        - ‘limiter’ is removed.  Its specific use is handled by Werkzeug
          directly, but stream limiting is better handled by the WSGI
          server in general.

        - ‘testtools’ is removed.  It did not offer significant benefit
          over the default test client.

        - ‘iterio’ is deprecated.

   - wsgi.get_host() no longer looks at ‘X-Forwarded-For’.
     Use ProxyFix to handle that.  (#609(69), #1303(70))

   - ProxyFix is refactored to support more headers,
     multiple values, and more secure configuration.

        - Each header supports multiple values.  The trusted number of
          proxies is configured separately for each header.  The
          ‘num_proxies’ argument is deprecated.  (#1314(71))

        - Sets ‘SERVER_NAME’ and ‘SERVER_PORT’ based on
          ‘X-Forwarded-Host’.  (#1314(72))

        - Sets ‘SERVER_PORT’ and modifies ‘HTTP_HOST’ based on
          ‘X-Forwarded-Port’.  (#1023(73), #1304(74))

        - Sets ‘SCRIPT_NAME’ based on ‘X-Forwarded-Prefix’.  (#1237(75))

        - The original WSGI environment values are stored in the
          ‘werkzeug.proxy_fix.orig’ key, a dict.  The individual keys
          ‘werkzeug.proxy_fix.orig_remote_addr’,
          ‘werkzeug.proxy_fix.orig_wsgi_url_scheme’, and
          ‘werkzeug.proxy_fix.orig_http_host’ are deprecated.

   - Middleware from ‘werkzeug.wsgi’ has moved to separate modules under
     ‘werkzeug.middleware’, along with the middleware moved from
     ‘werkzeug.contrib’.  The old ‘werkzeug.wsgi’ imports are deprecated
     and will be removed in version 1.0.  (#1452(76))

        - ‘werkzeug.wsgi.DispatcherMiddleware’ has moved to
          werkzeug.middleware.dispatcher.DispatcherMiddleware.

        - ‘werkzeug.wsgi.ProxyMiddleware’ as moved to
          werkzeug.middleware.http_proxy.ProxyMiddleware.

        - ‘werkzeug.wsgi.SharedDataMiddleware’ has moved to
          werkzeug.middleware.shared_data.SharedDataMiddleware.

   - ProxyMiddleware proxies the query string.  (#1252(77))

   - The filenames generated by ProfilerMiddleware can be
     customized.  (#1283(78))

   - The ‘werkzeug.wrappers’ module has been converted to a package, and
     its various classes have been organized into separate modules.  Any
     previously documented classes, understood to be the existing public
     API, are still importable from ‘werkzeug.wrappers’, or may be
     imported from their specific modules.  (#1456(79))

   ---------- Footnotes ----------

   (1) https://github.com/pallets/werkzeug/pull/1281

   (2) https://github.com/pallets/werkzeug/pull/724

   (3) https://github.com/pallets/werkzeug/issues/740

   (4) https://github.com/pallets/werkzeug/pull/768

   (5) https://github.com/pallets/werkzeug/pull/1316

   (6) https://github.com/pallets/werkzeug/pull/1342

   (7) https://github.com/pallets/werkzeug/pull/1355

   (8) https://github.com/pallets/werkzeug/issues/693

   (9) https://github.com/pallets/werkzeug/pull/718

   (10) https://github.com/pallets/werkzeug/pull/1315

   (11) https://github.com/pallets/werkzeug/pull/1233

   (12) https://github.com/pallets/werkzeug/issues/1231

   (13) https://github.com/pallets/werkzeug/pull/1255

   (14) https://github.com/pallets/werkzeug/pull/1294

   (15) https://github.com/pallets/werkzeug/issues/772

   (16) https://github.com/pallets/werkzeug/pull/795

   (17) https://github.com/pallets/werkzeug/pull/1358

   (18) https://github.com/pallets/werkzeug/issues/1245

   (19) https://github.com/pallets/werkzeug/pull/1301

   (20) https://github.com/pallets/werkzeug/pull/1325

   (21) https://tools.ietf.org/html/rfc2231.html

   (22) https://github.com/pallets/werkzeug/pull/1417

   (23) https://tools.ietf.org/html/rfc3987.html

   (24) https://github.com/pallets/werkzeug/pull/1433

   (25) https://github.com/pallets/werkzeug/pull/1439

   (26) https://github.com/pallets/werkzeug/pull/1282

   (27) https://github.com/pallets/werkzeug/pull/1377

   (28) https://github.com/pallets/werkzeug/issues/1259

   (29) https://github.com/pallets/werkzeug/pull/1260

   (30) https://github.com/pallets/werkzeug/pull/1346

   (31) https://github.com/pallets/werkzeug/pull/1412

   (32)
https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile

   (33) https://docs.python.org/3/library/io.html#io.IOBase

   (34) https://github.com/pallets/werkzeug/pull/1409

   (35) https://github.com/pallets/werkzeug/pull/1420

   (36) https://github.com/pallets/werkzeug/pull/1390

   (37) https://github.com/pallets/werkzeug/pull/1393

   (38) https://github.com/pallets/werkzeug/pull/1401

   (39) https://github.com/pallets/werkzeug/pull/1396

   (40) https://github.com/pallets/werkzeug/pull/1421

   (41) https://github.com/pallets/werkzeug/pull/1422

   (42) https://github.com/pallets/werkzeug/issues/1471

   (43) https://github.com/pallets/werkzeug/pull/1395

   (44) https://github.com/pallets/werkzeug/pull/735

   (45) https://github.com/pallets/werkzeug/pull/1318

   (46) https://github.com/pallets/werkzeug/pull/1242

   (47) https://github.com/pallets/werkzeug/pull/1416

   (48) https://github.com/pallets/werkzeug/pull/209

   (49) https://github.com/pallets/werkzeug/pull/1019

   (50) https://github.com/pallets/werkzeug/pull/1375

   (51) https://github.com/pallets/werkzeug/pull/1430

   (52) https://github.com/pallets/werkzeug/issues/1115

   (53) https://github.com/pallets/werkzeug/pull/1418

   (54) https://github.com/pallets/werkzeug/pull/1419

   (55) https://github.com/pallets/werkzeug/pull/1308

   (56) https://github.com/pallets/werkzeug/pull/1338

   (57) https://github.com/pallets/werkzeug/pull/1404

   (58) https://github.com/pallets/werkzeug/pull/1402

   (59) https://github.com/pallets/werkzeug/pull/988

   (60) https://github.com/pallets/werkzeug/pull/1340

   (61) https://docs.python.org/3/library/pickle.html#module-pickle

   (62) https://docs.python.org/3/library/json.html#module-json

   (63) https://github.com/pallets/werkzeug/pull/1413

   (64) https://github.com/pallets/werkzeug/pull/1141

   (65) https://github.com/pallets/werkzeug/pull/1445

   (66) https://github.com/pallets/werkzeug/issues/4

   (67) https://github.com/pallets/cachelib

   (68) https://github.com/pallets/secure-cookie

   (69) https://github.com/pallets/werkzeug/issues/609

   (70) https://github.com/pallets/werkzeug/pull/1303

   (71) https://github.com/pallets/werkzeug/pull/1314

   (72) https://github.com/pallets/werkzeug/pull/1314

   (73) https://github.com/pallets/werkzeug/issues/1023

   (74) https://github.com/pallets/werkzeug/pull/1304

   (75) https://github.com/pallets/werkzeug/issues/1237

   (76) https://github.com/pallets/werkzeug/pull/1452

   (77) https://github.com/pallets/werkzeug/pull/1252

   (78) https://github.com/pallets/werkzeug/issues/1283

   (79) https://github.com/pallets/werkzeug/pull/1456

5.6.15 Version 0.14.1
---------------------

Released on December 31st 2017

   - Resolved a regression with status code handling in the integrated
     development server.

5.6.16 Version 0.14
-------------------

Released on December 31st 2017

   - HTTP exceptions are now automatically caught by
     ‘Request.application’.

   - Added support for edge as browser.

   - Added support for platforms that lack ‘SpooledTemporaryFile’.

   - Add support for etag handling through if-match

   - Added support for the SameSite cookie attribute.

   - Added ‘werkzeug.wsgi.ProxyMiddleware’

   - Implemented ‘has’ for ‘NullCache’

   - ‘get_multi’ on cache clients now returns lists all the time.

   - Improved the watchdog observer shutdown for the reloader to not
     crash on exit on older Python versions.

   - Added support for ‘filename*’ filename attributes according to RFC
     2231

   - Resolved an issue where machine ID for the reloader PIN was not
     read accurately on windows.

   - Added a workaround for syntax errors in init files in the reloader.

   - Added support for using the reloader with console scripts on
     windows.

   - The built-in HTTP server will no longer close a connection in cases
     where no HTTP body is expected (204, 204, HEAD requests etc.)

   - The ‘EnvironHeaders’ object now skips over empty content type and
     lengths if they are set to falsy values.

   - Werkzeug will no longer send the content-length header on 1xx or
     204/304 responses.

   - Cookie values are now also permitted to include slashes and equal
     signs without quoting.

   - Relaxed the regex for the routing converter arguments.

   - If cookies are sent without values they are now assumed to have an
     empty value and the parser accepts this.  Previously this could
     have corrupted cookies that followed the value.

   - The test ‘Client’ and ‘EnvironBuilder’ now support mimetypes like
     the request object does.

   - Added support for static weights in URL rules.

   - Better handle some more complex reloader scenarios where sys.path
     contained non directory paths.

   - ‘EnvironHeaders’ no longer raises weird errors if non string keys
     are passed to it.

5.6.17 Version 0.13
-------------------

Released on December 7th 2017

   - `Deprecate support for Python 2.6 and 3.3.'  CI tests will not run
     for these versions, and support will be dropped completely in the
     next version.  (pallets/meta#24(1))

   - Raise ‘TypeError’ when port is not an integer.  (#1088(2))

   - Fully deprecate ‘werkzeug.script’.  Use Click(3) instead.
     (#1090(4))

   - ‘response.age’ is parsed as a ‘timedelta’.  Previously, it was
     incorrectly treated as a ‘datetime’.  The header value is an
     integer number of seconds, not a date string.  (#414(5))

   - Fix a bug in ‘TypeConversionDict’ where errors are not propagated
     when using the converter.  (#1102(6))

   - ‘Authorization.qop’ is a string instead of a set, to comply with
     RFC 2617.  (#984(7))

   - An exception is raised when an encoded cookie is larger than, by
     default, 4093 bytes.  Browsers may silently ignore cookies larger
     than this.  ‘BaseResponse’ has a new attribute ‘max_cookie_size’
     and ‘dump_cookie’ has a new argument ‘max_size’ to configure this.
     (#780(8), #1109(9))

   - Fix a TypeError in ‘werkzeug.contrib.lint.GuardedIterator.close’.
     (#1116(10))

   - ‘BaseResponse.calculate_content_length’ now correctly works for
     Unicode responses on Python 3.  It first encodes using
     ‘iter_encoded’.  (#705(11))

   - Secure cookie contrib works with string secret key on Python 3.
     (#1205(12))

   - Shared data middleware accepts a list instead of a dict of static
     locations to preserve lookup order.  (#1197(13))

   - HTTP header values without encoding can contain single quotes.
     (#1208(14))

   - The built-in dev server supports receiving requests with chunked
     transfer encoding.  (#1198(15))

   ---------- Footnotes ----------

   (1) https://github.com/pallets/meta/issues/24

   (2) https://github.com/pallets/werkzeug/pull/1088

   (3) https://palletsprojects.com/p/click/

   (4) https://github.com/pallets/werkzeug/pull/1090

   (5) https://github.com/pallets/werkzeug/pull/414

   (6) https://github.com/pallets/werkzeug/issues/1102

   (7) https://github.com/pallets/werkzeug/pull/984

   (8) https://github.com/pallets/werkzeug/pull/780

   (9) https://github.com/pallets/werkzeug/pull/1109

   (10) https://github.com/pallets/werkzeug/pull/1116

   (11) https://github.com/pallets/werkzeug/issues/705

   (12) https://github.com/pallets/werkzeug/pull/1205

   (13) https://github.com/pallets/werkzeug/pull/1197

   (14) https://github.com/pallets/werkzeug/pull/1208

   (15) https://github.com/pallets/werkzeug/pull/1198

5.6.18 Version 0.12.2
---------------------

Released on May 16 2017

   - Fix regression: Pull request ‘#892’ prevented Werkzeug from
     correctly logging the IP of a remote client behind a reverse proxy,
     even when using ‘ProxyFix’.

   - Fix a bug in ‘safe_join’ on Windows.

5.6.19 Version 0.12.1
---------------------

Released on March 15th 2017

   - Fix crash of reloader (used on debug mode) on Windows.  (‘OSError:
     [WinError 10038]’).  See pull request ‘#1081’

   - Partially revert change to class hierarchy of ‘Headers’.  See
     ‘#1084’.

5.6.20 Version 0.12
-------------------

Released on March 10th 2017

   - Spit out big deprecation warnings for werkzeug.script

   - Use ‘inspect.getfullargspec’ internally when available as
     ‘inspect.getargspec’ is gone in 3.6

   - Added support for status code 451 and 423

   - Improved the build error suggestions.  In particular only if
     someone stringifies the error will the suggestions be calculated.

   - Added support for uWSGI’s caching backend.

   - Fix a bug where iterating over a ‘FileStorage’ would result in an
     infinite loop.

   - Datastructures now inherit from the relevant baseclasses from the
     ‘collections’ module in the stdlib.  See #794.

   - Add support for recognizing NetBSD, OpenBSD, FreeBSD, DragonFlyBSD
     platforms in the user agent string.

   - Recognize SeaMonkey browser name and version correctly

   - Recognize Baiduspider, and bingbot user agents

   - If ‘LocalProxy’’s wrapped object is a function, refer to it with
     __wrapped__ attribute.

   - The defaults of ‘generate_password_hash’ have been changed to more
     secure ones, see pull request ‘#753’.

   - Add support for encoding in options header parsing, see pull
     request ‘#933’.

   - ‘test.Client’ now properly handles Location headers with relative
     URLs, see pull request ‘#879’.

   - When ‘HTTPException’ is raised, it now prints the description, for
     easier debugging.

   - Werkzeug’s dict-like datastructures now have ‘view’-methods under
     Python 2, see pull request ‘#968’.

   - Fix a bug in ‘MultiPartParser’ when no ‘stream_factory’ was
     provided during initialization, see pull request ‘#973’.

   - Disable autocorrect and spellchecker in the debugger middleware’s
     Python prompt, see pull request ‘#994’.

   - Don’t redirect to slash route when method doesn’t match, see pull
     request ‘#907’.

   - Fix a bug when using ‘SharedDataMiddleware’ with frozen packages,
     see pull request ‘#959’.

   - ‘Range’ header parsing function fixed for invalid values ‘#974’.

   - Add support for byte Range Requests, see pull request ‘#978’.

   - Use modern cryptographic defaults in the dev servers ‘#1004’.

   - the post() method of the test client now accept file object through
     the data parameter.

   - Color run_simple’s terminal output based on HTTP codes ‘#1013’.

   - Fix self-XSS in debugger console, see ‘#1031’.

   - Fix IPython 5.x shell support, see ‘#1033’.

   - Change Accept datastructure to sort by specificity first, allowing
     for more accurate results when using ‘best_match’ for mime types
     (for example in ‘requests.accept_mimetypes.best_match’)

5.6.21 Version 0.11.16
----------------------

   - werkzeug.serving: set CONTENT_TYPE / CONTENT_LENGTH if only they’re
     provided by the client

   - werkzeug.serving: Fix crash of reloader when using ‘python -m
     werkzeug.serving’.

5.6.22 Version 0.11.15
----------------------

Released on December 30th 2016.

   - Bugfix for the bugfix in the previous release.

5.6.23 Version 0.11.14
----------------------

Released on December 30th 2016.

   - Check if platform can fork before importing ‘ForkingMixIn’, raise
     exception when creating ‘ForkingWSGIServer’ on such a platform, see
     PR ‘#999’.

5.6.24 Version 0.11.13
----------------------

Released on December 26th 2016.

   - Correct fix for the reloader issuer on certain Windows
     installations.

5.6.25 Version 0.11.12
----------------------

Released on December 26th 2016.

   - Fix more bugs in multidicts regarding empty lists.  See ‘#1000’.

   - Add some docstrings to some ‘EnvironBuilder’ properties that were
     previously unintentionally missing.

   - Added a workaround for the reloader on windows.

5.6.26 Version 0.11.11
----------------------

Released on August 31st 2016.

   - Fix JSONRequestMixin for Python3.  See #731

   - Fix broken string handling in test client when passing integers.
     See #852

   - Fix a bug in ‘parse_options_header’ where an invalid content type
     starting with comma or semi-colon would result in an invalid return
     value, see issue ‘#995’.

   - Fix a bug in multidicts when passing empty lists as values, see
     issue ‘#979’.

   - Fix a security issue that allows XSS on the Werkzeug debugger.  See
     ‘#1001’.

5.6.27 Version 0.11.10
----------------------

Released on May 24th 2016.

   - Fixed a bug that occurs when running on Python 2.6 and using a
     broken locale.  See pull request #912.

   - Fixed a crash when running the debugger on Google App Engine.  See
     issue #925.

   - Fixed an issue with multipart parsing that could cause memory
     exhaustion.

5.6.28 Version 0.11.9
---------------------

Released on April 24th 2016.

   - Corrected an issue that caused the debugger not to use the machine
     GUID on POSIX systems.

   - Corrected a Unicode error on Python 3 for the debugger’s PIN usage.

   - Corrected the timestamp verification in the pin debug code.
     Without this fix the pin was remembered for too long.

5.6.29 Version 0.11.8
---------------------

Released on April 15th 2016.

   - fixed a problem with the machine GUID detection code on OS X on
     Python 3.

5.6.30 Version 0.11.7
---------------------

Released on April 14th 2016.

   - fixed a regression on Python 3 for the debugger.

5.6.31 Version 0.11.6
---------------------

Released on April 14th 2016.

   - werkzeug.serving: Still show the client address on bad requests.

   - improved the PIN based protection for the debugger to make it
     harder to brute force via trying cookies.  Please keep in mind that
     the debugger `is not intended for running on production
     environments'

   - increased the pin timeout to a week to make it less annoying for
     people which should decrease the chance that users disable the pin
     check entirely.

   - werkzeug.serving: Fix broken HTTP_HOST when path starts with double
     slash.

5.6.32 Version 0.11.5
---------------------

Released on March 22nd 2016.

   - werkzeug.serving: Fix crash when attempting SSL connection to HTTP
     server.

5.6.33 Version 0.11.4
---------------------

Released on February 14th 2016.

   - Fixed werkzeug.serving not working from -m flag.

   - Fixed incorrect weak etag handling.

5.6.34 Version 0.11.3
---------------------

Released on December 20th 2015.

   - Fixed an issue with copy operations not working against proxies.

   - Changed the logging operations of the development server to
     correctly log where the server is running in all situations again.

   - Fixed another regression with SSL wrapping similar to the fix in
     0.11.2 but for a different code path.

5.6.35 Version 0.11.2
---------------------

Released on November 12th 2015.

   - Fix inheritable sockets on Windows on Python 3.

   - Fixed an issue with the forking server not starting any longer.

   - Fixed SSL wrapping on platforms that supported opening sockets by
     file descriptor.

   - No longer log from the watchdog reloader.

   - Unicode errors in hosts are now better caught or converted into bad
     request errors.

5.6.36 Version 0.11.1
---------------------

Released on November 10th 2015.

   - Fixed a regression on Python 3 in the debugger.

5.6.37 Version 0.11
-------------------

Released on November 8th 2015, codename Gleisbaumaschine.

   - Added ‘reloader_paths’ option to ‘run_simple’ and other functions
     in ‘werkzeug.serving’.  This allows the user to completely override
     the Python module watching of Werkzeug with custom paths.

   - Many custom cached properties of Werkzeug’s classes are now
     subclasses of Python’s ‘property’ type (issue ‘#616’).

   - ‘bind_to_environ’ now doesn’t differentiate between implicit and
     explicit default port numbers in ‘HTTP_HOST’ (pull request ‘#204’).

   - ‘BuildErrors’ are now more informative.  They come with a complete
     sentence as error message, and also provide suggestions (pull
     request ‘#691’).

   - Fix a bug in the user agent parser where Safari’s build number
     instead of version would be extracted (pull request ‘#703’).

   - Fixed issue where RedisCache set_many was broken for twemproxy,
     which doesn’t support the default MULTI command (pull request
     ‘#702’).

   - ‘mimetype’ parameters on request and response classes are now
     always converted to lowercase.

   - Changed cache so that cache never expires if timeout is 0.  This
     also fixes an issue with redis setex (issue ‘#550’)

   - Werkzeug now assumes ‘UTF-8’ as filesystem encoding on Unix if
     Python detected it as ASCII.

   - New optional ‘has’ method on caches.

   - Fixed various bugs in ‘parse_options_header’ (pull request ‘#643’).

   - If the reloader is enabled the server will now open the socket in
     the parent process if this is possible.  This means that when the
     reloader kicks in the connection from client will wait instead of
     tearing down.  This does not work on all Python versions.

   - Implemented PIN based authentication for the debugger.  This can
     optionally be disabled but is discouraged.  This change was
     necessary as it has been discovered that too many people run the
     debugger in production.

   - Devserver no longer requires SSL module to be installed.

5.6.38 Version 0.10.5
---------------------

(bugfix release, release date yet to be decided)

   - Reloader: Correctly detect file changes made by moving temporary
     files over the original, which is e.g.  the case with PyCharm (pull
     request ‘#722’).

   - Fix bool behavior of ‘werkzeug.datastructures.ETags’ under Python 3
     (issue ‘#744’).

5.6.39 Version 0.10.4
---------------------

(bugfix release, released on March 26th 2015)

   - Re-release of 0.10.3 with packaging artifacts manually removed.

5.6.40 Version 0.10.3
---------------------

(bugfix release, released on March 26th 2015)

   - Re-release of 0.10.2 without packaging artifacts.

5.6.41 Version 0.10.2
---------------------

(bugfix release, released on March 26th 2015)

   - Fixed issue where ‘empty’ could break third-party libraries that
     relied on keyword arguments (pull request ‘#675’)

   - Improved ‘Rule.empty’ by providing a ‘`get_empty_kwargs’ to allow
     setting custom kwargs without having to override entire ‘empty’
     method.  (pull request ‘#675’)

   - Fixed ‘`extra_files`’ parameter for reloader to not cause startup
     to crash when included in server params

   - Using ‘MultiDict’ when building URLs is now not supported again.
     The behavior introduced several regressions.

   - Fix performance problems with stat-reloader (pull request ‘#715’).

5.6.42 Version 0.10.1
---------------------

(bugfix release, released on February 3rd 2015)

   - Fixed regression with multiple query values for URLs (pull request
     ‘#667’).

   - Fix issues with eventlet’s monkeypatching and the builtin server
     (pull request ‘#663’).

5.6.43 Version 0.10
-------------------

Released on January 30th 2015, codename Bagger.

   - Changed the error handling of and improved testsuite for the caches
     in ‘contrib.cache’.

   - Fixed a bug on Python 3 when creating adhoc ssl contexts, due to
     ‘sys.maxint’ not being defined.

   - Fixed a bug on Python 3, that caused make_ssl_devcert().
     to fail with an exception.

   - Added exceptions for 504 and 505.

   - Added support for ChromeOS detection.

   - Added UUID converter to the routing system.

   - Added message that explains how to quit the server.

   - Fixed a bug on Python 2, that caused ‘len’ for
     werkzeug.datastructures.CombinedMultiDict to crash.

   - Added support for stdlib pbkdf2 hmac if a compatible digest is
     found.

   - Ported testsuite to use ‘py.test’.

   - Minor optimizations to various middlewares (pull requests ‘#496’
     and ‘#571’).

   - Use stdlib ‘ssl’ module instead of ‘OpenSSL’ for the builtin server
     (issue ‘#434’).  This means that OpenSSL contexts are not supported
     anymore, but instead ‘ssl.SSLContext’ from the stdlib.

   - Allow protocol-relative URLs when building external URLs.

   - Fixed Atom syndication to print time zone offset for tz-aware
     datetime objects (pull request ‘#254’).

   - Improved reloader to track added files and to recover from broken
     sys.modules setups with syntax errors in packages.

   - ‘cache.RedisCache’ now supports arbitrary ‘**kwargs’ for the redis
     object.

   - ‘werkzeug.test.Client’ now uses the original request method when
     resolving 307 redirects (pull request ‘#556’).

   - ‘werkzeug.datastructures.MIMEAccept’ now properly deals with
     mimetype parameters (pull request ‘#205’).

   - ‘werkzeug.datastructures.Accept’ now handles a quality of ‘0’ as
     intolerable, as per RFC 2616 (pull request ‘#536’).

   - ‘werkzeug.urls.url_fix’ now properly encodes hostnames with ‘idna’
     encoding (issue ‘#559’).  It also doesn’t crash on malformed URLs
     anymore (issue ‘#582’).

   - ‘werkzeug.routing.MapAdapter.match’ now recognizes the difference
     between the path ‘/’ and an empty one (issue ‘#360’).

   - The interactive debugger now tries to decode non-ascii filenames
     (issue ‘#469’).

   - Increased default key size of generated SSL certificates to 1024
     bits (issue ‘#611’).

   - Added support for specifying a ‘Response’ subclass to use when
     calling redirect().

   - ‘werkzeug.test.EnvironBuilder’ now doesn’t use the request method
     anymore to guess the content type, and purely relies on the ‘form’,
     ‘files’ and ‘input_stream’ properties (issue ‘#620’).

   - Added Symbian to the user agent platform list.

   - Fixed make_conditional to respect automatically_set_content_length

   - Unset ‘Content-Length’ when writing to response.stream (issue
     ‘#451’)

   - ‘wrappers.Request.method’ is now always uppercase, eliminating
     inconsistencies of the WSGI environment (issue ‘647’).

   - ‘routing.Rule.empty’ now works correctly with subclasses of ‘Rule’
     (pull request ‘#645’).

   - Made map updating safe in light of concurrent updates.

   - Allow multiple values for the same field for url building (issue
     ‘#658’).

5.6.44 Version 0.9.7
--------------------

(bugfix release, release date to be decided)

   - Fix unicode problems in ‘werkzeug.debug.tbtools’.

   - Fix Python 3-compatibility problems in ‘werkzeug.posixemulation’.

   - Backport fix of fatal typo for ‘ImmutableList’ (issue ‘#492’).

   - Make creation of the cache dir for ‘FileSystemCache’ atomic (issue
     ‘#468’).

   - Use native strings for memcached keys to work with Python 3 client
     (issue ‘#539’).

   - Fix charset detection for ‘werkzeug.debug.tbtools.Frame’ objects
     (issues ‘#547’ and ‘#532’).

   - Fix ‘AttributeError’ masking in ‘werkzeug.utils.import_string’
     (issue ‘#182’).

   - Explicitly shut down server (issue ‘#519’).

   - Fix timeouts greater than 2592000 being misinterpreted as UNIX
     timestamps in ‘werkzeug.contrib.cache.MemcachedCache’ (issue
     ‘#533’).

   - Fix bug where ‘werkzeug.exceptions.abort’ would raise an arbitrary
     subclass of the expected class (issue ‘#422’).

   - Fix broken ‘jsrouting’ (due to removal of ‘werkzeug.templates’)

   - ‘werkzeug.urls.url_fix’ now doesn’t crash on malformed URLs
     anymore, but returns them unmodified.  This is a cheap workaround
     for ‘#582’, the proper fix is included in version 0.10.

   - The repr of ‘werkzeug.wrappers.Request’ doesn’t crash on
     non-ASCII-values anymore (pull request ‘#466’).

   - Fix bug in ‘cache.RedisCache’ when combined with
     ‘redis.StrictRedis’ object (pull request ‘#583’).

   - The ‘qop’ parameter for ‘WWW-Authenticate’ headers is now always
     quoted, as required by RFC 2617 (issue ‘#633’).

   - Fix bug in ‘werkzeug.contrib.cache.SimpleCache’ with Python 3 where
     add/set may throw an exception when pruning old entries from the
     cache (pull request ‘#651’).

5.6.45 Version 0.9.6
--------------------

(bugfix release, released on June 7th 2014)

   - Added a safe conversion for IRI to URI conversion and use that
     internally to work around issues with spec violations for protocols
     such as ‘itms-service’.

5.6.46 Version 0.9.7
--------------------

   - Fixed uri_to_iri() not re-encoding hashes in query string
     parameters.

5.6.47 Version 0.9.5
--------------------

(bugfix release, released on June 7th 2014)

   - Forward charset argument from request objects to the environ
     builder.

   - Fixed error handling for missing boundaries in multipart data.

   - Fixed session creation on systems without ‘os.urandom()’.

   - Fixed pluses in dictionary keys not being properly URL encoded.

   - Fixed a problem with deepcopy not working for multi dicts.

   - Fixed a double quoting issue on redirects.

   - Fixed a problem with unicode keys appearing in headers on 2.x.

   - Fixed a bug with unicode strings in the test builder.

   - Fixed a unicode bug on Python 3 in the WSGI profiler.

   - Fixed an issue with the safe string compare function on Python
     2.7.7 and Python 3.4.

5.6.48 Version 0.9.4
--------------------

(bugfix release, released on August 26th 2013)

   - Fixed an issue with Python 3.3 and an edge case in cookie parsing.

   - Fixed decoding errors not handled properly through the WSGI
     decoding dance.

   - Fixed URI to IRI conversion incorrectly decoding percent signs.

5.6.49 Version 0.9.3
--------------------

(bugfix release, released on July 25th 2013)

   - Restored behavior of the ‘data’ descriptor of the request class to
     pre 0.9 behavior.  This now also means that ‘.data’ and
     ‘.get_data()’ have different behavior.  New code should use
     ‘.get_data()’ always.

     In addition to that there is now a flag for the ‘.get_data()’
     method that controls what should happen with form data parsing and
     the form parser will honor cached data.  This makes dealing with
     custom form data more consistent.

5.6.50 Version 0.9.2
--------------------

(bugfix release, released on July 18th 2013)

   - Added ‘unsafe’ parameter to url_quote().

   - Fixed an issue with url_quote_plus() not quoting ‘‘+’’
     correctly.

   - Ported remaining parts of ‘RedisCache’ to Python 3.3.

   - Ported remaining parts of ‘MemcachedCache’ to Python 3.3

   - Fixed a deprecation warning in the contrib atom module.

   - Fixed a regression with setting of content types through the
     headers dictionary instead with the content type parameter.

   - Use correct name for stdlib secure string comparison function.

   - Fixed a wrong reference in the docstring of release_local().

   - Fixed an ‘AttributeError’ that sometimes occurred when accessing
     the ‘werkzeug.wrappers.BaseResponse.is_streamed’ attribute.

5.6.51 Version 0.9.1
--------------------

(bugfix release, released on June 14th 2013)

   - Fixed an issue with integers no longer being accepted in certain
     parts of the routing system or URL quoting functions.

   - Fixed an issue with ‘url_quote’ not producing the right escape
     codes for single digit codepoints.

   - Fixed an issue with ‘SharedDataMiddleware’ not reading the path
     correctly and breaking on etag generation in some cases.

   - Properly handle ‘Expect: 100-continue’ in the development server to
     resolve issues with curl.

   - Automatically exhaust the input stream on request close.  This
     should fix issues where not touching request files results in a
     timeout.

   - Fixed exhausting of streams not doing anything if a non-limited
     stream was passed into the multipart parser.

   - Raised the buffer sizes for the multipart parser.

5.6.52 Version 0.9
------------------

Released on June 13nd 2013, codename Planierraupe.

   - Added support for tell() on the limited stream.

   - ETags now is nonzero if it contains at least one etag of
     any kind, including weak ones.

   - Added a workaround for a bug in the stdlib for SSL servers.

   - Improved SSL interface of the devserver so that it can generate
     certificates easily and load them from files.

   - Refactored test client to invoke the open method on the class for
     redirects.  This makes subclassing more powerful.

   - werkzeug.wsgi.make_chunk_iter() and
     werkzeug.wsgi.make_line_iter() now support processing of
     iterators and streams.

   - URL generation by the routing system now no longer quotes ‘+’.

   - URL fixing now no longer quotes certain reserved characters.

   - The werkzeug.security.generate_password_hash() and
     check functions now support any of the hashlib algorithms.

   - ‘wsgi.get_current_url’ is now ascii safe for browsers sending
     non-ascii data in query strings.

   - improved parsing behavior for
     werkzeug.http.parse_options_header().

   - added more operators to local proxies.

   - added a hook to override the default converter in the routing
     system.

   - The description field of HTTP exceptions is now always escaped.
     Use markup objects to disable that.

   - Added number of proxy argument to the proxy fix to make it more
     secure out of the box on common proxy setups.  It will by default
     no longer trust the x-forwarded-for header as much as it did
     before.

   - Added support for fragment handling in URI/IRI functions.

   - Added custom class support for
     werkzeug.http.parse_dict_header().

   - Renamed ‘LighttpdCGIRootFix’ to ‘CGIRootFix’.

   - Always treat ‘+’ as safe when fixing URLs as people love misusing
     them.

   - Added support to profiling into directories in the contrib
     profiler.

   - The escape function now by default escapes quotes.

   - Changed repr of exceptions to be less magical.

   - Simplified exception interface to no longer require environments to
     be passed to receive the response object.

   - Added sentinel argument to IterIO objects.

   - Added pbkdf2 support for the security module.

   - Added a plain request type that disables all form parsing to only
     leave the stream behind.

   - Removed support for deprecated ‘fix_headers’.

   - Removed support for deprecated ‘header_list’.

   - Removed support for deprecated parameter for ‘iter_encoded’.

   - Removed support for deprecated non-silent usage of the limited
     stream object.

   - Removed support for previous dummy ‘writable’ parameter on the
     cached property.

   - Added support for explicitly closing request objects to close
     associated resources.

   - Conditional request handling or access to the data property on
     responses no longer ignores direct passthrough mode.

   - Removed werkzeug.templates and werkzeug.contrib.kickstart.

   - Changed host lookup logic for forwarded hosts to allow lists of
     hosts in which case only the first one is picked up.

   - Added ‘wsgi.get_query_string’, ‘wsgi.get_path_info’ and
     ‘wsgi.get_script_name’ and made the ‘wsgi.pop_path_info’ and
     ‘wsgi.peek_path_info’ functions perform unicode decoding.  This was
     necessary to avoid having to expose the WSGI encoding dance on
     Python 3.

   - Added ‘content_encoding’ and ‘content_md5’ to the request object’s
     common request descriptor mixin.

   - added ‘options’ and ‘trace’ to the test client.

   - Overhauled the utilization of the input stream to be easier to use
     and better to extend.  The detection of content payload on the
     input side is now more compliant with HTTP by detecting off the
     content type header instead of the request method.  This also now
     means that the stream property on the request class is always
     available instead of just when the parsing fails.

   - Added support for using ‘werkzeug.wrappers.BaseResponse’ in a with
     statement.

   - Changed ‘get_app_iter’ to fetch the response early so that it does
     not fail when wrapping a response iterable.  This makes filtering
     easier.

   - Introduced ‘get_data’ and ‘set_data’ methods for responses.

   - Introduced ‘get_data’ for requests.

   - Soft deprecated the ‘data’ descriptors for request and response
     objects.

   - Added ‘as_bytes’ operations to some of the headers to simplify
     working with things like cookies.

   - Made the debugger paste tracebacks into github’s gist service as
     private pastes.

5.6.53 Version 0.8.4
--------------------

(bugfix release, release date to be announced)

   - Added a favicon to the debugger which fixes problem with state
     changes being triggered through a request to /favicon.ico in Google
     Chrome.  This should fix some problems with Flask and other
     frameworks that use context local objects on a stack with context
     preservation on errors.

   - Fixed an issue with scrolling up in the debugger.

   - Fixed an issue with debuggers running on a different URL than the
     URL root.

   - Fixed a problem with proxies not forwarding some rarely used
     special methods properly.

   - Added a workaround to prevent the XSS protection from Chrome
     breaking the debugger.

   - Skip redis tests if redis is not running.

   - Fixed a typo in the multipart parser that caused content-type to
     not be picked up properly.

5.6.54 Version 0.8.3
--------------------

(bugfix release, released on February 5th 2012)

   - Fixed another issue with werkzeug.wsgi.make_line_iter().
     where lines longer than the buffer size were not handled properly.

   - Restore stdout after debug console finished executing so that the
     debugger can be used on GAE better.

   - Fixed a bug with the redis cache for int subclasses (affects bool
     caching).

   - Fixed an XSS problem with redirect targets coming from untrusted
     sources.

   - Redis cache backend now supports password authentication.

5.6.55 Version 0.8.2
--------------------

(bugfix release, released on December 16th 2011)

   - Fixed a problem with request handling of the builtin server not
     responding to socket errors properly.

   - The routing request redirect exception’s code attribute is now used
     properly.

   - Fixed a bug with shutdowns on Windows.

   - Fixed a few unicode issues with non-ascii characters being
     hardcoded in URL rules.

   - Fixed two property docstrings being assigned to fdel instead of
     ‘__doc__’.

   - Fixed an issue where CRLF line endings could be split into two by
     the line iter function, causing problems with multipart file
     uploads.

5.6.56 Version 0.8.1
--------------------

(bugfix release, released on September 30th 2011)

   - Fixed an issue with the memcache not working properly.

   - Fixed an issue for Python 2.7.1 and higher that broke copying of
     multidicts with copy.copy()(1).

   - Changed hashing methodology of immutable ordered multi dicts for a
     potential problem with alternative Python implementations.

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/copy.html#copy.copy

5.6.57 Version 0.8
------------------

Released on September 29th 2011, codename Lötkolben

   - Removed data structure specific KeyErrors for a general purpose
     BadRequestKeyError.

   - Documented ‘werkzeug.wrappers.BaseRequest._load_form_data()’.

   - The routing system now also accepts strings instead of dictionaries
     for the ‘query_args’ parameter since we’re only passing them
     through for redirects.

   - Werkzeug now automatically sets the content length immediately when
     the ‘data’ attribute is set for efficiency and simplicity reasons.

   - The routing system will now normalize server names to lowercase.

   - The routing system will no longer raise ValueErrors in case the
     configuration for the server name was incorrect.  This should make
     deployment much easier because you can ignore that factor now.

   - Fixed a bug with parsing HTTP digest headers.  It rejected headers
     with missing nc and nonce params.

   - Proxy fix now also updates wsgi.url_scheme based on
     X-Forwarded-Proto.

   - Added support for key prefixes to the redis cache.

   - Added the ability to suppress some auto corrections in the wrappers
     that are now controlled via ‘autocorrect_location_header’ and
     ‘automatically_set_content_length’ on the response objects.

   - Werkzeug now uses a new method to check that the length of incoming
     data is complete and will raise IO errors by itself if the server
     fails to do so.

   - make_line_iter() now requires a limit that is not
     higher than the length the stream can provide.

   - Refactored form parsing into a form parser class that makes it
     possible to hook into individual parts of the parsing process for
     debugging and extending.

   - For conditional responses the content length is no longer set when
     it is already there and added if missing.

   - Immutable datastructures are hashable now.

   - Headers datastructure no longer allows newlines in values to avoid
     header injection attacks.

   - Made it possible through subclassing to select a different remote
     addr in the proxy fix.

   - Added stream based URL decoding.  This reduces memory usage on
     large transmitted form data that is URL decoded since Werkzeug will
     no longer load all the unparsed data into memory.

   - Memcache client now no longer uses the buggy cmemcache module and
     supports pylibmc.  GAE is not tried automatically and the dedicated
     class is no longer necessary.

   - Redis cache now properly serializes data.

   - Removed support for Python 2.4

5.6.58 Version 0.7.2
--------------------

(bugfix release, released on September 30th 2011)

   - Fixed a CSRF problem with the debugger.

   - The debugger is now generating private pastes on lodgeit.

   - If URL maps are now bound to environments the query arguments are
     properly decoded from it for redirects.

5.6.59 Version 0.7.1
--------------------

(bugfix release, released on July 26th 2011)

   - Fixed a problem with newer versions of IPython.

   - Disabled pyinotify based reloader which does not work reliably.

5.6.60 Version 0.7
------------------

Released on July 24th 2011, codename Schraubschlüssel

   - Add support for python-libmemcached to the Werkzeug cache
     abstraction layer.

   - Improved ‘url_decode()’ and ‘url_encode()’ performance.

   - Fixed an issue where the SharedDataMiddleware could cause an
     internal server error on weird paths when loading via
     pkg_resources.

   - Fixed an URL generation bug that caused URLs to be invalid if a
     generated component contains a colon.

   - ‘werkzeug.import_string()’ now works with partially set up packages
     properly.

   - Disabled automatic socket switching for IPv6 on the development
     server due to problems it caused.

   - Werkzeug no longer overrides the Date header when creating a
     conditional HTTP response.

   - The routing system provides a method to retrieve the matching
     methods for a given path.

   - The routing system now accepts a parameter to change the encoding
     error behaviour.

   - The local manager can now accept custom ident functions in the
     constructor that are forwarded to the wrapped local objects.

   - url_unquote_plus now accepts unicode strings again.

   - Fixed an issue with the filesystem session support’s prune function
     and concurrent usage.

   - Fixed a problem with external URL generation discarding the port.

   - Added support for pylibmc to the Werkzeug cache abstraction layer.

   - Fixed an issue with the new multipart parser that happened when a
     linebreak happened to be on the chunk limit.

   - Cookies are now set properly if ports are in use.  A runtime error
     is raised if one tries to set a cookie for a domain without a dot.

   - Fixed an issue with Template.from_file not working for file
     descriptors.

   - Reloader can now use inotify to track reloads.  This requires the
     pyinotify library to be installed.

   - Werkzeug debugger can now submit to custom lodgeit installations.

   - redirect function’s status code assertion now allows 201 to be used
     as redirection code.  While it’s not a real redirect, it shares
     enough with redirects for the function to still be useful.

   - Fixed securecookie for pypy.

   - Fixed ‘ValueErrors’ being raised on calls to ‘best_match’ on
     ‘MIMEAccept’ objects when invalid user data was supplied.

   - Deprecated ‘werkzeug.contrib.kickstart’ and
     ‘werkzeug.contrib.testtools’

   - URL routing now can be passed the URL arguments to keep them for
     redirects.  In the future matching on URL arguments might also be
     possible.

   - Header encoding changed from utf-8 to latin1 to support a port to
     Python 3.  Bytestrings passed to the object stay untouched which
     makes it possible to have utf-8 cookies.  This is a part where the
     Python 3 version will later change in that it will always operate
     on latin1 values.

   - Fixed a bug in the form parser that caused the last character to be
     dropped off if certain values in multipart data are used.

   - Multipart parser now looks at the part-individual content type
     header to override the global charset.

   - Introduced mimetype and mimetype_params attribute for the file
     storage object.

   - Changed FileStorage filename fallback logic to skip special
     filenames that Python uses for marking special files like stdin.

   - Introduced more HTTP exception classes.

   - ‘call_on_close’ now can be used as a decorator.

   - Support for redis as cache backend.

   - Added ‘BaseRequest.scheme’.

   - Support for the RFC 5789 PATCH method.

   - New custom routing parser and better ordering.

   - Removed support for ‘is_behind_proxy’.  Use a WSGI middleware
     instead that rewrites the ‘REMOTE_ADDR’ according to your setup.
     Also see the ‘werkzeug.contrib.fixers.ProxyFix’ for a drop-in
     replacement.

   - Added cookie forging support to the test client.

   - Added support for host based matching in the routing system.

   - Switched from the default ‘ignore’ to the better ‘replace’ unicode
     error handling mode.

   - The builtin server now adds a function named
     ‘werkzeug.server.shutdown’ into the WSGI env to initiate a
     shutdown.  This currently only works in Python 2.6 and later.

   - Headers are now assumed to be latin1 for better compatibility with
     Python 3 once we have support.

   - Added werkzeug.security.safe_join().

   - Added ‘accept_json’ property analogous to ‘accept_html’ on the
     werkzeug.datastructures.MIMEAccept.

   - werkzeug.utils.import_string() now fails with much
     better error messages that pinpoint to the problem.

   - Added support for parsing of the ‘If-Range’ header (see
     werkzeug.http.parse_if_range_header() and
     werkzeug.datastructures.IfRange).

   - Added support for parsing of the ‘Range’ header (see
     werkzeug.http.parse_range_header() and
     werkzeug.datastructures.Range).

   - Added support for parsing of the ‘Content-Range’ header of
     responses and provided an accessor object for it (see
     werkzeug.http.parse_content_range_header() and
     werkzeug.datastructures.ContentRange).

5.6.61 Version 0.6.2
--------------------

(bugfix release, released on April 23th 2010)

   - renamed the attribute ‘implicit_seqence_conversion’ attribute of
     the request object to ‘implicit_sequence_conversion’.

5.6.62 Version 0.6.1
--------------------

(bugfix release, released on April 13th 2010)

   - heavily improved local objects.  Should pick up standalone greenlet
     builds now and support proxies to free callables as well.  There is
     also a stacked local now that makes it possible to invoke the same
     application from within itself by pushing current request/response
     on top of the stack.

   - routing build method will also build non-default method rules
     properly if no method is provided.

   - added proper IPv6 support for the builtin server.

   - windows specific filesystem session store fixes.  (should now be
     more stable under high concurrency)

   - fixed a ‘NameError’ in the session system.

   - fixed a bug with empty arguments in the werkzeug.script system.

   - fixed a bug where log lines will be duplicated if an application
     uses ‘logging.basicConfig()’ (#499)

   - added secure password hashing and checking functions.

   - ‘HEAD’ is now implicitly added as method in the routing system if
     ‘GET’ is present.  Not doing that was considered a bug because
     often code assumed that this is the case and in web servers that do
     not normalize ‘HEAD’ to ‘GET’ this could break ‘HEAD’ requests.

   - the script support can start SSL servers now.

5.6.63 Version 0.6
------------------

Released on Feb 19th 2010, codename Hammer.

   - removed pending deprecations

   - sys.path is now printed from the testapp.

   - fixed an RFC 2068 incompatibility with cookie value quoting.

   - the ‘FileStorage’ now gives access to the multipart headers.

   - ‘cached_property.writeable’ has been deprecated.

   - ‘MapAdapter.match()’ now accepts a ‘return_rule’ keyword argument
     that returns the matched ‘Rule’ instead of just the ‘endpoint’

   - routing.Map.bind_to_environ() raises a more correct
     error message now if the map was bound to an invalid WSGI
     environment.

   - added support for SSL to the builtin development server.

   - Response objects are no longer modified in place when they are
     evaluated as WSGI applications.  For backwards compatibility the
     ‘fix_headers’ function is still called in case it was overridden.
     You should however change your application to use
     ‘get_wsgi_headers’ if you need header modifications before
     responses are sent as the backwards compatibility support will go
     away in future versions.

   - ‘append_slash_redirect()’ no longer requires the QUERY_STRING to be
     in the WSGI environment.

   - added ‘DynamicCharsetResponseMixin’

   - added ‘DynamicCharsetRequestMixin’

   - added ‘BaseRequest.url_charset’

   - request and response objects have a default ‘__repr__’ now.

   - builtin data structures can be pickled now.

   - the form data parser will now look at the filename instead the
     content type to figure out if it should treat the upload as regular
     form data or file upload.  This fixes a bug with Google Chrome.

   - improved performance of ‘make_line_iter’ and the multipart parser
     for binary uploads.

   - fixed ‘is_streamed’

   - fixed a path quoting bug in ‘EnvironBuilder’ that caused PATH_INFO
     and SCRIPT_NAME to end up in the environ unquoted.

   - ‘werkzeug.BaseResponse.freeze()’ now sets the content length.

   - for unknown HTTP methods the request stream is now always limited
     instead of being empty.  This makes it easier to implement DAV and
     other protocols on top of Werkzeug.

   - added ‘werkzeug.MIMEAccept.best_match()’

   - multi-value test-client posts from a standard dictionary are now
     supported.  Previously you had to use a multi dict.

   - rule templates properly work with submounts, subdomains and other
     rule factories now.

   - deprecated non-silent usage of the ‘werkzeug.LimitedStream’.

   - added support for IRI handling to many parts of Werkzeug.

   - development server properly logs to the werkzeug logger now.

   - added ‘werkzeug.extract_path_info()’

   - fixed a querystring quoting bug in ‘url_fix()’

   - added ‘fallback_mimetype’ to ‘werkzeug.SharedDataMiddleware’.

   - deprecated ‘BaseResponse.iter_encoded()’’s charset parameter.

   - added ‘BaseResponse.make_sequence()’, ‘BaseResponse.is_sequence’
     and ‘BaseResponse._ensure_sequence()’.

   - added better __repr__ of ‘werkzeug.Map’

   - ‘import_string’ accepts unicode strings as well now.

   - development server doesn’t break on double slashes after the host
     name.

   - better ‘__repr__’ and ‘__str__’ of
     werkzeug.exceptions.HTTPException.

   - test client works correctly with multiple cookies now.

   - the werkzeug.routing.Map now has a class attribute with
     the default converter mapping.  This helps subclasses to override
     the converters without passing them to the constructor.

   - implemented ‘OrderedMultiDict’

   - improved the session support for more efficient session storing on
     the filesystem.  Also added support for listing of sessions
     currently stored in the filesystem session store.

   - werkzeug no longer utilizes the Python time module for parsing
     which means that dates in a broader range can be parsed.

   - the wrappers have no class attributes that make it possible to swap
     out the dict and list types it uses.

   - werkzeug debugger should work on the appengine dev server now.

   - the URL builder supports dropping of unexpected arguments now.
     Previously they were always appended to the URL as query string.

   - profiler now writes to the correct stream.

5.6.64 Version 0.5.1
--------------------

(bugfix release for 0.5, released on July 9th 2009)

   - fixed boolean check of ‘FileStorage’

   - url routing system properly supports unicode URL rules now.

   - file upload streams no longer have to provide a truncate() method.

   - implemented ‘BaseRequest._form_parsing_failed()’.

   - fixed #394

   - ‘ImmutableDict.copy()’, ‘ImmutableMultiDict.copy()’ and
     ‘ImmutableTypeConversionDict.copy()’ return mutable shallow copies.

   - fixed a bug with the ‘make_runserver’ script action.

   - ‘MultiDict.items()’ and ‘MutiDict.iteritems()’ now accept an
     argument to return a pair for each value of each key.

   - the multipart parser works better with hand-crafted multipart
     requests now that have extra newlines added.  This fixes a bug with
     setuptools uploads not handled properly (#390)

   - fixed some minor bugs in the atom feed generator.

   - fixed a bug with client cookie header parsing being case sensitive.

   - fixed a not-working deprecation warning.

   - fixed package loading for ‘SharedDataMiddleware’.

   - fixed a bug in the secure cookie that made server-side expiration
     on servers with a local time that was not set to UTC impossible.

   - fixed console of the interactive debugger.

5.6.65 Version 0.5
------------------

Released on April 24th, codename Schlagbohrer.

   - requires Python 2.4 now

   - fixed a bug in ‘IterIO’

   - added ‘MIMEAccept’ and ‘CharsetAccept’ that work like the regular
     ‘Accept’ but have extra special normalization for mimetypes and
     charsets and extra convenience methods.

   - switched the serving system from wsgiref to something homebrew.

   - the ‘Client’ now supports cookies.

   - added the ‘fixers’ module with various fixes for webserver bugs and
     hosting setup side-effects.

   - added ‘werkzeug.contrib.wrappers’

   - added ‘is_hop_by_hop_header()’

   - added ‘is_entity_header()’

   - added ‘remove_hop_by_hop_headers()’

   - added ‘pop_path_info()’

   - added ‘peek_path_info()’

   - added ‘wrap_file()’ and ‘FileWrapper’

   - moved ‘LimitedStream’ from the contrib package into the regular
     werkzeug one and changed the default behavior to raise exceptions
     rather than stopping without warning.  The old class will stick in
     the module until 0.6.

   - implemented experimental multipart parser that replaces the old CGI
     hack.

   - added ‘dump_options_header()’ and ‘parse_options_header()’

   - added ‘quote_header_value()’ and ‘unquote_header_value()’

   - ‘url_encode()’ and ‘url_decode()’ now accept a separator argument
     to switch between ‘&’ and ‘;’ as pair separator.  The magic switch
     is no longer in place.

   - all form data parsing functions as well as the ‘BaseRequest’ object
     have parameters (or attributes) to limit the number of incoming
     bytes (either totally or per field).

   - added ‘LanguageAccept’

   - request objects are now enforced to be read only for all
     collections.

   - added many new collection classes, refactored collections in
     general.

   - test support was refactored, semi-undocumented ‘werkzeug.test.File’
     was replaced by ‘werkzeug.FileStorage’.

   - ‘EnvironBuilder’ was added and unifies the previous distinct
     ‘create_environ()’, ‘Client’ and ‘BaseRequest.from_values()’.  They
     all work the same now which is less confusing.

   - officially documented imports from the internal modules as
     undefined behavior.  These modules were never exposed as public
     interfaces.

   - removed ‘FileStorage.__len__’ which previously made the object
     falsy for browsers not sending the content length which all
     browsers do.

   - ‘SharedDataMiddleware’ uses ‘wrap_file’ now and has a configurable
     cache timeout.

   - added ‘CommonRequestDescriptorsMixin’

   - added ‘CommonResponseDescriptorsMixin.mimetype_params’

   - added ‘werkzeug.contrib.lint’

   - added ‘passthrough_errors’ to ‘run_simple’.

   - added ‘secure_filename’

   - added ‘make_line_iter()’

   - ‘MultiDict’ copies now instead of revealing internal lists to the
     caller for ‘getlist’ and iteration functions that return lists.

   - added ‘follow_redirect’ to the open()(1) of ‘Client’.

   - added support for ‘extra_files’ in ‘make_runserver()’

   ---------- Footnotes ----------

   (1) https://docs.python.org/3/library/functions.html#open

5.6.66 Version 0.4.1
--------------------

(Bugfix release, released on January 11th 2009)

   - ‘werkzeug.contrib.cache.Memcached’ accepts now objects that
     implement the memcache.Client interface as alternative to a list of
     strings with server addresses.  There is also now a
     ‘GAEMemcachedCache’ that connects to the Google appengine cache.

   - explicitly convert secret keys to bytestrings now because Python
     2.6 no longer does that.

   - ‘url_encode’ and all interfaces that call it, support ordering of
     options now which however is disabled by default.

   - the development server no longer resolves the addresses of clients.

   - Fixed a typo in ‘werkzeug.test’ that broke ‘File’.

   - ‘Map.bind_to_environ’ uses the ‘Host’ header now if available.

   - Fixed ‘BaseCache.get_dict’ (#345)

   - ‘werkzeug.test.Client’ can now run the application buffered in
     which case the application is properly closed automatically.

   - Fixed ‘Headers.set’ (#354).  Caused header duplication before.

   - Fixed ‘Headers.pop’ (#349).  default parameter was not properly
     handled.

   - Fixed UnboundLocalError in ‘create_environ’ (#351)

   - ‘Headers’ is more compatible with wsgiref now.

   - ‘Template.render’ accepts multidicts now.

   - dropped support for Python 2.3

5.6.67 Version 0.4
------------------

Released on November 23rd 2008, codename Schraubenzieher.

   - ‘Client’ supports an empty ‘data’ argument now.

   - fixed a bug in ‘Response.application’ that made it impossible to
     use it as method decorator.

   - the session system should work on appengine now

   - the secure cookie works properly in load balanced environments with
     different cpu architectures now.

   - ‘CacheControl.no_cache’ and ‘CacheControl.private’ behavior changed
     to reflect the possibilities of the HTTP RFC. Setting these
     attributes to ‘None’ or ‘True’ now sets the value to “the empty
     value”.  More details in the documentation.

   - fixed ‘werkzeug.contrib.atom.AtomFeed.__call__’.  (#338)

   - ‘BaseResponse.make_conditional’ now always returns ‘self’.
     Previously it didn’t for post requests and such.

   - fixed a bug in boolean attribute handling of ‘html’ and ‘xhtml’.

   - added graceful error handling to the debugger pastebin feature.

   - added a more list like interface to ‘Headers’ (slicing and indexing
     works now)

   - fixed a bug with the ‘__setitem__’ method of ‘Headers’ that didn’t
     properly remove all keys on replacing.

   - added ‘remove_entity_headers’ which removes all entity headers from
     a list of headers (or a ‘Headers’ object)

   - the responses now automatically call ‘remove_entity_headers’ if the
     status code is 304.

   - fixed a bug with ‘Href’ query parameter handling.  Previously the
     last item of a call to ‘Href’ was not handled properly if it was a
     dict.

   - headers now support a ‘pop’ operation to better work with environ
     properties.

5.6.68 Version 0.3.1
--------------------

(bugfix release, released on June 24th 2008)

   - fixed a security problem with ‘werkzeug.contrib.SecureCookie’.

5.6.69 Version 0.3
------------------

Released on June 14th 2008, codename EUR325CAT6.

   - added support for redirecting in url routing.

   - added ‘Authorization’ and ‘AuthorizationMixin’

   - added ‘WWWAuthenticate’ and ‘WWWAuthenticateMixin’

   - added ‘parse_list_header’

   - added ‘parse_dict_header’

   - added ‘parse_authorization_header’

   - added ‘parse_www_authenticate_header’

   - added ‘_get_current_object’ method to ‘LocalProxy’ objects

   - added ‘parse_form_data’

   - ‘MultiDict’, ‘CombinedMultiDict’, ‘Headers’, and ‘EnvironHeaders’
     raise special key errors now that are subclasses of ‘BadRequest’ so
     if you don’t catch them they give meaningful HTTP responses.

   - added support for alternative encoding error handling and the new
     ‘HTTPUnicodeError’ which (if not caught) behaves like a
     ‘BadRequest’.

   - added ‘BadRequest.wrap’.

   - added ETag support to the SharedDataMiddleware and added an option
     to disable caching.

   - fixed ‘is_xhr’ on the request objects.

   - fixed error handling of the url adapter’s ‘dispatch’ method.
     (#318)

   - fixed bug with ‘SharedDataMiddleware’.

   - fixed ‘Accept.values’.

   - ‘EnvironHeaders’ contain content-type and content-length now

   - ‘url_encode’ treats lists and tuples in dicts passed to it as
     multiple values for the same key so that one doesn’t have to pass a
     ‘MultiDict’ to the function.

   - added ‘validate_arguments’

   - added ‘BaseRequest.application’

   - improved Python 2.3 support

   - ‘run_simple’ accepts ‘use_debugger’ and ‘use_evalex’ parameters
     now, like the ‘make_runserver’ factory function from the script
     module.

   - the ‘environ_property’ is now read-only by default

   - it’s now possible to initialize requests as “shallow” requests
     which causes runtime errors if the request object tries to consume
     the input stream.

5.6.70 Version 0.2
------------------

Released Feb 14th 2008, codename Faustkeil.

   - Added ‘AnyConverter’ to the routing system.

   - Added ‘werkzeug.contrib.securecookie’

   - Exceptions have a ‘get_response()’ method that return a response
     object

   - fixed the path ordering bug (#293), thanks Thomas Johansson

   - ‘BaseReporterStream’ is now part of the werkzeug contrib module.
     From Werkzeug 0.3 onwards you will have to import it from there.

   - added ‘DispatcherMiddleware’.

   - ‘RequestRedirect’ is now a subclass of ‘HTTPException’ and uses a
     301 status code instead of 302.

   - ‘url_encode’ and ‘url_decode’ can optionally treat keys as unicode
     strings now, too.

   - ‘werkzeug.script’ has a different caller format for boolean
     arguments now.

   - renamed ‘lazy_property’ to ‘cached_property’.

   - added ‘import_string’.

   - added is_* properties to request objects.

   - added ‘empty()’ method to routing rules.

   - added ‘werkzeug.contrib.profiler’.

   - added ‘extends’ to ‘Headers’.

   - added ‘dump_cookie’ and ‘parse_cookie’.

   - added ‘as_tuple’ to the ‘Client’.

   - added ‘werkzeug.contrib.testtools’.

   - added ‘werkzeug.unescape’

   - added ‘BaseResponse.freeze’

   - added ‘werkzeug.contrib.atom’

   - the HTTPExceptions accept an argument ‘description’ now which
     overrides the default description.

   - the ‘MapAdapter’ has a default for path info now.  If you use
     ‘bind_to_environ’ you don’t have to pass the path later.

   - the wsgiref subclass werkzeug uses for the dev server does not use
     direct sys.stderr logging any more but a logger called “werkzeug”.

   - implemented ‘Href’.

   - implemented ‘find_modules’

   - refactored request and response objects into base objects, mixins
     and full featured subclasses that implement all mixins.

   - added simple user agent parser

   - werkzeug’s routing raises ‘MethodNotAllowed’ now if it matches a
     rule but for a different method.

   - many fixes and small improvements

5.6.71 Version 0.1
------------------

Released on Dec 9th 2007, codename Wictorinoxger.

   - Initial release