diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 86e010df..b0251c75 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,8 +1,19 @@
version: 2
updates:
-- package-ecosystem: pip
+- package-ecosystem: "pip"
+ directory: "/requirements"
+ target-branch: "2.0.x"
+ versioning-strategy: "lockfile-only"
+ schedule:
+ interval: "monthly"
+ day: "monday"
+ time: "16:00"
+ timezone: "UTC"
+ open-pull-requests-limit: 99
+- package-ecosystem: "github-actions"
directory: "/"
schedule:
- interval: monthly
- time: "08:00"
- open-pull-requests-limit: 99
+ interval: "monthly"
+ day: "monday"
+ time: "16:00"
+ timezone: "UTC"
diff --git a/.github/workflows/lock.yaml b/.github/workflows/lock.yaml
index 7128f382..b4f76338 100644
--- a/.github/workflows/lock.yaml
+++ b/.github/workflows/lock.yaml
@@ -8,8 +8,8 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- - uses: dessant/lock-threads@v2
+ - uses: dessant/lock-threads@v3
with:
github-token: ${{ github.token }}
- issue-lock-inactive-days: 14
- pr-lock-inactive-days: 14
+ issue-inactive-days: 14
+ pr-inactive-days: 14
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 06338f6b..b121dd8e 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -24,14 +24,17 @@ jobs:
fail-fast: false
matrix:
include:
- - {name: Linux, python: '3.9', os: ubuntu-latest, tox: py39}
- - {name: Windows, python: '3.9', os: windows-latest, tox: py39}
- - {name: Mac, python: '3.9', os: macos-latest, tox: py39}
+ - {name: Linux, python: '3.10', os: ubuntu-latest, tox: py310}
+ - {name: Windows, python: '3.10', os: windows-latest, tox: py310}
+ - {name: Mac, python: '3.10', os: macos-latest, tox: py310}
+ - {name: '3.11-dev', python: '3.11-dev', os: ubuntu-latest, tox: py311}
+ - {name: '3.9', python: '3.9', os: ubuntu-latest, tox: py39}
- {name: '3.8', python: '3.8', os: ubuntu-latest, tox: py38}
- {name: '3.7', python: '3.7', os: ubuntu-latest, tox: py37}
- - {name: '3.6', python: '3.6', os: ubuntu-latest, tox: py36}
- - {name: 'PyPy', python: pypy3, os: ubuntu-latest, tox: pypy3}
- - {name: Typing, python: '3.9', os: ubuntu-latest, tox: typing}
+ - {name: 'PyPy', python: 'pypy-3.7', os: ubuntu-latest, tox: pypy37}
+ - {name: 'Pallets Minimum Versions', python: '3.10', os: ubuntu-latest, tox: py-min}
+ - {name: 'Pallets Development Versions', python: '3.7', os: ubuntu-latest, tox: py-dev}
+ - {name: Typing, python: '3.10', os: ubuntu-latest, tox: typing}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index d75f3c31..a039d330 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,31 +1,32 @@
ci:
+ autoupdate_branch: "2.0.x"
autoupdate_schedule: monthly
repos:
- repo: https://github.com/asottile/pyupgrade
- rev: v2.15.0
+ rev: v2.29.1
hooks:
- id: pyupgrade
args: ["--py36-plus"]
- repo: https://github.com/asottile/reorder_python_imports
- rev: v2.5.0
+ rev: v2.6.0
hooks:
- id: reorder-python-imports
name: Reorder Python imports (src, tests)
files: "^(?!examples/)"
args: ["--application-directories", "src"]
- repo: https://github.com/psf/black
- rev: 21.5b1
+ rev: 21.12b0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
- rev: 3.9.2
+ rev: 4.0.1
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- flake8-implicit-str-concat
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v3.4.0
+ rev: v4.0.1
hooks:
- id: fix-byte-order-marker
- id: trailing-whitespace
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index 0c363636..346900b2 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -1,4 +1,8 @@
version: 2
+build:
+ os: ubuntu-20.04
+ tools:
+ python: "3.10"
python:
install:
- requirements: requirements/docs.txt
diff --git a/CHANGES.rst b/CHANGES.rst
index f4e0b5d0..a57a97d2 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,19 +5,79 @@ Version 2.1.0
Unreleased
-- Update Click dependency to >= 8.0.
+- Drop support for Python 3.6. :pr:`4335`
+- Update Click dependency to >= 8.0. :pr:`4008`
+- Remove previously deprecated code. :pr:`4337`
+
+ - The CLI does not pass ``script_info`` to app factory functions.
+ - ``config.from_json`` is replaced by
+ ``config.from_file(name, load=json.load)``.
+ - ``json`` functions no longer take an ``encoding`` parameter.
+ - ``safe_join`` is removed, use ``werkzeug.utils.safe_join``
+ instead.
+ - ``total_seconds`` is removed, use ``timedelta.total_seconds``
+ instead.
+ - The same blueprint cannot be registered with the same name. Use
+ ``name=`` when registering to specify a unique name.
+
+- Some parameters in ``send_file`` and ``send_from_directory`` were
+ renamed in 2.0. The deprecation period for the old names is extended
+ to 2.2. Be sure to test with deprecation warnings visible.
+
+ - ``attachment_filename`` is renamed to ``download_name``.
+ - ``cache_timeout`` is renamed to ``max_age``.
+ - ``add_etags`` is renamed to ``etag``.
+ - ``filename`` is renamed to ``path``.
+
+- The ``RequestContext.g`` property is deprecated. Use ``g`` directly
+ or ``AppContext.g`` instead. :issue:`3898`
+- ``copy_current_request_context`` can decorate async functions.
+ :pr:`4303`
+
+
+Version 2.0.3
+-------------
+
+Unreleased
+
+- The test client's ``as_tuple`` parameter is deprecated and will be
+ removed in Werkzeug 2.1. It is now also deprecated in Flask, to be
+ removed in Flask 2.1, while remaining compatible with both in
+ 2.0.x. Use ``response.request.environ`` instead. :pr:`4341`
+- Fix type annotation for ``errorhandler`` decorator. :issue:`4295`
+- Revert a change to the CLI that caused it to hide ``ImportError``
+ tracebacks when importing the application. :issue:`4307`
+- ``app.json_encoder`` and ``json_decoder`` are only passed to
+ ``dumps`` and ``loads`` if they have custom behavior. This improves
+ performance, mainly on PyPy. :issue:`4349`
+- Clearer error message when ``after_this_request`` is used outside a
+ request context. :issue:`4333`
Version 2.0.2
-------------
-Unreleased
+Released 2021-10-04
-- Fix type annotation for ``teardown_request``. :issue:`4093`
+- Fix type annotation for ``teardown_*`` methods. :issue:`4093`
- Fix type annotation for ``before_request`` and ``before_app_request``
decorators. :issue:`4104`
- Fixed the issue where typing requires template global
decorators to accept functions with no arguments. :issue:`4098`
+- Support View and MethodView instances with async handlers. :issue:`4112`
+- Enhance typing of ``app.errorhandler`` decorator. :issue:`4095`
+- Fix registering a blueprint twice with differing names. :issue:`4124`
+- Fix the type of ``static_folder`` to accept ``pathlib.Path``.
+ :issue:`4150`
+- ``jsonify`` handles ``decimal.Decimal`` by encoding to ``str``.
+ :issue:`4157`
+- Correctly handle raising deferred errors in CLI lazy loading.
+ :issue:`4096`
+- The CLI loader handles ``**kwargs`` in a ``create_app`` function.
+ :issue:`4170`
+- Fix the order of ``before_request`` and other callbacks that trigger
+ before the view returns. They are called from the app down to the
+ closest nested blueprint. :issue:`4229`
Version 2.0.1
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 3a9177a4..a3c8b851 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -12,14 +12,16 @@ to address bugs and feature requests in Flask itself. Use one of the
following resources for questions about using Flask or issues with your
own code:
-- The ``#get-help`` channel on our Discord chat:
+- The ``#questions`` channel on our Discord chat:
https://discord.gg/pallets
- The mailing list flask@python.org for long term discussion or larger
issues.
- Ask on `Stack Overflow`_. Search with Google first using:
``site:stackoverflow.com flask {search term, exception message, etc.}``
+- Ask on our `GitHub Discussions`_.
.. _Stack Overflow: https://stackoverflow.com/questions/tagged/flask?tab=Frequent
+.. _GitHub Discussions: https://github.com/pallets/flask/discussions
Reporting issues
@@ -92,7 +94,7 @@ First time setup
.. code-block:: text
- git remote add fork https://github.com/{username}/flask
+ $ git remote add fork https://github.com/{username}/flask
- Create a virtualenv.
diff --git a/README.rst b/README.rst
index e389c6d6..b4f802f6 100644
--- a/README.rst
+++ b/README.rst
@@ -26,7 +26,7 @@ Install and update using `pip`_:
$ pip install -U Flask
-.. _pip: https://pip.pypa.io/en/stable/quickstart/
+.. _pip: https://pip.pypa.io/en/stable/getting-started/
A Simple Example
diff --git a/artwork/LICENSE.rst b/artwork/LICENSE.rst
index 605e41cb..99c58a21 100644
--- a/artwork/LICENSE.rst
+++ b/artwork/LICENSE.rst
@@ -10,7 +10,7 @@ following conditions are met:
1. Redistributions of source code must retain the above copyright
notice and this list of conditions.
-3. Neither the name of the copyright holder nor the names of its
+2. 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.
diff --git a/docs/api.rst b/docs/api.rst
index e6862878..5eb8b693 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -218,8 +218,6 @@ Useful Functions and Classes
.. autofunction:: send_from_directory
-.. autofunction:: safe_join
-
.. autofunction:: escape
.. autoclass:: Markup
@@ -256,7 +254,7 @@ the filter to render data inside ``
diff --git a/docs/appcontext.rst b/docs/appcontext.rst
index 68176494..b214f254 100644
--- a/docs/appcontext.rst
+++ b/docs/appcontext.rst
@@ -8,7 +8,7 @@ a request, CLI command, or other activity. Rather than passing the
application around to each function, the :data:`current_app` and
:data:`g` proxies are accessed instead.
-This is similar to the :doc:`/reqcontext`, which keeps track of
+This is similar to :doc:`/reqcontext`, which keeps track of
request-level data during a request. A corresponding application context
is pushed when a request context is pushed.
diff --git a/docs/async-await.rst b/docs/async-await.rst
index 34751d47..4c70f961 100644
--- a/docs/async-await.rst
+++ b/docs/async-await.rst
@@ -17,12 +17,24 @@ 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.
+.. admonition:: Using ``async`` with greenlet
+
+ When using gevent or eventlet to serve an application or patch the
+ runtime, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
+ required.
+
Performance
-----------
diff --git a/docs/cli.rst b/docs/cli.rst
index 6036cb2d..d32dd7be 100644
--- a/docs/cli.rst
+++ b/docs/cli.rst
@@ -103,6 +103,11 @@ replaces the :meth:`Flask.run` method in most cases. ::
is provided for convenience, but is not designed to be particularly secure,
stable, or efficient. See :doc:`/deploying/index` for how to run in production.
+If another program is already using port 5000, you'll see
+``OSError: [Errno 98]`` or ``OSError: [WinError 10013]`` when the
+server tries to start. See :ref:`address-already-in-use` for how to
+handle that.
+
Open a Shell
------------
@@ -112,10 +117,9 @@ shell with the :func:`shell ` command. An application
context will be active, and the app instance will be imported. ::
$ flask shell
- Python 3.6.2 (default, Jul 20 2017, 03:52:27)
- [GCC 7.1.1 20170630] on linux
- App: example
- Instance: /home/user/Projects/hello/instance
+ Python 3.10.0 (default, Oct 27 2021, 06:59:51) [GCC 11.1.0] on linux
+ App: example [production]
+ Instance: /home/david/Projects/pallets/flask/instance
>>>
Use :meth:`~Flask.shell_context_processor` to add other automatic imports.
diff --git a/docs/config.rst b/docs/config.rst
index 768cf60d..ad737109 100644
--- a/docs/config.rst
+++ b/docs/config.rst
@@ -38,7 +38,7 @@ method::
app.config.update(
TESTING=True,
- SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/'
+ SECRET_KEY='192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
)
@@ -180,8 +180,8 @@ The following configuration values are used internally by Flask:
application. It should be a long random ``bytes`` or ``str``. For
example, copy the output of this to your config::
- $ python -c 'import os; print(os.urandom(16))'
- b'_5#y2L"F4Q8z\n\xec]/'
+ $ python -c 'import secrets; print(secrets.token_hex())'
+ '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
**Do not reveal the secret key when posting questions or committing code.**
@@ -468,7 +468,7 @@ sure to use uppercase letters for your config keys.
Here is an example of a configuration file::
# Example configuration
- SECRET_KEY = b'_5#y2L"F4Q8z\n\xec]/'
+ SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
Make sure to load the configuration very early on, so that extensions have
the ability to access the configuration when starting up. There are other
diff --git a/docs/debugging.rst b/docs/debugging.rst
index a9f984b4..66118de2 100644
--- a/docs/debugging.rst
+++ b/docs/debugging.rst
@@ -69,7 +69,7 @@ enables the debugger and reloader.
``FLASK_ENV`` can only be set as an environment variable. When running
from Python code, passing ``debug=True`` enables debug mode, which is
-mostly equivalent. Debug mode can be controled separately from
+mostly equivalent. Debug mode can be controlled separately from
``FLASK_ENV`` with the ``FLASK_DEBUG`` environment variable as well.
.. code-block:: python
diff --git a/docs/deploying/asgi.rst b/docs/deploying/asgi.rst
index c7e04027..39cd76b7 100644
--- a/docs/deploying/asgi.rst
+++ b/docs/deploying/asgi.rst
@@ -5,7 +5,7 @@ ASGI
If you'd like to use an ASGI server you will need to utilise WSGI to
ASGI middleware. The asgiref
-[WsgiToAsgi](https://github.com/django/asgiref#wsgi-to-asgi-adapter)
+`WsgiToAsgi `_
adapter is recommended as it integrates with the event loop used for
Flask's :ref:`async_await` support. You can use the adapter by
wrapping the Flask app,
@@ -21,7 +21,7 @@ wrapping the Flask app,
asgi_app = WsgiToAsgi(app)
-and then serving the ``asgi_app`` with the asgi server, e.g. using
+and then serving the ``asgi_app`` with the ASGI server, e.g. using
`Hypercorn `_,
.. sourcecode:: text
diff --git a/docs/deploying/fastcgi.rst b/docs/deploying/fastcgi.rst
index ef2201c8..d3614d37 100644
--- a/docs/deploying/fastcgi.rst
+++ b/docs/deploying/fastcgi.rst
@@ -234,5 +234,5 @@ python path. Common problems are:
.. _nginx: https://nginx.org/
.. _lighttpd: https://www.lighttpd.net/
-.. _cherokee: http://cherokee-project.com/
+.. _cherokee: https://cherokee-project.com/
.. _flup: https://pypi.org/project/flup/
diff --git a/docs/deploying/uwsgi.rst b/docs/deploying/uwsgi.rst
index 22930d7b..b6958dc0 100644
--- a/docs/deploying/uwsgi.rst
+++ b/docs/deploying/uwsgi.rst
@@ -37,7 +37,7 @@ If your application is accessible at root level, you can use a
single ``/`` instead of ``/yourapplication``. ``myapp`` refers to the name of
the file of your flask application (without extension) or the module which
provides ``app``. ``app`` is the callable inside of your application (usually
-the line reads ``app = Flask(__name__)``.
+the line reads ``app = Flask(__name__)``).
If you want to deploy your flask application inside of a virtual environment,
you need to also add ``--virtualenv /path/to/virtual/environment``. You might
@@ -67,5 +67,5 @@ to have it in the URL root its a bit simpler::
.. _nginx: https://nginx.org/
.. _lighttpd: https://www.lighttpd.net/
-.. _cherokee: http://cherokee-project.com/
+.. _cherokee: https://cherokee-project.com/
.. _uwsgi: https://uwsgi-docs.readthedocs.io/en/latest/
diff --git a/docs/deploying/wsgi-standalone.rst b/docs/deploying/wsgi-standalone.rst
index 1339a625..823426ac 100644
--- a/docs/deploying/wsgi-standalone.rst
+++ b/docs/deploying/wsgi-standalone.rst
@@ -1,67 +1,171 @@
-Standalone WSGI Containers
-==========================
+Standalone WSGI Servers
+=======================
+
+Most WSGI servers also provide HTTP servers, so they can run a WSGI
+application and make it available externally.
+
+It may still be a good idea to run the server behind a dedicated HTTP
+server such as Apache or Nginx. See :ref:`deploying-proxy-setups` if you
+run into issues with that.
-There are popular servers written in Python that contain WSGI applications and
-serve HTTP. These servers stand alone when they run; you can proxy to them
-from your web server. Note the section on :ref:`deploying-proxy-setups` if you
-run into issues.
Gunicorn
--------
-`Gunicorn`_ 'Green Unicorn' is a WSGI HTTP Server for UNIX. It's a pre-fork
-worker model ported from Ruby's Unicorn project. It supports both `eventlet`_
-and `greenlet`_. Running a Flask application on this server is quite simple::
+`Gunicorn`_ is a WSGI and HTTP server for UNIX. To run a Flask
+application, tell Gunicorn how to import your Flask app object.
- $ gunicorn myproject:app
+.. code-block:: text
-`Gunicorn`_ provides many command-line options -- see ``gunicorn -h``.
-For example, to run a Flask application with 4 worker processes (``-w
-4``) binding to localhost port 4000 (``-b 127.0.0.1:4000``)::
+ $ gunicorn -w 4 -b 0.0.0.0:5000 your_project:app
- $ gunicorn -w 4 -b 127.0.0.1:4000 myproject:app
+The ``-w 4`` option uses 4 workers to handle 4 requests at once. The
+``-b 0.0.0.0:5000`` serves the application on all interfaces on port
+5000.
-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 provides many options for configuring the server, either
+through a configuration file or with command line options. Use
+``gunicorn --help`` or see the docs for more information.
+
+The command expects the name of your module or package to import and
+the application instance within the module. If you use the application
+factory pattern, you can pass a call to that.
+
+.. code-block:: text
+
+ $ gunicorn -w 4 -b 0.0.0.0:5000 "myproject:create_app()"
+
+
+Async with Gevent or Eventlet
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The default sync worker is appropriate for many use cases. If you need
+asynchronous support, Gunicorn provides workers using either `gevent`_
+or `eventlet`_. This is not the same as Python's ``async/await``, or the
+ASGI server spec.
+
+When using either gevent or eventlet, greenlet>=1.0 is required,
+otherwise context locals such as ``request`` will not work as expected.
+When using PyPy, PyPy>=7.3.7 is required.
+
+To use gevent:
+
+.. code-block:: text
+
+ $ gunicorn -k gevent -b 0.0.0.0:5000 your_project:app
+
+To use eventlet:
+
+.. code-block:: text
+
+ $ gunicorn -k eventlet -b 0.0.0.0:5000 your_project:app
- $ gunicorn "myproject:create_app()"
.. _Gunicorn: https://gunicorn.org/
+.. _gevent: http://www.gevent.org/
.. _eventlet: https://eventlet.net/
+.. _greenlet: https://greenlet.readthedocs.io/en/latest/
uWSGI
---------
+-----
-`uWSGI`_ is a fast application server written in C. It is very configurable
-which makes it more complicated to setup than gunicorn.
+`uWSGI`_ is a fast application server written in C. It is very
+configurable, which makes it more complicated to setup than Gunicorn.
+It also provides many other utilities for writing robust web
+applications. To run a Flask application, tell Gunicorn how to import
+your Flask app object.
-Running `uWSGI HTTP Router`_::
+.. code-block:: text
- $ uwsgi --http 127.0.0.1:5000 --module myproject:app
+ $ uwsgi --master -p 4 --http 0.0.0.0:5000 -w your_project:app
-For a more optimized setup, see :doc:`configuring uWSGI and NGINX `.
+The ``-p 4`` option uses 4 workers to handle 4 requests at once. The
+``--http 0.0.0.0:5000`` serves the application on all interfaces on port
+5000.
+
+uWSGI has optimized integration with Nginx and Apache instead of using
+a standard HTTP proxy. See :doc:`configuring uWSGI and Nginx `.
+
+
+Async with Gevent
+~~~~~~~~~~~~~~~~~
+
+The default sync worker is appropriate for many use cases. If you need
+asynchronous support, uWSGI provides workers using `gevent`_. It also
+supports other async modes, see the docs for more information. This is
+not the same as Python's ``async/await``, or the ASGI server spec.
+
+When using gevent, greenlet>=1.0 is required, otherwise context locals
+such as ``request`` will not work as expected. When using PyPy,
+PyPy>=7.3.7 is required.
+
+.. code-block:: text
+
+ $ uwsgi --master --gevent 100 --http 0.0.0.0:5000 -w your_project:app
.. _uWSGI: https://uwsgi-docs.readthedocs.io/en/latest/
-.. _uWSGI HTTP Router: https://uwsgi-docs.readthedocs.io/en/latest/HTTP.html#the-uwsgi-http-https-router
+
Gevent
--------
+------
-`Gevent`_ is a coroutine-based Python networking library that uses
-`greenlet`_ to provide a high-level synchronous API on top of `libev`_
-event loop::
+Prefer using `Gunicorn`_ with Gevent workers rather than using Gevent
+directly. Gunicorn provides a much more configurable and
+production-tested server. See the section on Gunicorn above.
+
+`Gevent`_ allows writing asynchronous, coroutine-based code that looks
+like standard synchronous Python. It uses `greenlet`_ to enable task
+switching without writing ``async/await`` or using ``asyncio``.
+
+It provides a WSGI server that can handle many connections at once
+instead of one per worker process.
+
+`Eventlet`_, described below, is another library that does the same
+thing. Certain dependencies you have, or other consideration, may affect
+which of the two you choose to use
+
+To use gevent to serve your application, import its ``WSGIServer`` and
+use it to run your ``app``.
+
+.. code-block:: python
from gevent.pywsgi import WSGIServer
- from yourapplication import app
+ from your_project import app
- http_server = WSGIServer(('', 5000), app)
+ http_server = WSGIServer(("", 5000), app)
http_server.serve_forever()
-.. _Gevent: http://www.gevent.org/
-.. _greenlet: https://greenlet.readthedocs.io/en/latest/
-.. _libev: http://software.schmorp.de/pkg/libev.html
+
+Eventlet
+--------
+
+Prefer using `Gunicorn`_ with Eventlet workers rather than using
+Eventlet directly. Gunicorn provides a much more configurable and
+production-tested server. See the section on Gunicorn above.
+
+`Eventlet`_ allows writing asynchronous, coroutine-based code that looks
+like standard synchronous Python. It uses `greenlet`_ to enable task
+switching without writing ``async/await`` or using ``asyncio``.
+
+It provides a WSGI server that can handle many connections at once
+instead of one per worker process.
+
+`Gevent`_, described above, is another library that does the same
+thing. Certain dependencies you have, or other consideration, may affect
+which of the two you choose to use
+
+To use eventlet to serve your application, import its ``wsgi.server``
+and use it to run your ``app``.
+
+.. code-block:: python
+
+ import eventlet
+ from eventlet import wsgi
+ from your_project import app
+
+ wsgi.server(eventlet.listen(("", 5000), app)
+
Twisted Web
-----------
@@ -69,7 +173,9 @@ Twisted Web
`Twisted Web`_ is the web server shipped with `Twisted`_, a mature,
non-blocking event-driven networking library. Twisted Web comes with a
standard WSGI container which can be controlled from the command line using
-the ``twistd`` utility::
+the ``twistd`` utility:
+
+.. code-block:: text
$ twistd web --wsgi myproject.app
@@ -79,13 +185,16 @@ This example will run a Flask application called ``app`` from a module named
Twisted Web supports many flags and options, and the ``twistd`` utility does
as well; see ``twistd -h`` and ``twistd web -h`` for more information. For
example, to run a Twisted Web server in the foreground, on port 8080, with an
-application from ``myproject``::
+application from ``myproject``:
+
+.. code-block:: text
$ twistd -n web --port tcp:8080 --wsgi myproject.app
.. _Twisted: https://twistedmatrix.com/trac/
.. _Twisted Web: https://twistedmatrix.com/trac/wiki/TwistedWeb
+
.. _deploying-proxy-setups:
Proxy Setups
diff --git a/docs/extensiondev.rst b/docs/extensiondev.rst
index 18b4fa7d..dbaf62cb 100644
--- a/docs/extensiondev.rst
+++ b/docs/extensiondev.rst
@@ -322,9 +322,9 @@ ecosystem remain consistent and compatible.
`Official Pallets Themes`_. A link to the documentation or project
website must be in the PyPI metadata or the readme.
7. For maximum compatibility, the extension should support the same
- versions of Python that Flask supports. 3.6+ is recommended as of
- 2020. Use ``python_requires=">= 3.6"`` in ``setup.py`` to indicate
- supported versions.
+ versions of Python that Flask supports. 3.7+ is recommended as of
+ December 2021. Use ``python_requires=">= 3.7"`` in ``setup.py`` to
+ indicate supported versions.
.. _PyPI: https://pypi.org/search/?c=Framework+%3A%3A+Flask
.. _mailinglist: https://mail.python.org/mailman/listinfo/flask
diff --git a/docs/installation.rst b/docs/installation.rst
index aef7df0c..8a338e18 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -6,7 +6,7 @@ Python Version
--------------
We recommend using the latest version of Python. Flask supports Python
-3.6 and newer.
+3.7 and newer.
Dependencies
@@ -49,6 +49,18 @@ use them if you install them.
.. _watchdog: https://pythonhosted.org/watchdog/
+greenlet
+~~~~~~~~
+
+You may choose to use gevent or eventlet with your application. In this
+case, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
+required.
+
+These are not minimum supported versions, they only indicate the first
+versions that added necessary features. You should use the latest
+versions of each.
+
+
Virtual environments
--------------------
diff --git a/docs/patterns/celery.rst b/docs/patterns/celery.rst
index e1f6847e..38a9a025 100644
--- a/docs/patterns/celery.rst
+++ b/docs/patterns/celery.rst
@@ -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
diff --git a/docs/patterns/fileuploads.rst b/docs/patterns/fileuploads.rst
index f24a43ca..304f57dc 100644
--- a/docs/patterns/fileuploads.rst
+++ b/docs/patterns/fileuploads.rst
@@ -175,9 +175,8 @@ are JavaScript libraries like jQuery_ that have form plugins to ease the
construction of progress bar.
Because the common pattern for file uploads exists almost unchanged in all
-applications dealing with uploads, there is also a Flask extension called
-`Flask-Uploads`_ that implements a full fledged upload mechanism that
-allows controlling which file extensions are allowed to be uploaded.
+applications dealing with uploads, there are also some Flask extensions that
+implement a full fledged upload mechanism that allows controlling which
+file extensions are allowed to be uploaded.
.. _jQuery: https://jquery.com/
-.. _Flask-Uploads: https://flask-uploads.readthedocs.io/en/latest/
diff --git a/docs/patterns/jquery.rst b/docs/patterns/jquery.rst
index fafbdf18..0a75bb71 100644
--- a/docs/patterns/jquery.rst
+++ b/docs/patterns/jquery.rst
@@ -23,8 +23,7 @@ to add a script statement to the bottom of your ```` to load jQuery:
.. sourcecode:: html
-
+
Another method is using Google's `AJAX Libraries API
`_ to load jQuery:
@@ -59,7 +58,7 @@ like this:
.. sourcecode:: html+jinja
-
@@ -109,7 +108,7 @@ usually a better idea to have that in a separate script file:
.. sourcecode:: html
-