Merge branch '1.0.x'

This commit is contained in:
David Lord 2019-05-16 12:18:36 -07:00
commit 2236ba980c
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8
18 changed files with 76 additions and 60 deletions

View file

@ -9,8 +9,9 @@ Support questions
Please, don't use the issue tracker for this. Use one of the following Please, don't use the issue tracker for this. Use one of the following
resources for questions about your own code: resources for questions about your own code:
* The IRC channel ``#pocoo`` on FreeNode. * The ``#get-help`` channel on our Discord chat: https://discord.gg/t6rrQZH
* The IRC channel ``#python`` on FreeNode for more general questions. * The IRC channel ``#pocoo`` on FreeNode is linked to Discord, but
Discord is preferred.
* The mailing list flask@python.org for long term discussion or larger issues. * The mailing list flask@python.org for long term discussion or larger issues.
* Ask on `Stack Overflow`_. Search with Google first using: * Ask on `Stack Overflow`_. Search with Google first using:
``site:stackoverflow.com flask {search term, exception message, etc.}`` ``site:stackoverflow.com flask {search term, exception message, etc.}``
@ -81,14 +82,26 @@ First time setup
Start coding Start coding
~~~~~~~~~~~~ ~~~~~~~~~~~~
- Create a branch to identify the issue you would like to work on (e.g. - Create a branch to identify the issue you would like to work on. If
``2287-dry-test-suite``) you're submitting a bug or documentation fix, branch off of the
latest ".x" branch::
git checkout -b your-branch-name origin/1.0.x
If you're submitting a feature addition or change, branch off of the
"master" branch::
git checkout -b your-branch-name origin/master
- Using your favorite editor, make your changes, `committing as you go`_. - Using your favorite editor, make your changes, `committing as you go`_.
- Try to follow `PEP8`_, but you may ignore the line length limit if following - Try to follow `PEP8`_, but you may ignore the line length limit if following
it would make the code uglier. it would make the code uglier.
- Include tests that cover any code changes you make. Make sure the test fails - Include tests that cover any code changes you make. Make sure the test fails
without your patch. `Run the tests. <contributing-testsuite_>`_. without your patch. `Run the tests. <contributing-testsuite_>`_.
- Push your commits to GitHub and `create a pull request`_. - Push your commits to GitHub and `create a pull request`_ by using::
git push --set-upstream origin your-branch-name
- Celebrate 🎉 - Celebrate 🎉
.. _committing as you go: https://dont-be-afraid-to-commit.readthedocs.io/en/latest/git/commandlinegit.html#commit-your-changes .. _committing as you go: https://dont-be-afraid-to-commit.readthedocs.io/en/latest/git/commandlinegit.html#commit-your-changes

View file

@ -75,6 +75,7 @@ Links
* Test status: https://dev.azure.com/pallets/pallets/_build?definitionId=2 * Test status: https://dev.azure.com/pallets/pallets/_build?definitionId=2
* Test coverage: https://codecov.io/gh/pallets/flask * Test coverage: https://codecov.io/gh/pallets/flask
* Official chat: https://discord.gg/t6rrQZH
.. _WSGI: https://wsgi.readthedocs.io .. _WSGI: https://wsgi.readthedocs.io
.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/ .. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/

View file

@ -726,7 +726,7 @@ requests, make sure the default route only handles ``GET``, as redirects
can't preserve form data. :: can't preserve form data. ::
@app.route('/region/', defaults={'id': 1}) @app.route('/region/', defaults={'id': 1})
@app.route('/region/<id>', methods=['GET', 'POST']) @app.route('/region/<int:id>', methods=['GET', 'POST'])
def region(id): def region(id):
pass pass

View file

@ -49,7 +49,7 @@ Typically, an application context will have the same lifetime as a
request. request.
See :doc:`/reqcontext` for more information about how the contexts work See :doc:`/reqcontext` for more information about how the contexts work
and the full lifecycle of a request. and the full life cycle of a request.
Manually Push a Context Manually Push a Context

View file

