Merge branch 'main' into class-route

This commit is contained in:
Grey Li 2021-08-06 09:47:32 +08:00 committed by GitHub
commit e5fb65b171
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 902 additions and 534 deletions

View file

@ -7,7 +7,8 @@ Using ``async`` and ``await``
Routes, error handlers, before request, after request, and teardown
functions can all be coroutine functions if Flask is installed with the
``async`` extra (``pip install flask[async]``). This allows views to be
``async`` extra (``pip install flask[async]``). It requires Python 3.7+
where ``contextvars.ContextVar`` is available. This allows views to be
defined with ``async def`` and use ``await``.
.. code-block:: python
@ -17,6 +18,18 @@ defined with ``async def`` and use ``await``.
data = await async_db_query(...)
return jsonify(data)
Pluggable class-based views also support handlers that are implemented as
coroutines. This applies to the :meth:`~flask.views.View.dispatch_request`
method in views that inherit from the :class:`flask.views.View` class, as
well as all the HTTP method handlers in views that inherit from the
:class:`flask.views.MethodView` class.
.. admonition:: Using ``async`` on Windows on Python 3.8
Python 3.8 has a bug related to asyncio on Windows. If you encounter
something like ``ValueError: set_wakeup_fd only works in main thread``,
please upgrade to Python 3.9.
Performance
-----------
@ -51,7 +64,7 @@ example via ``asyncio.create_task``.
If you wish to use background tasks it is best to use a task queue to
trigger background work, rather than spawn tasks in a view
function. With that in mind you can spawn asyncio tasks by serving
Flask with a ASGI server and utilising the asgiref WsgiToAsgi adapter
Flask with an ASGI server and utilising the asgiref WsgiToAsgi adapter
as described in :ref:`asgi`. This works as the adapter creates an
event loop that runs continually.
@ -64,7 +77,7 @@ to the way it is implemented. If you have a mainly async codebase it
would make sense to consider `Quart`_. Quart is a reimplementation of
Flask based on the `ASGI`_ standard instead of WSGI. This allows it to
handle many concurrent requests, long running requests, and websockets
without requiring individual worker processes or threads.
without requiring multiple worker processes or threads.
It has also already been possible to run Flask with Gevent or Eventlet
to get many of the benefits of async request handling. These libraries
@ -80,12 +93,27 @@ to understanding the specific needs of your project.
Extensions
----------
Existing Flask extensions only expect views to be synchronous. If they
provide decorators to add functionality to views, those will probably
Flask extensions predating Flask's async support do not expect async views.
If they provide decorators to add functionality to views, those will probably
not work with async views because they will not await the function or be
awaitable. Other functions they provide will not be awaitable either and
will probably be blocking if called within an async view.
Extension authors can support async functions by utilising the
:meth:`flask.Flask.ensure_sync` method. For example, if the extension
provides a view function decorator add ``ensure_sync`` before calling
the decorated function,
.. code-block:: python
def extension(func):
@wraps(func)
def wrapper(*args, **kwargs):
... # Extension logic
return current_app.ensure_sync(func)(*args, **kwargs)
return wrapper
Check the changelog of the extension you want to use to see if they've
implemented async support, or make a feature request or PR to them.

View file