@ -97,6 +97,6 @@ Discuss with the community.
The Flask developers keep the framework accessible to users with codebases big The Flask developers keep the framework accessible to users with codebases big
and small. If you find an obstacle in your way, caused by Flask, don't hesitate and small. If you find an obstacle in your way, caused by Flask, don't hesitate
to contact the developers on the mailinglist or IRC channel. The best way for to contact the developers on the mailing list or IRC channel. The best way for
the Flask and Flask extension developers to improve the tools for larger the Flask and Flask extension developers to improve the tools for larger
applications is getting feedback from users. applications is getting feedback from users.

View file

@ -246,7 +246,7 @@ was dispatched to any other admin blueprint endpoint.
Error Handlers Error Handlers
-------------- --------------
Blueprints support the errorhandler decorator just like the :class:`Flask` Blueprints support the ``errorhandler`` decorator just like the :class:`Flask`
application object, so it is easy to make Blueprint-specific custom error application object, so it is easy to make Blueprint-specific custom error
pages. pages.
@ -258,14 +258,13 @@ Here is an example for a "404 Page Not Found" exception::
Most errorhandlers will simply work as expected; however, there is a caveat Most errorhandlers will simply work as expected; however, there is a caveat
concerning handlers for 404 and 405 exceptions. These errorhandlers are only concerning handlers for 404 and 405 exceptions. These errorhandlers are only
invoked from an appropriate ``raise`` statement or a call to ``abort`` invoked from an appropriate ``raise`` statement or a call to ``abort`` in another
in another of the blueprint's view functions; they are not invoked by, of the blueprint's view functions; they are not invoked by, e.g., an invalid URL
e.g., an invalid URL access. This is because the blueprint does not access. This is because the blueprint does not "own" a certain URL space, so
"own" a certain URL space, so the application instance has no way of the application instance has no way of knowing which blueprint error handler it
knowing which blueprint errorhandler it should run if given an invalid URL. should run if given an invalid URL. If you would like to execute different
If you would like to execute different handling strategies for these errors handling strategies for these errors based on URL prefixes, they may be defined
based on URL prefixes, they may be defined at the application level using at the application level using the ``request`` proxy object::
the ``request`` proxy object::
@app.errorhandler(404) @app.errorhandler(404)
@app.errorhandler(405) @app.errorhandler(405)

View file

@ -68,9 +68,9 @@ parts:
The ``create_app`` factory in ``hello`` is called with the string ``'dev'`` The ``create_app`` factory in ``hello`` is called with the string ``'dev'``
as the argument. as the argument.
If ``FLASK_APP`` is not set, the command will look for a file called If ``FLASK_APP`` is not set, the command will try to import "app" or
:file:`wsgi.py` or :file:`app.py` and try to detect an application instance or "wsgi" (as a ".py" file, or package) and try to detect an application
factory. instance or factory.
Within the given import, the command looks for an application instance named Within the given import, the command looks for an application instance named
``app`` or ``application``, then any application instance. If no instance is ``app`` or ``application``, then any application instance. If no instance is

View file