@ -127,8 +127,8 @@ It is possible to register a blueprint on another blueprint.
.. code-block:: python
parent = Blueprint("parent", __name__, url_prefix="/parent")
child = Blueprint("child", __name__, url_prefix="/child)
parent = Blueprint('parent', __name__, url_prefix='/parent')
child = Blueprint('child', __name__, url_prefix='/child')
parent.register_blueprint(child)
app.register_blueprint(parent)

View file

@ -45,13 +45,13 @@ While ``FLASK_APP`` supports a variety of options for specifying your
application, most use cases should be simple. Here are the typical values:
(nothing)
The file :file:`wsgi.py` is imported, automatically detecting an app
(``app``). This provides an easy way to create an app from a factory with
extra arguments.
The name "app" or "wsgi" is imported (as a ".py" file, or package),
automatically detecting an app (``app`` or ``application``) or
factory (``create_app`` or ``make_app``).
``FLASK_APP=hello``
The name is imported, automatically detecting an app (``app``) or factory
(``create_app``).
The given name is imported, automatically detecting an app (``app``
or ``application``) or factory (``create_app`` or ``make_app``).
----

View file

@ -20,6 +20,7 @@ extensions = [
"sphinx_issues",
"sphinx_tabs.tabs",
]
autodoc_typehints = "description"
intersphinx_mapping = {
"python": ("https://docs.python.org/3/", None),
"werkzeug": ("https://werkzeug.palletsprojects.com/", None),
@ -48,10 +49,10 @@ html_context = {
]
}
html_sidebars = {
"index": ["project.html", "localtoc.html", "searchbox.html"],
"**": ["localtoc.html", "relations.html", "searchbox.html"],
"index": ["project.html", "localtoc.html", "searchbox.html", "ethicalads.html"],
"**": ["localtoc.html", "relations.html", "searchbox.html", "ethicalads.html"],
}
singlehtml_sidebars = {"index": ["project.html", "localtoc.html"]}
singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]}
html_static_path = ["_static"]
html_favicon = "_static/flask-icon.png"
html_logo = "_static/flask-icon.png"
@ -77,7 +78,7 @@ def github_link(name, rawtext, text, lineno, inliner, options=None, content=None
words = None
if packaging.version.parse(release).is_devrelease:
url = f"{base_url}master/{text}"
url = f"{base_url}main/{text}"
else:
url = f"{base_url}{release}/{text}"

View file

@ -16,6 +16,7 @@ Hosted options
- `Deploying Flask on Heroku <https://devcenter.heroku.com/articles/getting-started-with-python>`_
- `Deploying Flask on Google App Engine <https://cloud.google.com/appengine/docs/standard/python3/runtime>`_
- `Deploying Flask on Google Cloud Run <https://cloud.google.com/run/docs/quickstarts/build-and-deploy/python>`_
- `Deploying Flask on AWS Elastic Beanstalk <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-flask.html>`_
- `Deploying on Azure (IIS) <https://docs.microsoft.com/en-us/azure/app-service/containers/how-to-configure-python>`_
- `Deploying on PythonAnywhere <https://help.pythonanywhere.com/pages/Flask/>`_

View file

@ -8,6 +8,8 @@ Python Version
We recommend using the latest version of Python. Flask supports Python
3.6 and newer.
``async`` support in Flask requires Python 3.7+ for ``contextvars.ContextVar``.
Dependencies
------------

View file

@ -64,7 +64,7 @@ An example task
Let's write a task that adds two numbers together and returns the result. We
configure Celery's broker and backend to use Redis, create a ``celery``
application using the factor from above, and then use it to define the task. ::
application using the factory from above, and then use it to define the task. ::
from flask import Flask

View file

@ -142,7 +142,7 @@ Here is the code for that decorator::
def decorated_function(*args, **kwargs):
template_name = template
if template_name is None:
template_name = f"'{request.endpoint.replace('.', '/')}.html'"
template_name = f"{request.endpoint.replace('.', '/')}.html"
ctx = f(*args, **kwargs)
if ctx is None:
ctx = {}

View file

@ -50,7 +50,7 @@ to tell your terminal the application to work with by exporting the
.. code-block:: text
$ export FLASK_APP=hello.py
$ export FLASK_APP=hello
$ flask run
* Running on http://127.0.0.1:5000/
@ -58,7 +58,7 @@ to tell your terminal the application to work with by exporting the
.. code-block:: text
> set FLASK_APP=hello.py
> set FLASK_APP=hello
> flask run
* Running on http://127.0.0.1:5000/
@ -66,10 +66,16 @@ to tell your terminal the application to work with by exporting the
.. code-block:: text
> $env:FLASK_APP = "hello.py"
> $env:FLASK_APP = "hello"
> flask run
* Running on http://127.0.0.1:5000/
.. admonition:: Application Discovery Behavior
As a shortcut, if the file is named ``app.py`` or ``wsgi.py``, you
don't have to set the ``FLASK_APP`` environment variable. See
:doc:`/cli` for more details.
This launches a very simple builtin server, which is good enough for
testing but probably not what you want to use in production. For
deployment options see :doc:`deploying/index`.
@ -240,7 +246,7 @@ of the argument like ``<converter:variable_name>``. ::
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return f'User {username}'
return f'User {escape(username)}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
@ -250,7 +256,7 @@ of the argument like ``<converter:variable_name>``. ::
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# show the subpath after /path/
return f'Subpath {subpath}'
return f'Subpath {escape(subpath)}'
Converter types:
@ -438,9 +444,9 @@ Here is an example template:
<h1>Hello, World!</h1>
{% endif %}
Inside templates you also have access to the :class:`~flask.request`,
:class:`~flask.session` and :class:`~flask.g` [#]_ objects
as well as the :func:`~flask.get_flashed_messages` function.
Inside templates you also have access to the :data:`~flask.Flask.config`,
:class:`~flask.request`, :class:`~flask.session` and :class:`~flask.g` [#]_ objects
as well as the :func:`~flask.url_for` and :func:`~flask.get_flashed_messages` functions.
Templates are especially useful if inheritance is used. If you want to
know how that works, see :doc:`patterns/templateinheritance`. Basically

View file

@ -37,7 +37,7 @@ by default:
.. data:: config
:noindex:
The current configuration object (:data:`flask.config`)
The current configuration object (:data:`flask.Flask.config`)
.. versionadded:: 0.6

View file

@ -48,20 +48,21 @@ the application for testing and initializes a new database::
import pytest
from flaskr import create_app
from flaskr.db import init_db
@pytest.fixture
def client():
db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
flaskr.app.config['TESTING'] = True
db_fd, db_path = tempfile.mkstemp()
app = create_app({'TESTING': True, 'DATABASE': db_path})
with flaskr.app.test_client() as client:
with flaskr.app.app_context():
flaskr.init_db()
with app.test_client() as client:
with app.app_context():
init_db()
yield client
os.close(db_fd)
os.unlink(flaskr.app.config['DATABASE'])
os.unlink(db_path)
This client fixture will be called by each individual test. It gives us a
simple interface to the application, where we can trigger test requests to the
@ -224,13 +225,13 @@ temporarily. With this you can access the :class:`~flask.request`,
:class:`~flask.g` and :class:`~flask.session` objects like in view
functions. Here is a full example that demonstrates this approach::
import flask
from flask import Flask, request
app = flask.Flask(__name__)
app = Flask(__name__)
with app.test_request_context('/?name=Peter'):
assert flask.request.path == '/'
assert flask.request.args['name'] == 'Peter'
assert request.path == '/'
assert request.args['name'] == 'Peter'
All the other objects that are context bound can be used in the same
way.
@ -247,7 +248,7 @@ the test request context leaves the ``with`` block. If you do want the
:meth:`~flask.Flask.before_request` functions to be called as well, you
need to call :meth:`~flask.Flask.preprocess_request` yourself::
app = flask.Flask(__name__)
app = Flask(__name__)
with app.test_request_context('/?name=Peter'):
app.preprocess_request()
@ -260,7 +261,7 @@ If you want to call the :meth:`~flask.Flask.after_request` functions you
need to call into :meth:`~flask.Flask.process_response` which however
requires that you pass it a response object::
app = flask.Flask(__name__)
app = Flask(__name__)
with app.test_request_context('/?name=Peter'):
resp = Response('...')
@ -329,7 +330,7 @@ context around for a little longer so that additional introspection can
happen. With Flask 0.4 this is possible by using the
:meth:`~flask.Flask.test_client` with a ``with`` block::
app = flask.Flask(__name__)
app = Flask(__name__)
with app.test_client() as c:
rv = c.get('/?tequila=42')
@ -353,7 +354,7 @@ keep the context around and access :data:`flask.session`::
with app.test_client() as c:
rv = c.get('/')
assert flask.session['foo'] == 42
assert session['foo'] == 42
This however does not make it possible to also modify the session or to
access the session before a request was fired. Starting with Flask 0.8 we

View file

@ -55,7 +55,7 @@ this structure and take full advantage of Flask's flexibility.
.. image:: flaskr_edit.png
:align: center
:class: screenshot
:alt: screenshot of login page
:alt: screenshot of edit page
:gh:`The tutorial project is available as an example in the Flask
repository <examples/tutorial>`, if you want to compare your project

View file

@ -113,8 +113,8 @@ Method Based Dispatching
For RESTful APIs it's especially helpful to execute a different function
for each HTTP method. With the :class:`flask.views.MethodView` you can
easily do that. Each HTTP method maps to a function with the same name
(just in lowercase)::
easily do that. Each HTTP method maps to a method of the class with the
same name (just in lowercase)::
from flask.views import MethodView