@ -9,7 +9,7 @@ toggling the debug mode, setting the secret key, and other such
environment-specific things. environment-specific things.
The way Flask is designed usually requires the configuration to be The way Flask is designed usually requires the configuration to be
available when the application starts up. You can hardcode the available when the application starts up. You can hard code the
configuration in the code, which for many small applications is not configuration in the code, which for many small applications is not
actually that bad, but there are better ways. actually that bad, but there are better ways.
@ -437,6 +437,7 @@ methods on the config object as well to load from individual files. For a
complete reference, read the :class:`~flask.Config` object's complete reference, read the :class:`~flask.Config` object's
documentation. documentation.
Configuring from Environment Variables Configuring from Environment Variables
-------------------------------------- --------------------------------------
@ -448,15 +449,13 @@ Environment variables can be set on Linux or OS X with the export command in
the shell before starting the server:: the shell before starting the server::
$ export SECRET_KEY='5f352379324c22463451387a0aec5d2f' $ export SECRET_KEY='5f352379324c22463451387a0aec5d2f'
$ export DEBUG=False $ export MAIL_ENABLED=false
$ python run-app.py $ python run-app.py
* Running on http://127.0.0.1:5000/ * Running on http://127.0.0.1:5000/
* Restarting with reloader...
On Windows systems use the `set` builtin instead:: On Windows systems use the ``set`` builtin instead::
> set SECRET_KEY='5f352379324c22463451387a0aec5d2f' > set SECRET_KEY='5f352379324c22463451387a0aec5d2f'
> set DEBUG=False
While this approach is straightforward to use, it is important to remember that While this approach is straightforward to use, it is important to remember that
environment variables are strings -- they are not automatically deserialized environment variables are strings -- they are not automatically deserialized
@ -464,17 +463,15 @@ into Python types.
Here is an example of a configuration file that uses environment variables:: Here is an example of a configuration file that uses environment variables::
# Example configuration
import os import os
ENVIRONMENT_DEBUG = os.environ.get("DEBUG", default=False) _mail_enabled = os.environ.get("MAIL_ENABLED", default="true")
if ENVIRONMENT_DEBUG.lower() in ("f", "false"): MAIL_ENABLED = _mail_enabled.lower() in {"1", "t", "true"}
ENVIRONMENT_DEBUG = False
SECRET_KEY = os.environ.get("SECRET_KEY")
DEBUG = ENVIRONMENT_DEBUG
SECRET_KEY = os.environ.get("SECRET_KEY", default=None)
if not SECRET_KEY: if not SECRET_KEY:
raise ValueError("No secret key set for Flask application") raise ValueError("No SECRET_KEY set for Flask application")
Notice that any value besides an empty string will be interpreted as a boolean Notice that any value besides an empty string will be interpreted as a boolean
@ -486,6 +483,7 @@ ability to access the configuration when starting up. There are other methods
on the config object as well to load from individual files. For a complete on the config object as well to load from individual files. For a complete
reference, read the :class:`~flask.Config` class documentation. reference, read the :class:`~flask.Config` class documentation.
Configuration Best Practices Configuration Best Practices
---------------------------- ----------------------------
@ -496,7 +494,7 @@ that experience:
1. Create your application in a function and register blueprints on it. 1. Create your application in a function and register blueprints on it.
That way you can create multiple instances of your application with That way you can create multiple instances of your application with
different configurations attached which makes unittesting a lot different configurations attached which makes unit testing a lot
easier. You can use this to pass in configuration as needed. easier. You can use this to pass in configuration as needed.
2. Do not write code that needs the configuration at import time. If you 2. Do not write code that needs the configuration at import time. If you
@ -529,7 +527,7 @@ the config file by adding ``from yourapplication.default_settings
import *`` to the top of the file and then overriding the changes by hand. import *`` to the top of the file and then overriding the changes by hand.
You could also inspect an environment variable like You could also inspect an environment variable like
``YOURAPPLICATION_MODE`` and set that to `production`, `development` etc ``YOURAPPLICATION_MODE`` and set that to `production`, `development` etc
and import different hardcoded files based on that. and import different hard-coded files based on that.
An interesting pattern is also to use classes and inheritance for An interesting pattern is also to use classes and inheritance for
configuration:: configuration::

View file

@ -23,9 +23,15 @@ For example, to run a Flask application with 4 worker processes (``-w
$ gunicorn -w 4 -b 127.0.0.1:4000 myproject:app $ gunicorn -w 4 -b 127.0.0.1:4000 myproject:app
The ``gunicorn`` command expects the names of your application module or
package and the application instance within the module. If you use the
application factory pattern, you can pass a call to that::
$ gunicorn "myproject:create_app()"
.. _Gunicorn: https://gunicorn.org/ .. _Gunicorn: https://gunicorn.org/
.. _eventlet: https://eventlet.net/ .. _eventlet: https://eventlet.net/
.. _greenlet: https://greenlet.readthedocs.io/en/latest/
uWSGI uWSGI
-------- --------
@ -123,8 +129,8 @@ If your httpd is not providing these headers, the most common setup invokes the
host being set from ``X-Forwarded-Host`` and the remote address from host being set from ``X-Forwarded-Host`` and the remote address from
``X-Forwarded-For``:: ``X-Forwarded-For``::
from werkzeug.contrib.fixers import ProxyFix from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app) app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
.. admonition:: Trusting Headers .. admonition:: Trusting Headers

View file

@ -41,7 +41,7 @@ the time. There are ways to fake multiple applications with a single
application object, like maintaining a stack of applications, but this application object, like maintaining a stack of applications, but this
causes some problems I won't outline here in detail. Now the question is: causes some problems I won't outline here in detail. Now the question is:
when does a microframework need more than one application at the same when does a microframework need more than one application at the same
time? A good example for this is unittesting. When you want to test time? A good example for this is unit testing. When you want to test
something it can be very helpful to create a minimal application to test something it can be very helpful to create a minimal application to test
specific behavior. When the application object is deleted everything it specific behavior. When the application object is deleted everything it
allocated will be freed again. allocated will be freed again.
@ -76,7 +76,7 @@ there are better ways to do that so that you do not lose the reference
to the application object :meth:`~flask.Flask.wsgi_app`). to the application object :meth:`~flask.Flask.wsgi_app`).
Furthermore this design makes it possible to use a factory function to Furthermore this design makes it possible to use a factory function to
create the application which is very helpful for unittesting and similar create the application which is very helpful for unit testing and similar
things (:ref:`app-factories`). things (:ref:`app-factories`).
The Routing System The Routing System

View file

@ -287,7 +287,7 @@ also avoids having multiple developers working in isolation on pretty much the
same problem. same problem.
Remember: good API design is hard, so introduce your project on the Remember: good API design is hard, so introduce your project on the
mailinglist, and let other developers give you a helping hand with mailing list, and let other developers give you a helping hand with
designing the API. designing the API.
The best Flask extensions are extensions that share common idioms for the The best Flask extensions are extensions that share common idioms for the

View file

@ -6,7 +6,7 @@ Extensions
Extensions are extra packages that add functionality to a Flask Extensions are extra packages that add functionality to a Flask
application. For example, an extension might add support for sending application. For example, an extension might add support for sending
email or connecting to a database. Some extensions add entire new email or connecting to a database. Some extensions add entire new
frameworks to help build certain types of applications, like a ReST API. frameworks to help build certain types of applications, like a REST API.
Finding Extensions Finding Extensions

View file

@ -2,14 +2,14 @@ Adding HTTP Method Overrides
============================ ============================
Some HTTP proxies do not support arbitrary HTTP methods or newer HTTP Some HTTP proxies do not support arbitrary HTTP methods or newer HTTP
methods (such as PATCH). In that case it's possible to “proxy” HTTP methods (such as PATCH). In that case it's possible to "proxy" HTTP
methods through another HTTP method in total violation of the protocol. methods through another HTTP method in total violation of the protocol.
The way this works is by letting the client do an HTTP POST request and The way this works is by letting the client do an HTTP POST request and
set the ``X-HTTP-Method-Override`` header and set the value to the set the ``X-HTTP-Method-Override`` header. Then the method is replaced
intended HTTP method (such as ``PATCH``). with the header value before being passed to Flask.
This can easily be accomplished with an HTTP middleware:: This can be accomplished with an HTTP middleware::
class HTTPMethodOverrideMiddleware(object): class HTTPMethodOverrideMiddleware(object):
allowed_methods = frozenset([ allowed_methods = frozenset([
@ -29,13 +29,12 @@ This can easily be accomplished with an HTTP middleware::
def __call__(self, environ, start_response): def __call__(self, environ, start_response):
method = environ.get('HTTP_X_HTTP_METHOD_OVERRIDE', '').upper() method = environ.get('HTTP_X_HTTP_METHOD_OVERRIDE', '').upper()
if method in self.allowed_methods: if method in self.allowed_methods:
method = method.encode('ascii', 'replace')
environ['REQUEST_METHOD'] = method environ['REQUEST_METHOD'] = method
if method in self.bodyless_methods: if method in self.bodyless_methods:
environ['CONTENT_LENGTH'] = '0' environ['CONTENT_LENGTH'] = '0'
return self.app(environ, start_response) return self.app(environ, start_response)
To use this with Flask this is all that is necessary:: To use this with Flask, wrap the app object with the middleware::
from flask import Flask from flask import Flask

View file

@ -203,7 +203,7 @@ of the argument like ``<converter:variable_name>``. ::
@app.route('/user/<username>') @app.route('/user/<username>')
def show_user_profile(username): def show_user_profile(username):
# show the user profile for that user # show the user profile for that user
return 'User %s' % username return 'User %s' % escape(username)
@app.route('/post/<int:post_id>') @app.route('/post/<int:post_id>')
def show_post(post_id): def show_post(post_id):
@ -213,7 +213,7 @@ of the argument like ``<converter:variable_name>``. ::
@app.route('/path/<path:subpath>') @app.route('/path/<path:subpath>')
def show_subpath(subpath): def show_subpath(subpath):
# show the subpath after /path/ # show the subpath after /path/
return 'Subpath %s' % subpath return 'Subpath %s' % escape(subpath)
Converter types: Converter types:
@ -281,7 +281,7 @@ Python shell. See :ref:`context-locals`.
.. code-block:: python .. code-block:: python
from flask import Flask, url_for from flask import Flask, escape, url_for
app = Flask(__name__) app = Flask(__name__)
@ -295,7 +295,7 @@ Python shell. See :ref:`context-locals`.
@app.route('/user/<username>') @app.route('/user/<username>')
def profile(username): def profile(username):
return '{}\'s profile'.format(username) return '{}\'s profile'.format(escape(username))
with app.test_request_context(): with app.test_request_context():
print(url_for('index')) print(url_for('index'))
@ -690,10 +690,10 @@ response objects is as follows:
returned from the view. returned from the view.
2. If it's a string, a response object is created with that data and the 2. If it's a string, a response object is created with that data and the
default parameters. default parameters.
3. If a tuple is returned the items in the tuple can provide extra 3. If a tuple is returned the items in the tuple can provide extra information.
information. Such tuples have to be in the form ``(response, status, Such tuples have to be in the form ``(response, status, headers)``,
headers)`` or ``(response, headers)`` where at least one item has ``(response, headers)`` or ``(response, status)`` where at least one item
to be in the tuple. The ``status`` value will override the status code has to be in the tuple. The ``status`` value will override the status code
and ``headers`` can be a list or dictionary of additional header values. and ``headers`` can be a list or dictionary of additional header values.
4. If none of that works, Flask will assume the return value is a 4. If none of that works, Flask will assume the return value is a
valid WSGI application and convert that into a response object. valid WSGI application and convert that into a response object.

View file

@ -20,7 +20,7 @@ can you do?
This is where some helper functions come in handy. Keep in mind however This is where some helper functions come in handy. Keep in mind however
that these functions are not only there for interactive shell usage, but that these functions are not only there for interactive shell usage, but
also for unittesting and other situations that require a faked request also for unit testing and other situations that require a faked request
context. context.
Generally it's recommended that you read the :ref:`request-context` Generally it's recommended that you read the :ref:`request-context`

View file

@ -43,8 +43,8 @@ The Golden Rule
So the rule of thumb: if you are not dealing with binary data, work with So the rule of thumb: if you are not dealing with binary data, work with
Unicode. What does working with Unicode in Python 2.x mean? Unicode. What does working with Unicode in Python 2.x mean?
- as long as you are using ASCII charpoints only (basically numbers, - as long as you are using ASCII code points only (basically numbers,
some special characters of latin letters without umlauts or anything some special characters of Latin letters without umlauts or anything
fancy) you can use regular string literals (``'Hello World'``). fancy) you can use regular string literals (``'Hello World'``).
- if you need anything else than ASCII in a string you have to mark - if you need anything else than ASCII in a string you have to mark
this string as Unicode string by prefixing it with a lowercase `u`. this string as Unicode string by prefixing it with a lowercase `u`.

View file

@ -175,7 +175,7 @@ def has_request_context():
self.remote_addr = remote_addr self.remote_addr = remote_addr
Alternatively you can also just test any of the context bound objects Alternatively you can also just test any of the context bound objects
(such as :class:`request` or :class:`g` for truthness):: (such as :class:`request` or :class:`g`) for truthness::
class User(db.Model): class User(db.Model):

View file

@ -278,7 +278,7 @@ def url_for(endpoint, **values):
:param values: the variable arguments of the URL rule :param values: the variable arguments of the URL rule
:param _external: if set to ``True``, an absolute URL is generated. Server :param _external: if set to ``True``, an absolute URL is generated. Server
address can be changed via ``SERVER_NAME`` configuration variable which address can be changed via ``SERVER_NAME`` configuration variable which
defaults to `localhost`. falls back to the `Host` header, then to the IP and port of the request.
:param _scheme: a string specifying the desired URL scheme. The `_external` :param _scheme: a string specifying the desired URL scheme. The `_external`
parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default parameter must be set to ``True`` or a :exc:`ValueError` is raised. The default
behavior uses the same scheme as the current request, or behavior uses the same scheme as the current request, or