Merge branch 'main' into pr/emisargent/4969
This commit is contained in:
commit
58c52e84cd
38 changed files with 282 additions and 1063 deletions
2
.github/workflows/publish.yaml
vendored
2
.github/workflows/publish.yaml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
||||||
id-token: write
|
id-token: write
|
||||||
contents: write
|
contents: write
|
||||||
# Can't pin with hash due to how this workflow works.
|
# Can't pin with hash due to how this workflow works.
|
||||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0
|
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.5.0
|
||||||
with:
|
with:
|
||||||
base64-subjects: ${{ needs.build.outputs.hash }}
|
base64-subjects: ${{ needs.build.outputs.hash }}
|
||||||
create-release:
|
create-release:
|
||||||
|
|
|
||||||
2
.github/workflows/tests.yaml
vendored
2
.github/workflows/tests.yaml
vendored
|
|
@ -49,7 +49,7 @@ jobs:
|
||||||
pip install -U setuptools
|
pip install -U setuptools
|
||||||
python -m pip install -U pip
|
python -m pip install -U pip
|
||||||
- name: cache mypy
|
- name: cache mypy
|
||||||
uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920
|
uses: actions/cache@69d9d449aced6a2ede0bc19182fadc3a0a42d2b0
|
||||||
with:
|
with:
|
||||||
path: ./.mypy_cache
|
path: ./.mypy_cache
|
||||||
key: mypy|${{ matrix.python }}|${{ hashFiles('pyproject.toml') }}
|
key: mypy|${{ matrix.python }}|${{ hashFiles('pyproject.toml') }}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ repos:
|
||||||
- flake8-bugbear
|
- flake8-bugbear
|
||||||
- flake8-implicit-str-concat
|
- flake8-implicit-str-concat
|
||||||
- repo: https://github.com/peterdemin/pip-compile-multi
|
- repo: https://github.com/peterdemin/pip-compile-multi
|
||||||
rev: v2.6.1
|
rev: v2.6.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: pip-compile-multi-verify
|
- id: pip-compile-multi-verify
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
|
|
||||||
45
CHANGES.rst
45
CHANGES.rst
|
|
@ -3,19 +3,56 @@ Version 2.3.0
|
||||||
|
|
||||||
Unreleased
|
Unreleased
|
||||||
|
|
||||||
|
- Remove previously deprecated code. :pr:`4995`
|
||||||
|
|
||||||
|
- The ``push`` and ``pop`` methods of the deprecated ``_app_ctx_stack`` and
|
||||||
|
``_request_ctx_stack`` objects are removed. ``top`` still exists to give
|
||||||
|
extensions more time to update, but it will be removed.
|
||||||
|
- The ``FLASK_ENV`` environment variable, ``ENV`` config key, and ``app.env``
|
||||||
|
property are removed.
|
||||||
|
- The ``session_cookie_name``, ``send_file_max_age_default``, ``use_x_sendfile``,
|
||||||
|
``propagate_exceptions``, and ``templates_auto_reload`` properties on ``app``
|
||||||
|
are removed.
|
||||||
|
- The ``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_MIMETYPE``, and
|
||||||
|
``JSONIFY_PRETTYPRINT_REGULAR`` config keys are removed.
|
||||||
|
- The ``app.before_first_request`` and ``bp.before_app_first_request`` decorators
|
||||||
|
are removed.
|
||||||
|
- ``json_encoder`` and ``json_decoder`` attributes on app and blueprint, and the
|
||||||
|
corresponding ``json.JSONEncoder`` and ``JSONDecoder`` classes, are removed.
|
||||||
|
- The ``json.htmlsafe_dumps`` and ``htmlsafe_dump`` functions are removed.
|
||||||
|
- Calling setup methods on blueprints after registration is an error instead of a
|
||||||
|
warning. :pr:`4997`
|
||||||
|
|
||||||
|
- Importing ``escape`` and ``Markup`` from ``flask`` is deprecated. Import them
|
||||||
|
directly from ``markupsafe`` instead. :pr:`4996`
|
||||||
|
- The ``app.got_first_request`` property is deprecated. :pr:`4997`
|
||||||
|
- The ``locked_cached_property`` decorator is deprecated. Use a lock inside the
|
||||||
|
decorated function if locking is needed. :issue:`4993`
|
||||||
|
- Remove uses of locks that could cause requests to block each other very briefly.
|
||||||
|
:issue:`4993`
|
||||||
- Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``.
|
- Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``.
|
||||||
:pr:`4947`
|
:pr:`4947`
|
||||||
- Ensure subdomains are applied with nested blueprints. :issue:`4834`
|
- Ensure subdomains are applied with nested blueprints. :issue:`4834`
|
||||||
|
- ``config.from_file`` can use ``text=False`` to indicate that the parser wants a
|
||||||
|
binary file instead. :issue:`4989`
|
||||||
|
- If a blueprint is created with an empty name it raises a ``ValueError``.
|
||||||
|
:issue:`5010`
|
||||||
|
|
||||||
|
|
||||||
|
Version 2.2.4
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Unreleased
|
||||||
|
|
||||||
|
- Update for compatibility with Werkzeug 2.3.
|
||||||
|
|
||||||
|
|
||||||
Version 2.2.3
|
Version 2.2.3
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Unreleased
|
Released 2023-02-15
|
||||||
|
|
||||||
- Autoescaping is now enabled by default for ``.svg`` files. Inside
|
- Autoescape is enabled by default for ``.svg`` template files. :issue:`4831`
|
||||||
templates this behavior can be changed with the ``autoescape`` tag.
|
|
||||||
:issue:`4831`
|
|
||||||
- Fix the type of ``template_folder`` to accept ``pathlib.Path``. :issue:`4892`
|
- Fix the type of ``template_folder`` to accept ``pathlib.Path``. :issue:`4892`
|
||||||
- Add ``--debug`` option to the ``flask run`` command. :issue:`4777`
|
- Add ``--debug`` option to the ``flask run`` command. :issue:`4777`
|
||||||
|
|
||||||
|
|
|
||||||
10
docs/api.rst
10
docs/api.rst
|
|
@ -217,10 +217,6 @@ Useful Functions and Classes
|
||||||
|
|
||||||
.. autofunction:: send_from_directory
|
.. autofunction:: send_from_directory
|
||||||
|
|
||||||
.. autofunction:: escape
|
|
||||||
|
|
||||||
.. autoclass:: Markup
|
|
||||||
:members: escape, unescape, striptags
|
|
||||||
|
|
||||||
Message Flashing
|
Message Flashing
|
||||||
----------------
|
----------------
|
||||||
|
|
@ -270,12 +266,6 @@ HTML ``<script>`` tags.
|
||||||
:members:
|
:members:
|
||||||
:member-order: bysource
|
:member-order: bysource
|
||||||
|
|
||||||
.. autoclass:: JSONEncoder
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. autoclass:: JSONDecoder
|
|
||||||
:members:
|
|
||||||
|
|
||||||
.. automodule:: flask.json.tag
|
.. automodule:: flask.json.tag
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,14 @@ the ``--debug`` option.
|
||||||
* Debugger is active!
|
* Debugger is active!
|
||||||
* Debugger PIN: 223-456-919
|
* Debugger PIN: 223-456-919
|
||||||
|
|
||||||
|
The ``--debug`` option can also be passed to the top level ``flask`` command to enable
|
||||||
|
debug mode for any command. The following two ``run`` calls are equivalent.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ flask --app hello --debug run
|
||||||
|
$ flask --app hello run --debug
|
||||||
|
|
||||||
|
|
||||||
Watch and Ignore Files with the Reloader
|
Watch and Ignore Files with the Reloader
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
||||||
|
|
@ -47,17 +47,17 @@ Debug Mode
|
||||||
|
|
||||||
The :data:`DEBUG` config value is special because it may behave inconsistently if
|
The :data:`DEBUG` config value is special because it may behave inconsistently if
|
||||||
changed after the app has begun setting up. In order to set debug mode reliably, use the
|
changed after the app has begun setting up. In order to set debug mode reliably, use the
|
||||||
``--debug`` option on the ``flask run`` command. ``flask run`` will use the interactive
|
``--debug`` option on the ``flask`` or ``flask run`` command. ``flask run`` will use the
|
||||||
debugger and reloader by default in debug mode.
|
interactive debugger and reloader by default in debug mode.
|
||||||
|
|
||||||
.. code-block:: text
|
.. code-block:: text
|
||||||
|
|
||||||
$ flask --app hello run --debug
|
$ flask --app hello run --debug
|
||||||
|
|
||||||
Using the option is recommended. While it is possible to set :data:`DEBUG` in your
|
Using the option is recommended. While it is possible to set :data:`DEBUG` in your
|
||||||
config or code, this is strongly discouraged. It can't be read early by the ``flask run``
|
config or code, this is strongly discouraged. It can't be read early by the
|
||||||
command, and some systems or extensions may have already configured themselves based on
|
``flask run`` command, and some systems or extensions may have already configured
|
||||||
a previous value.
|
themselves based on a previous value.
|
||||||
|
|
||||||
|
|
||||||
Builtin Configuration Values
|
Builtin Configuration Values
|
||||||
|
|
@ -65,18 +65,6 @@ Builtin Configuration Values
|
||||||
|
|
||||||
The following configuration values are used internally by Flask:
|
The following configuration values are used internally by Flask:
|
||||||
|
|
||||||
.. py:data:: ENV
|
|
||||||
|
|
||||||
What environment the app is running in. The :attr:`~flask.Flask.env` attribute maps
|
|
||||||
to this config key.
|
|
||||||
|
|
||||||
Default: ``'production'``
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Use ``--debug`` instead.
|
|
||||||
|
|
||||||
.. versionadded:: 1.0
|
|
||||||
|
|
||||||
.. py:data:: DEBUG
|
.. py:data:: DEBUG
|
||||||
|
|
||||||
Whether debug mode is enabled. When using ``flask run`` to start the development
|
Whether debug mode is enabled. When using ``flask run`` to start the development
|
||||||
|
|
@ -271,52 +259,6 @@ The following configuration values are used internally by Flask:
|
||||||
|
|
||||||
Default: ``None``
|
Default: ``None``
|
||||||
|
|
||||||
.. py:data:: JSON_AS_ASCII
|
|
||||||
|
|
||||||
Serialize objects to ASCII-encoded JSON. If this is disabled, the
|
|
||||||
JSON returned from ``jsonify`` will contain Unicode characters. This
|
|
||||||
has security implications when rendering the JSON into JavaScript in
|
|
||||||
templates, and should typically remain enabled.
|
|
||||||
|
|
||||||
Default: ``True``
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Set ``app.json.ensure_ascii``
|
|
||||||
instead.
|
|
||||||
|
|
||||||
.. py:data:: JSON_SORT_KEYS
|
|
||||||
|
|
||||||
Sort the keys of JSON objects alphabetically. This is useful for caching
|
|
||||||
because it ensures the data is serialized the same way no matter what
|
|
||||||
Python's hash seed is. While not recommended, you can disable this for a
|
|
||||||
possible performance improvement at the cost of caching.
|
|
||||||
|
|
||||||
Default: ``True``
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Set ``app.json.sort_keys``
|
|
||||||
instead.
|
|
||||||
|
|
||||||
.. py:data:: JSONIFY_PRETTYPRINT_REGULAR
|
|
||||||
|
|
||||||
:func:`~flask.jsonify` responses will be output with newlines,
|
|
||||||
spaces, and indentation for easier reading by humans. Always enabled
|
|
||||||
in debug mode.
|
|
||||||
|
|
||||||
Default: ``False``
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Set ``app.json.compact`` instead.
|
|
||||||
|
|
||||||
.. py:data:: JSONIFY_MIMETYPE
|
|
||||||
|
|
||||||
The mimetype of ``jsonify`` responses.
|
|
||||||
|
|
||||||
Default: ``'application/json'``
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Set ``app.json.mimetype`` instead.
|
|
||||||
|
|
||||||
.. py:data:: TEMPLATES_AUTO_RELOAD
|
.. py:data:: TEMPLATES_AUTO_RELOAD
|
||||||
|
|
||||||
Reload templates when they are changed. If not set, it will be enabled in
|
Reload templates when they are changed. If not set, it will be enabled in
|
||||||
|
|
@ -381,14 +323,13 @@ The following configuration values are used internally by Flask:
|
||||||
.. versionchanged:: 2.2
|
.. versionchanged:: 2.2
|
||||||
Removed ``PRESERVE_CONTEXT_ON_EXCEPTION``.
|
Removed ``PRESERVE_CONTEXT_ON_EXCEPTION``.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
.. versionchanged:: 2.3
|
||||||
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``,
|
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_MIMETYPE``, and
|
||||||
``JSONIFY_MIMETYPE``, and ``JSONIFY_PRETTYPRINT_REGULAR`` will be
|
``JSONIFY_PRETTYPRINT_REGULAR`` were removed. The default ``app.json`` provider has
|
||||||
removed in Flask 2.3. The default ``app.json`` provider has
|
|
||||||
equivalent attributes instead.
|
equivalent attributes instead.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
.. versionchanged:: 2.3
|
||||||
``ENV`` will be removed in Flask 2.3. Use ``--debug`` instead.
|
``ENV`` was removed.
|
||||||
|
|
||||||
|
|
||||||
Configuring from Python Files
|
Configuring from Python Files
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ See also:
|
||||||
- Sentry also supports catching errors from a worker queue
|
- Sentry also supports catching errors from a worker queue
|
||||||
(RQ, Celery, etc.) in a similar fashion. See the `Python SDK docs
|
(RQ, Celery, etc.) in a similar fashion. See the `Python SDK docs
|
||||||
<https://docs.sentry.io/platforms/python/>`__ for more information.
|
<https://docs.sentry.io/platforms/python/>`__ for more information.
|
||||||
- `Getting started with Sentry <https://docs.sentry.io/quickstart/?platform=python>`__
|
|
||||||
- `Flask-specific documentation <https://docs.sentry.io/platforms/python/guides/flask/>`__
|
- `Flask-specific documentation <https://docs.sentry.io/platforms/python/guides/flask/>`__
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ use them if you install them.
|
||||||
* `Watchdog`_ provides a faster, more efficient reloader for the development
|
* `Watchdog`_ provides a faster, more efficient reloader for the development
|
||||||
server.
|
server.
|
||||||
|
|
||||||
.. _Blinker: https://pythonhosted.org/blinker/
|
.. _Blinker: https://blinker.readthedocs.io/en/stable/
|
||||||
.. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
|
.. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
|
||||||
.. _watchdog: https://pythonhosted.org/watchdog/
|
.. _watchdog: https://pythonhosted.org/watchdog/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ in templates, but there are still other places where you have to be
|
||||||
careful:
|
careful:
|
||||||
|
|
||||||
- generating HTML without the help of Jinja2
|
- generating HTML without the help of Jinja2
|
||||||
- calling :class:`~flask.Markup` on data submitted by users
|
- calling :class:`~markupsafe.Markup` on data submitted by users
|
||||||
- sending out HTML from uploaded files, never do that, use the
|
- sending out HTML from uploaded files, never do that, use the
|
||||||
``Content-Disposition: attachment`` header to prevent that problem.
|
``Content-Disposition: attachment`` header to prevent that problem.
|
||||||
- sending out textfiles from uploaded files. Some browsers are using
|
- sending out textfiles from uploaded files. Some browsers are using
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ markdown to HTML converter.
|
||||||
|
|
||||||
There are three ways to accomplish that:
|
There are three ways to accomplish that:
|
||||||
|
|
||||||
- In the Python code, wrap the HTML string in a :class:`~flask.Markup`
|
- In the Python code, wrap the HTML string in a :class:`~markupsafe.Markup`
|
||||||
object before passing it to the template. This is in general the
|
object before passing it to the template. This is in general the
|
||||||
recommended way.
|
recommended way.
|
||||||
- Inside the template, use the ``|safe`` filter to explicitly mark a
|
- Inside the template, use the ``|safe`` filter to explicitly mark a
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ In a separate terminal, activate the virtualenv and run the Flask development se
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ . ./.venv/bin/activate
|
$ . ./.venv/bin/activate
|
||||||
$ flask -A task_app --debug run
|
$ flask -A task_app run --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
Go to http://localhost:5000/ and use the forms to submit tasks. You can see the polling
|
Go to http://localhost:5000/ and use the forms to submit tasks. You can see the polling
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# This file is autogenerated by pip-compile with Python 3.10
|
# This file is autogenerated by pip-compile with Python 3.10
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile pyproject.toml
|
# pip-compile --resolver=backtracking pyproject.toml
|
||||||
#
|
#
|
||||||
amqp==5.1.1
|
amqp==5.1.1
|
||||||
# via kombu
|
# via kombu
|
||||||
|
|
@ -25,7 +25,7 @@ click-plugins==1.1.1
|
||||||
# via celery
|
# via celery
|
||||||
click-repl==0.2.0
|
click-repl==0.2.0
|
||||||
# via celery
|
# via celery
|
||||||
flask==2.2.2
|
flask==2.2.3
|
||||||
# via flask-example-celery (pyproject.toml)
|
# via flask-example-celery (pyproject.toml)
|
||||||
itsdangerous==2.1.2
|
itsdangerous==2.1.2
|
||||||
# via flask
|
# via flask
|
||||||
|
|
@ -37,7 +37,7 @@ markupsafe==2.1.2
|
||||||
# via
|
# via
|
||||||
# jinja2
|
# jinja2
|
||||||
# werkzeug
|
# werkzeug
|
||||||
prompt-toolkit==3.0.36
|
prompt-toolkit==3.0.37
|
||||||
# via click-repl
|
# via click-repl
|
||||||
pytz==2022.7.1
|
pytz==2022.7.1
|
||||||
# via celery
|
# via celery
|
||||||
|
|
@ -52,5 +52,5 @@ vine==5.0.0
|
||||||
# kombu
|
# kombu
|
||||||
wcwidth==0.2.6
|
wcwidth==0.2.6
|
||||||
# via prompt-toolkit
|
# via prompt-toolkit
|
||||||
werkzeug==2.2.2
|
werkzeug==2.2.3
|
||||||
# via flask
|
# via flask
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,11 @@
|
||||||
#
|
#
|
||||||
# pip-compile-multi
|
# pip-compile-multi
|
||||||
#
|
#
|
||||||
build==0.9.0
|
build==0.10.0
|
||||||
# via -r requirements/build.in
|
# via -r requirements/build.in
|
||||||
packaging==23.0
|
packaging==23.0
|
||||||
# via build
|
# via build
|
||||||
pep517==0.13.0
|
pyproject-hooks==1.0.0
|
||||||
# via build
|
# via build
|
||||||
tomli==2.0.1
|
tomli==2.0.1
|
||||||
# via
|
# via build
|
||||||
# build
|
|
||||||
# pep517
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@
|
||||||
-r docs.txt
|
-r docs.txt
|
||||||
-r tests.txt
|
-r tests.txt
|
||||||
-r typing.txt
|
-r typing.txt
|
||||||
build==0.9.0
|
build==0.10.0
|
||||||
# via pip-tools
|
# via pip-tools
|
||||||
cachetools==5.2.0
|
cachetools==5.3.0
|
||||||
# via tox
|
# via tox
|
||||||
cfgv==3.3.1
|
cfgv==3.3.1
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
|
|
@ -24,37 +24,35 @@ colorama==0.4.6
|
||||||
# via tox
|
# via tox
|
||||||
distlib==0.3.6
|
distlib==0.3.6
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.8.2
|
filelock==3.9.0
|
||||||
# via
|
# via
|
||||||
# tox
|
# tox
|
||||||
# virtualenv
|
# virtualenv
|
||||||
identify==2.5.11
|
identify==2.5.19
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
nodeenv==1.7.0
|
nodeenv==1.7.0
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
pep517==0.13.0
|
pip-compile-multi==2.6.2
|
||||||
# via build
|
|
||||||
pip-compile-multi==2.6.1
|
|
||||||
# via -r requirements/dev.in
|
# via -r requirements/dev.in
|
||||||
pip-tools==6.12.1
|
pip-tools==6.12.3
|
||||||
# via pip-compile-multi
|
# via pip-compile-multi
|
||||||
platformdirs==2.6.0
|
platformdirs==3.1.1
|
||||||
# via
|
# via
|
||||||
# tox
|
# tox
|
||||||
# virtualenv
|
# virtualenv
|
||||||
pre-commit==2.20.0
|
pre-commit==3.1.1
|
||||||
# via -r requirements/dev.in
|
# via -r requirements/dev.in
|
||||||
pyproject-api==1.2.1
|
pyproject-api==1.5.0
|
||||||
# via tox
|
# via tox
|
||||||
|
pyproject-hooks==1.0.0
|
||||||
|
# via build
|
||||||
pyyaml==6.0
|
pyyaml==6.0
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
toml==0.10.2
|
toposort==1.10
|
||||||
# via pre-commit
|
|
||||||
toposort==1.7
|
|
||||||
# via pip-compile-multi
|
# via pip-compile-multi
|
||||||
tox==4.0.16
|
tox==4.4.6
|
||||||
# via -r requirements/dev.in
|
# via -r requirements/dev.in
|
||||||
virtualenv==20.17.1
|
virtualenv==20.20.0
|
||||||
# via
|
# via
|
||||||
# pre-commit
|
# pre-commit
|
||||||
# tox
|
# tox
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@
|
||||||
#
|
#
|
||||||
# pip-compile-multi
|
# pip-compile-multi
|
||||||
#
|
#
|
||||||
alabaster==0.7.12
|
alabaster==0.7.13
|
||||||
# via sphinx
|
# via sphinx
|
||||||
babel==2.11.0
|
babel==2.12.1
|
||||||
# via sphinx
|
# via sphinx
|
||||||
certifi==2022.12.7
|
certifi==2022.12.7
|
||||||
# via requests
|
# via requests
|
||||||
charset-normalizer==2.1.1
|
charset-normalizer==3.1.0
|
||||||
# via requests
|
# via requests
|
||||||
docutils==0.17.1
|
docutils==0.17.1
|
||||||
# via
|
# via
|
||||||
|
|
@ -23,21 +23,19 @@ imagesize==1.4.1
|
||||||
# via sphinx
|
# via sphinx
|
||||||
jinja2==3.1.2
|
jinja2==3.1.2
|
||||||
# via sphinx
|
# via sphinx
|
||||||
markupsafe==2.1.1
|
markupsafe==2.1.2
|
||||||
# via jinja2
|
# via jinja2
|
||||||
packaging==22.0
|
packaging==23.0
|
||||||
# via
|
# via
|
||||||
# pallets-sphinx-themes
|
# pallets-sphinx-themes
|
||||||
# sphinx
|
# sphinx
|
||||||
pallets-sphinx-themes==2.0.3
|
pallets-sphinx-themes==2.0.3
|
||||||
# via -r requirements/docs.in
|
# via -r requirements/docs.in
|
||||||
pygments==2.13.0
|
pygments==2.14.0
|
||||||
# via
|
# via
|
||||||
# sphinx
|
# sphinx
|
||||||
# sphinx-tabs
|
# sphinx-tabs
|
||||||
pytz==2022.7
|
requests==2.28.2
|
||||||
# via babel
|
|
||||||
requests==2.28.1
|
|
||||||
# via sphinx
|
# via sphinx
|
||||||
snowballstemmer==2.2.0
|
snowballstemmer==2.2.0
|
||||||
# via sphinx
|
# via sphinx
|
||||||
|
|
@ -52,11 +50,11 @@ sphinx-issues==3.0.1
|
||||||
# via -r requirements/docs.in
|
# via -r requirements/docs.in
|
||||||
sphinx-tabs==3.3.1
|
sphinx-tabs==3.3.1
|
||||||
# via -r requirements/docs.in
|
# via -r requirements/docs.in
|
||||||
sphinxcontrib-applehelp==1.0.2
|
sphinxcontrib-applehelp==1.0.4
|
||||||
# via sphinx
|
# via sphinx
|
||||||
sphinxcontrib-devhelp==1.0.2
|
sphinxcontrib-devhelp==1.0.2
|
||||||
# via sphinx
|
# via sphinx
|
||||||
sphinxcontrib-htmlhelp==2.0.0
|
sphinxcontrib-htmlhelp==2.0.1
|
||||||
# via sphinx
|
# via sphinx
|
||||||
sphinxcontrib-jsmath==1.0.1
|
sphinxcontrib-jsmath==1.0.1
|
||||||
# via sphinx
|
# via sphinx
|
||||||
|
|
@ -66,5 +64,5 @@ sphinxcontrib-qthelp==1.0.3
|
||||||
# via sphinx
|
# via sphinx
|
||||||
sphinxcontrib-serializinghtml==1.1.5
|
sphinxcontrib-serializinghtml==1.1.5
|
||||||
# via sphinx
|
# via sphinx
|
||||||
urllib3==1.26.13
|
urllib3==1.26.15
|
||||||
# via requests
|
# via requests
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,4 @@ pytest
|
||||||
asgiref
|
asgiref
|
||||||
blinker
|
blinker
|
||||||
greenlet ; python_version < "3.11"
|
greenlet ; python_version < "3.11"
|
||||||
python-dotenv
|
python-dotenv>=1; python_version >= "3.8"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# SHA1:69cf1e101a60350e9933c6f1f3b129bd9ed1ea7c
|
# SHA1:30698f5f4f9cba5088318306829a15b0dc123b38
|
||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile-multi
|
# This file is autogenerated by pip-compile-multi
|
||||||
# To update, run:
|
# To update, run:
|
||||||
|
|
@ -11,13 +11,19 @@ attrs==22.2.0
|
||||||
# via pytest
|
# via pytest
|
||||||
blinker==1.5
|
blinker==1.5
|
||||||
# via -r requirements/tests.in
|
# via -r requirements/tests.in
|
||||||
iniconfig==1.1.1
|
exceptiongroup==1.1.0
|
||||||
# via pytest
|
# via pytest
|
||||||
packaging==22.0
|
greenlet==2.0.2 ; python_version < "3.11"
|
||||||
|
# via -r requirements/tests.in
|
||||||
|
iniconfig==2.0.0
|
||||||
|
# via pytest
|
||||||
|
packaging==23.0
|
||||||
# via pytest
|
# via pytest
|
||||||
pluggy==1.0.0
|
pluggy==1.0.0
|
||||||
# via pytest
|
# via pytest
|
||||||
pytest==7.2.0
|
pytest==7.2.2
|
||||||
# via -r requirements/tests.in
|
# via -r requirements/tests.in
|
||||||
python-dotenv==0.21.0
|
python-dotenv==1.0.0 ; python_version >= "3.8"
|
||||||
# via -r requirements/tests.in
|
# via -r requirements/tests.in
|
||||||
|
tomli==2.0.1
|
||||||
|
# via pytest
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,21 @@
|
||||||
#
|
#
|
||||||
cffi==1.15.1
|
cffi==1.15.1
|
||||||
# via cryptography
|
# via cryptography
|
||||||
cryptography==38.0.4
|
cryptography==39.0.2
|
||||||
# via -r requirements/typing.in
|
# via -r requirements/typing.in
|
||||||
mypy==0.991
|
mypy==1.1.1
|
||||||
# via -r requirements/typing.in
|
# via -r requirements/typing.in
|
||||||
mypy-extensions==0.4.3
|
mypy-extensions==1.0.0
|
||||||
# via mypy
|
# via mypy
|
||||||
pycparser==2.21
|
pycparser==2.21
|
||||||
# via cffi
|
# via cffi
|
||||||
types-contextvars==2.4.7
|
tomli==2.0.1
|
||||||
|
# via mypy
|
||||||
|
types-contextvars==2.4.7.1
|
||||||
# via -r requirements/typing.in
|
# via -r requirements/typing.in
|
||||||
types-dataclasses==0.6.6
|
types-dataclasses==0.6.6
|
||||||
# via -r requirements/typing.in
|
# via -r requirements/typing.in
|
||||||
types-setuptools==65.6.0.2
|
types-setuptools==67.6.0.0
|
||||||
# via -r requirements/typing.in
|
# via -r requirements/typing.in
|
||||||
typing-extensions==4.4.0
|
typing-extensions==4.5.0
|
||||||
# via mypy
|
# via mypy
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
from markupsafe import escape
|
|
||||||
from markupsafe import Markup
|
|
||||||
|
|
||||||
from . import json as json
|
from . import json as json
|
||||||
from .app import Flask as Flask
|
from .app import Flask as Flask
|
||||||
from .app import Request as Request
|
from .app import Request as Request
|
||||||
|
|
@ -51,7 +48,7 @@ def __getattr__(name):
|
||||||
from .globals import __app_ctx_stack
|
from .globals import __app_ctx_stack
|
||||||
|
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"'_app_ctx_stack' is deprecated and will be removed in Flask 2.3.",
|
"'_app_ctx_stack' is deprecated and will be removed in Flask 2.4.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
|
|
@ -62,10 +59,34 @@ def __getattr__(name):
|
||||||
from .globals import __request_ctx_stack
|
from .globals import __request_ctx_stack
|
||||||
|
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"'_request_ctx_stack' is deprecated and will be removed in Flask 2.3.",
|
"'_request_ctx_stack' is deprecated and will be removed in Flask 2.4.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
return __request_ctx_stack
|
return __request_ctx_stack
|
||||||
|
|
||||||
|
if name == "escape":
|
||||||
|
import warnings
|
||||||
|
from markupsafe import escape
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"'flask.escape' is deprecated and will be removed in Flask 2.4. Import"
|
||||||
|
" 'markupsafe.escape' instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
return escape
|
||||||
|
|
||||||
|
if name == "escape":
|
||||||
|
import warnings
|
||||||
|
from markupsafe import Markup
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"'flask.Markup' is deprecated and will be removed in Flask 2.4. Import"
|
||||||
|
" 'markupsafe.Markup' instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
return Markup
|
||||||
|
|
||||||
raise AttributeError(name)
|
raise AttributeError(name)
|
||||||
|
|
|
||||||
367
src/flask/app.py
367
src/flask/app.py
|
|
@ -1,6 +1,5 @@
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -9,8 +8,8 @@ import weakref
|
||||||
from collections.abc import Iterator as _abc_Iterator
|
from collections.abc import Iterator as _abc_Iterator
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
from threading import Lock
|
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
|
from urllib.parse import quote as _url_quote
|
||||||
|
|
||||||
import click
|
import click
|
||||||
from werkzeug.datastructures import Headers
|
from werkzeug.datastructures import Headers
|
||||||
|
|
@ -27,7 +26,7 @@ from werkzeug.routing import RequestRedirect
|
||||||
from werkzeug.routing import RoutingException
|
from werkzeug.routing import RoutingException
|
||||||
from werkzeug.routing import Rule
|
from werkzeug.routing import Rule
|
||||||
from werkzeug.serving import is_running_from_reloader
|
from werkzeug.serving import is_running_from_reloader
|
||||||
from werkzeug.urls import url_quote
|
from werkzeug.utils import cached_property
|
||||||
from werkzeug.utils import redirect as _wz_redirect
|
from werkzeug.utils import redirect as _wz_redirect
|
||||||
from werkzeug.wrappers import Response as BaseResponse
|
from werkzeug.wrappers import Response as BaseResponse
|
||||||
|
|
||||||
|
|
@ -48,7 +47,6 @@ from .helpers import _split_blueprint_path
|
||||||
from .helpers import get_debug_flag
|
from .helpers import get_debug_flag
|
||||||
from .helpers import get_flashed_messages
|
from .helpers import get_flashed_messages
|
||||||
from .helpers import get_load_dotenv
|
from .helpers import get_load_dotenv
|
||||||
from .helpers import locked_cached_property
|
|
||||||
from .json.provider import DefaultJSONProvider
|
from .json.provider import DefaultJSONProvider
|
||||||
from .json.provider import JSONProvider
|
from .json.provider import JSONProvider
|
||||||
from .logging import create_logger
|
from .logging import create_logger
|
||||||
|
|
@ -75,9 +73,6 @@ if t.TYPE_CHECKING: # pragma: no cover
|
||||||
from .testing import FlaskClient
|
from .testing import FlaskClient
|
||||||
from .testing import FlaskCliRunner
|
from .testing import FlaskCliRunner
|
||||||
|
|
||||||
T_before_first_request = t.TypeVar(
|
|
||||||
"T_before_first_request", bound=ft.BeforeFirstRequestCallable
|
|
||||||
)
|
|
||||||
T_shell_context_processor = t.TypeVar(
|
T_shell_context_processor = t.TypeVar(
|
||||||
"T_shell_context_processor", bound=ft.ShellContextProcessorCallable
|
"T_shell_context_processor", bound=ft.ShellContextProcessorCallable
|
||||||
)
|
)
|
||||||
|
|
@ -274,36 +269,6 @@ class Flask(Scaffold):
|
||||||
#: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
|
#: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
|
||||||
secret_key = ConfigAttribute("SECRET_KEY")
|
secret_key = ConfigAttribute("SECRET_KEY")
|
||||||
|
|
||||||
@property
|
|
||||||
def session_cookie_name(self) -> str:
|
|
||||||
"""The name of the cookie set by the session interface.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Use ``app.config["SESSION_COOKIE_NAME"]``
|
|
||||||
instead.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'session_cookie_name' is deprecated and will be removed in Flask 2.3. Use"
|
|
||||||
" 'SESSION_COOKIE_NAME' in 'app.config' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self.config["SESSION_COOKIE_NAME"]
|
|
||||||
|
|
||||||
@session_cookie_name.setter
|
|
||||||
def session_cookie_name(self, value: str) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'session_cookie_name' is deprecated and will be removed in Flask 2.3. Use"
|
|
||||||
" 'SESSION_COOKIE_NAME' in 'app.config' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self.config["SESSION_COOKIE_NAME"] = value
|
|
||||||
|
|
||||||
#: A :class:`~datetime.timedelta` which is used to set the expiration
|
#: A :class:`~datetime.timedelta` which is used to set the expiration
|
||||||
#: date of a permanent session. The default is 31 days which makes a
|
#: date of a permanent session. The default is 31 days which makes a
|
||||||
#: permanent session survive for roughly one month.
|
#: permanent session survive for roughly one month.
|
||||||
|
|
@ -315,152 +280,6 @@ class Flask(Scaffold):
|
||||||
"PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
|
"PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def send_file_max_age_default(self) -> t.Optional[timedelta]:
|
|
||||||
"""The default value for ``max_age`` for :func:`~flask.send_file`. The default
|
|
||||||
is ``None``, which tells the browser to use conditional requests instead of a
|
|
||||||
timed cache.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Use
|
|
||||||
``app.config["SEND_FILE_MAX_AGE_DEFAULT"]`` instead.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.0
|
|
||||||
Defaults to ``None`` instead of 12 hours.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'send_file_max_age_default' is deprecated and will be removed in Flask"
|
|
||||||
" 2.3. Use 'SEND_FILE_MAX_AGE_DEFAULT' in 'app.config' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return _make_timedelta(self.config["SEND_FILE_MAX_AGE_DEFAULT"])
|
|
||||||
|
|
||||||
@send_file_max_age_default.setter
|
|
||||||
def send_file_max_age_default(self, value: t.Union[int, timedelta, None]) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'send_file_max_age_default' is deprecated and will be removed in Flask"
|
|
||||||
" 2.3. Use 'SEND_FILE_MAX_AGE_DEFAULT' in 'app.config' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self.config["SEND_FILE_MAX_AGE_DEFAULT"] = _make_timedelta(value)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def use_x_sendfile(self) -> bool:
|
|
||||||
"""Enable this to use the ``X-Sendfile`` feature, assuming the server supports
|
|
||||||
it, from :func:`~flask.send_file`.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Use ``app.config["USE_X_SENDFILE"]`` instead.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'use_x_sendfile' is deprecated and will be removed in Flask 2.3. Use"
|
|
||||||
" 'USE_X_SENDFILE' in 'app.config' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self.config["USE_X_SENDFILE"]
|
|
||||||
|
|
||||||
@use_x_sendfile.setter
|
|
||||||
def use_x_sendfile(self, value: bool) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'use_x_sendfile' is deprecated and will be removed in Flask 2.3. Use"
|
|
||||||
" 'USE_X_SENDFILE' in 'app.config' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self.config["USE_X_SENDFILE"] = value
|
|
||||||
|
|
||||||
_json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None
|
|
||||||
_json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None
|
|
||||||
|
|
||||||
@property # type: ignore[override]
|
|
||||||
def json_encoder(self) -> t.Type[json.JSONEncoder]:
|
|
||||||
"""The JSON encoder class to use. Defaults to
|
|
||||||
:class:`~flask.json.JSONEncoder`.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Customize
|
|
||||||
:attr:`json_provider_class` instead.
|
|
||||||
|
|
||||||
.. versionadded:: 0.10
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'app.json_encoder' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json_provider_class' or 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
if self._json_encoder is None:
|
|
||||||
from . import json
|
|
||||||
|
|
||||||
return json.JSONEncoder
|
|
||||||
|
|
||||||
return self._json_encoder
|
|
||||||
|
|
||||||
@json_encoder.setter
|
|
||||||
def json_encoder(self, value: t.Type[json.JSONEncoder]) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'app.json_encoder' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json_provider_class' or 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self._json_encoder = value
|
|
||||||
|
|
||||||
@property # type: ignore[override]
|
|
||||||
def json_decoder(self) -> t.Type[json.JSONDecoder]:
|
|
||||||
"""The JSON decoder class to use. Defaults to
|
|
||||||
:class:`~flask.json.JSONDecoder`.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Customize
|
|
||||||
:attr:`json_provider_class` instead.
|
|
||||||
|
|
||||||
.. versionadded:: 0.10
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'app.json_decoder' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json_provider_class' or 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
|
|
||||||
if self._json_decoder is None:
|
|
||||||
from . import json
|
|
||||||
|
|
||||||
return json.JSONDecoder
|
|
||||||
|
|
||||||
return self._json_decoder
|
|
||||||
|
|
||||||
@json_decoder.setter
|
|
||||||
def json_decoder(self, value: t.Type[json.JSONDecoder]) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'app.json_decoder' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json_provider_class' or 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self._json_decoder = value
|
|
||||||
|
|
||||||
json_provider_class: t.Type[JSONProvider] = DefaultJSONProvider
|
json_provider_class: t.Type[JSONProvider] = DefaultJSONProvider
|
||||||
"""A subclass of :class:`~flask.json.provider.JSONProvider`. An
|
"""A subclass of :class:`~flask.json.provider.JSONProvider`. An
|
||||||
instance is created and assigned to :attr:`app.json` when creating
|
instance is created and assigned to :attr:`app.json` when creating
|
||||||
|
|
@ -487,7 +306,6 @@ class Flask(Scaffold):
|
||||||
#: Default configuration parameters.
|
#: Default configuration parameters.
|
||||||
default_config = ImmutableDict(
|
default_config = ImmutableDict(
|
||||||
{
|
{
|
||||||
"ENV": None,
|
|
||||||
"DEBUG": None,
|
"DEBUG": None,
|
||||||
"TESTING": False,
|
"TESTING": False,
|
||||||
"PROPAGATE_EXCEPTIONS": None,
|
"PROPAGATE_EXCEPTIONS": None,
|
||||||
|
|
@ -509,10 +327,6 @@ class Flask(Scaffold):
|
||||||
"TRAP_HTTP_EXCEPTIONS": False,
|
"TRAP_HTTP_EXCEPTIONS": False,
|
||||||
"EXPLAIN_TEMPLATE_LOADING": False,
|
"EXPLAIN_TEMPLATE_LOADING": False,
|
||||||
"PREFERRED_URL_SCHEME": "http",
|
"PREFERRED_URL_SCHEME": "http",
|
||||||
"JSON_AS_ASCII": None,
|
|
||||||
"JSON_SORT_KEYS": None,
|
|
||||||
"JSONIFY_PRETTYPRINT_REGULAR": None,
|
|
||||||
"JSONIFY_MIMETYPE": None,
|
|
||||||
"TEMPLATES_AUTO_RELOAD": None,
|
"TEMPLATES_AUTO_RELOAD": None,
|
||||||
"MAX_COOKIE_SIZE": 4093,
|
"MAX_COOKIE_SIZE": 4093,
|
||||||
}
|
}
|
||||||
|
|
@ -625,17 +439,6 @@ class Flask(Scaffold):
|
||||||
t.Callable[[Exception, str, t.Dict[str, t.Any]], str]
|
t.Callable[[Exception, str, t.Dict[str, t.Any]], str]
|
||||||
] = []
|
] = []
|
||||||
|
|
||||||
#: A list of functions that will be called at the beginning of the
|
|
||||||
#: first request to this instance. To register a function, use the
|
|
||||||
#: :meth:`before_first_request` decorator.
|
|
||||||
#:
|
|
||||||
#: .. deprecated:: 2.2
|
|
||||||
#: Will be removed in Flask 2.3. Run setup code when
|
|
||||||
#: creating the application instead.
|
|
||||||
#:
|
|
||||||
#: .. versionadded:: 0.8
|
|
||||||
self.before_first_request_funcs: t.List[ft.BeforeFirstRequestCallable] = []
|
|
||||||
|
|
||||||
#: A list of functions that are called when the application context
|
#: A list of functions that are called when the application context
|
||||||
#: is destroyed. Since the application context is also torn down
|
#: is destroyed. Since the application context is also torn down
|
||||||
#: if the request ends this is the place to store code that disconnects
|
#: if the request ends this is the place to store code that disconnects
|
||||||
|
|
@ -692,7 +495,6 @@ class Flask(Scaffold):
|
||||||
# tracks internally if the application already handled at least one
|
# tracks internally if the application already handled at least one
|
||||||
# request.
|
# request.
|
||||||
self._got_first_request = False
|
self._got_first_request = False
|
||||||
self._before_request_lock = Lock()
|
|
||||||
|
|
||||||
# Add a static route using the provided static_url_path, static_host,
|
# Add a static route using the provided static_url_path, static_host,
|
||||||
# and static_folder if there is a configured static_folder.
|
# and static_folder if there is a configured static_folder.
|
||||||
|
|
@ -729,7 +531,7 @@ class Flask(Scaffold):
|
||||||
" running it."
|
" running it."
|
||||||
)
|
)
|
||||||
|
|
||||||
@locked_cached_property
|
@cached_property
|
||||||
def name(self) -> str: # type: ignore
|
def name(self) -> str: # type: ignore
|
||||||
"""The name of the application. This is usually the import name
|
"""The name of the application. This is usually the import name
|
||||||
with the difference that it's guessed from the run file if the
|
with the difference that it's guessed from the run file if the
|
||||||
|
|
@ -746,29 +548,7 @@ class Flask(Scaffold):
|
||||||
return os.path.splitext(os.path.basename(fn))[0]
|
return os.path.splitext(os.path.basename(fn))[0]
|
||||||
return self.import_name
|
return self.import_name
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def propagate_exceptions(self) -> bool:
|
|
||||||
"""Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
|
|
||||||
value in case it's set, otherwise a sensible default is returned.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3.
|
|
||||||
|
|
||||||
.. versionadded:: 0.7
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'propagate_exceptions' is deprecated and will be removed in Flask 2.3.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
rv = self.config["PROPAGATE_EXCEPTIONS"]
|
|
||||||
if rv is not None:
|
|
||||||
return rv
|
|
||||||
return self.testing or self.debug
|
|
||||||
|
|
||||||
@locked_cached_property
|
|
||||||
def logger(self) -> logging.Logger:
|
def logger(self) -> logging.Logger:
|
||||||
"""A standard Python :class:`~logging.Logger` for the app, with
|
"""A standard Python :class:`~logging.Logger` for the app, with
|
||||||
the same name as :attr:`name`.
|
the same name as :attr:`name`.
|
||||||
|
|
@ -795,7 +575,7 @@ class Flask(Scaffold):
|
||||||
"""
|
"""
|
||||||
return create_logger(self)
|
return create_logger(self)
|
||||||
|
|
||||||
@locked_cached_property
|
@cached_property
|
||||||
def jinja_env(self) -> Environment:
|
def jinja_env(self) -> Environment:
|
||||||
"""The Jinja environment used to load templates.
|
"""The Jinja environment used to load templates.
|
||||||
|
|
||||||
|
|
@ -810,8 +590,18 @@ class Flask(Scaffold):
|
||||||
"""This attribute is set to ``True`` if the application started
|
"""This attribute is set to ``True`` if the application started
|
||||||
handling the first request.
|
handling the first request.
|
||||||
|
|
||||||
|
.. deprecated:: 2.3
|
||||||
|
Will be removed in Flask 2.4.
|
||||||
|
|
||||||
.. versionadded:: 0.8
|
.. versionadded:: 0.8
|
||||||
"""
|
"""
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"'got_first_request' is deprecated and will be removed in Flask 2.4.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
return self._got_first_request
|
return self._got_first_request
|
||||||
|
|
||||||
def make_config(self, instance_relative: bool = False) -> Config:
|
def make_config(self, instance_relative: bool = False) -> Config:
|
||||||
|
|
@ -827,7 +617,6 @@ class Flask(Scaffold):
|
||||||
if instance_relative:
|
if instance_relative:
|
||||||
root_path = self.instance_path
|
root_path = self.instance_path
|
||||||
defaults = dict(self.default_config)
|
defaults = dict(self.default_config)
|
||||||
defaults["ENV"] = os.environ.get("FLASK_ENV") or "production"
|
|
||||||
defaults["DEBUG"] = get_debug_flag()
|
defaults["DEBUG"] = get_debug_flag()
|
||||||
return self.config_class(root_path, defaults)
|
return self.config_class(root_path, defaults)
|
||||||
|
|
||||||
|
|
@ -868,42 +657,6 @@ class Flask(Scaffold):
|
||||||
"""
|
"""
|
||||||
return open(os.path.join(self.instance_path, resource), mode)
|
return open(os.path.join(self.instance_path, resource), mode)
|
||||||
|
|
||||||
@property
|
|
||||||
def templates_auto_reload(self) -> bool:
|
|
||||||
"""Reload templates when they are changed. Used by
|
|
||||||
:meth:`create_jinja_environment`. It is enabled by default in debug mode.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Use ``app.config["TEMPLATES_AUTO_RELOAD"]``
|
|
||||||
instead.
|
|
||||||
|
|
||||||
.. versionadded:: 1.0
|
|
||||||
This property was added but the underlying config and behavior
|
|
||||||
already existed.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'templates_auto_reload' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Use 'TEMPLATES_AUTO_RELOAD' in 'app.config' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
rv = self.config["TEMPLATES_AUTO_RELOAD"]
|
|
||||||
return rv if rv is not None else self.debug
|
|
||||||
|
|
||||||
@templates_auto_reload.setter
|
|
||||||
def templates_auto_reload(self, value: bool) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'templates_auto_reload' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Use 'TEMPLATES_AUTO_RELOAD' in 'app.config' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self.config["TEMPLATES_AUTO_RELOAD"] = value
|
|
||||||
|
|
||||||
def create_jinja_environment(self) -> Environment:
|
def create_jinja_environment(self) -> Environment:
|
||||||
"""Create the Jinja environment based on :attr:`jinja_options`
|
"""Create the Jinja environment based on :attr:`jinja_options`
|
||||||
and the various Jinja-related methods of the app. Changing
|
and the various Jinja-related methods of the app. Changing
|
||||||
|
|
@ -1010,40 +763,6 @@ class Flask(Scaffold):
|
||||||
rv.update(processor())
|
rv.update(processor())
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
@property
|
|
||||||
def env(self) -> str:
|
|
||||||
"""What environment the app is running in. This maps to the :data:`ENV` config
|
|
||||||
key.
|
|
||||||
|
|
||||||
**Do not enable development when deploying in production.**
|
|
||||||
|
|
||||||
Default: ``'production'``
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'app.env' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Use 'app.debug' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self.config["ENV"]
|
|
||||||
|
|
||||||
@env.setter
|
|
||||||
def env(self, value: str) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'app.env' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Use 'app.debug' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self.config["ENV"] = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def debug(self) -> bool:
|
def debug(self) -> bool:
|
||||||
"""Whether debug mode is enabled. When using ``flask run`` to start the
|
"""Whether debug mode is enabled. When using ``flask run`` to start the
|
||||||
|
|
@ -1144,16 +863,8 @@ class Flask(Scaffold):
|
||||||
if get_load_dotenv(load_dotenv):
|
if get_load_dotenv(load_dotenv):
|
||||||
cli.load_dotenv()
|
cli.load_dotenv()
|
||||||
|
|
||||||
# if set, let env vars override previous values
|
# if set, env var overrides existing value
|
||||||
if "FLASK_ENV" in os.environ:
|
if "FLASK_DEBUG" in os.environ:
|
||||||
print(
|
|
||||||
"'FLASK_ENV' is deprecated and will not be used in"
|
|
||||||
" Flask 2.3. Use 'FLASK_DEBUG' instead.",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
self.config["ENV"] = os.environ.get("FLASK_ENV") or "production"
|
|
||||||
self.debug = get_debug_flag()
|
|
||||||
elif "FLASK_DEBUG" in os.environ:
|
|
||||||
self.debug = get_debug_flag()
|
self.debug = get_debug_flag()
|
||||||
|
|
||||||
# debug passed to method overrides all other sources
|
# debug passed to method overrides all other sources
|
||||||
|
|
@ -1248,7 +959,7 @@ class Flask(Scaffold):
|
||||||
"""
|
"""
|
||||||
cls = self.test_client_class
|
cls = self.test_client_class
|
||||||
if cls is None:
|
if cls is None:
|
||||||
from .testing import FlaskClient as cls # type: ignore
|
from .testing import FlaskClient as cls
|
||||||
return cls( # type: ignore
|
return cls( # type: ignore
|
||||||
self, self.response_class, use_cookies=use_cookies, **kwargs
|
self, self.response_class, use_cookies=use_cookies, **kwargs
|
||||||
)
|
)
|
||||||
|
|
@ -1266,7 +977,7 @@ class Flask(Scaffold):
|
||||||
cls = self.test_cli_runner_class
|
cls = self.test_cli_runner_class
|
||||||
|
|
||||||
if cls is None:
|
if cls is None:
|
||||||
from .testing import FlaskCliRunner as cls # type: ignore
|
from .testing import FlaskCliRunner as cls
|
||||||
|
|
||||||
return cls(self, **kwargs) # type: ignore
|
return cls(self, **kwargs) # type: ignore
|
||||||
|
|
||||||
|
|
@ -1479,32 +1190,6 @@ class Flask(Scaffold):
|
||||||
"""
|
"""
|
||||||
self.jinja_env.globals[name or f.__name__] = f
|
self.jinja_env.globals[name or f.__name__] = f
|
||||||
|
|
||||||
@setupmethod
|
|
||||||
def before_first_request(self, f: T_before_first_request) -> T_before_first_request:
|
|
||||||
"""Registers a function to be run before the first request to this
|
|
||||||
instance of the application.
|
|
||||||
|
|
||||||
The function will be called without any arguments and its return
|
|
||||||
value is ignored.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Run setup code when creating
|
|
||||||
the application instead.
|
|
||||||
|
|
||||||
.. versionadded:: 0.8
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'before_first_request' is deprecated and will be removed"
|
|
||||||
" in Flask 2.3. Run setup code while creating the"
|
|
||||||
" application instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self.before_first_request_funcs.append(f)
|
|
||||||
return f
|
|
||||||
|
|
||||||
@setupmethod
|
@setupmethod
|
||||||
def teardown_appcontext(self, f: T_teardown) -> T_teardown:
|
def teardown_appcontext(self, f: T_teardown) -> T_teardown:
|
||||||
"""Registers a function to be called when the application
|
"""Registers a function to be called when the application
|
||||||
|
|
@ -1682,7 +1367,7 @@ class Flask(Scaffold):
|
||||||
|
|
||||||
Always sends the :data:`got_request_exception` signal.
|
Always sends the :data:`got_request_exception` signal.
|
||||||
|
|
||||||
If :attr:`propagate_exceptions` is ``True``, such as in debug
|
If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug
|
||||||
mode, the error will be re-raised so that the debugger can
|
mode, the error will be re-raised so that the debugger can
|
||||||
display it. Otherwise, the original exception is logged, and
|
display it. Otherwise, the original exception is logged, and
|
||||||
an :exc:`~werkzeug.exceptions.InternalServerError` is returned.
|
an :exc:`~werkzeug.exceptions.InternalServerError` is returned.
|
||||||
|
|
@ -1805,15 +1490,6 @@ class Flask(Scaffold):
|
||||||
|
|
||||||
.. versionadded:: 0.7
|
.. versionadded:: 0.7
|
||||||
"""
|
"""
|
||||||
# Run before_first_request functions if this is the thread's first request.
|
|
||||||
# Inlined to avoid a method call on subsequent requests.
|
|
||||||
# This is deprecated, will be removed in Flask 2.3.
|
|
||||||
if not self._got_first_request:
|
|
||||||
with self._before_request_lock:
|
|
||||||
if not self._got_first_request:
|
|
||||||
for func in self.before_first_request_funcs:
|
|
||||||
self.ensure_sync(func)()
|
|
||||||
|
|
||||||
self._got_first_request = True
|
self._got_first_request = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -2034,7 +1710,8 @@ class Flask(Scaffold):
|
||||||
return self.handle_url_build_error(error, endpoint, values)
|
return self.handle_url_build_error(error, endpoint, values)
|
||||||
|
|
||||||
if _anchor is not None:
|
if _anchor is not None:
|
||||||
rv = f"{rv}#{url_quote(_anchor)}"
|
_anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@")
|
||||||
|
rv = f"{rv}#{_anchor}"
|
||||||
|
|
||||||
return rv
|
return rv
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
import typing as t
|
import typing as t
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
@ -15,9 +14,6 @@ if t.TYPE_CHECKING: # pragma: no cover
|
||||||
|
|
||||||
DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable]
|
DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable]
|
||||||
T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable)
|
T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable)
|
||||||
T_before_first_request = t.TypeVar(
|
|
||||||
"T_before_first_request", bound=ft.BeforeFirstRequestCallable
|
|
||||||
)
|
|
||||||
T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable)
|
T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable)
|
||||||
T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable)
|
T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable)
|
||||||
T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable)
|
T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable)
|
||||||
|
|
@ -173,77 +169,6 @@ class Blueprint(Scaffold):
|
||||||
|
|
||||||
_got_registered_once = False
|
_got_registered_once = False
|
||||||
|
|
||||||
_json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None
|
|
||||||
_json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def json_encoder(
|
|
||||||
self,
|
|
||||||
) -> t.Union[t.Type[json.JSONEncoder], None]:
|
|
||||||
"""Blueprint-local JSON encoder class to use. Set to ``None`` to use the app's.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Customize
|
|
||||||
:attr:`json_provider_class` instead.
|
|
||||||
|
|
||||||
.. versionadded:: 0.10
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'bp.json_encoder' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json_provider_class' or 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self._json_encoder
|
|
||||||
|
|
||||||
@json_encoder.setter
|
|
||||||
def json_encoder(self, value: t.Union[t.Type[json.JSONEncoder], None]) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'bp.json_encoder' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json_provider_class' or 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self._json_encoder = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def json_decoder(
|
|
||||||
self,
|
|
||||||
) -> t.Union[t.Type[json.JSONDecoder], None]:
|
|
||||||
"""Blueprint-local JSON decoder class to use. Set to ``None`` to use the app's.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Customize
|
|
||||||
:attr:`json_provider_class` instead.
|
|
||||||
|
|
||||||
.. versionadded:: 0.10
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'bp.json_decoder' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json_provider_class' or 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return self._json_decoder
|
|
||||||
|
|
||||||
@json_decoder.setter
|
|
||||||
def json_decoder(self, value: t.Union[t.Type[json.JSONDecoder], None]) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'bp.json_decoder' is deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json_provider_class' or 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self._json_decoder = value
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
|
|
@ -265,6 +190,9 @@ class Blueprint(Scaffold):
|
||||||
root_path=root_path,
|
root_path=root_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
raise ValueError("'name' may not be empty.")
|
||||||
|
|
||||||
if "." in name:
|
if "." in name:
|
||||||
raise ValueError("'name' may not contain a dot '.' character.")
|
raise ValueError("'name' may not contain a dot '.' character.")
|
||||||
|
|
||||||
|
|
@ -282,19 +210,12 @@ class Blueprint(Scaffold):
|
||||||
|
|
||||||
def _check_setup_finished(self, f_name: str) -> None:
|
def _check_setup_finished(self, f_name: str) -> None:
|
||||||
if self._got_registered_once:
|
if self._got_registered_once:
|
||||||
import warnings
|
raise AssertionError(
|
||||||
|
f"The setup method '{f_name}' can no longer be called on the blueprint"
|
||||||
warnings.warn(
|
f" '{self.name}'. It has already been registered at least once, any"
|
||||||
f"The setup method '{f_name}' can no longer be called on"
|
" changes will not be applied consistently.\n"
|
||||||
f" the blueprint '{self.name}'. It has already been"
|
"Make sure all imports, decorators, functions, etc. needed to set up"
|
||||||
" registered at least once, any changes will not be"
|
" the blueprint are done before registering it."
|
||||||
" applied consistently.\n"
|
|
||||||
"Make sure all imports, decorators, functions, etc."
|
|
||||||
" needed to set up the blueprint are done before"
|
|
||||||
" registering it.\n"
|
|
||||||
"This warning will become an exception in Flask 2.3.",
|
|
||||||
UserWarning,
|
|
||||||
stacklevel=3,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@setupmethod
|
@setupmethod
|
||||||
|
|
@ -361,6 +282,10 @@ class Blueprint(Scaffold):
|
||||||
.. versionchanged:: 2.3
|
.. versionchanged:: 2.3
|
||||||
Nested blueprints now correctly apply subdomains.
|
Nested blueprints now correctly apply subdomains.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.1
|
||||||
|
Registering the same blueprint with the same name multiple
|
||||||
|
times is an error.
|
||||||
|
|
||||||
.. versionchanged:: 2.0.1
|
.. versionchanged:: 2.0.1
|
||||||
Nested blueprints are registered with their dotted name.
|
Nested blueprints are registered with their dotted name.
|
||||||
This allows different blueprints with the same name to be
|
This allows different blueprints with the same name to be
|
||||||
|
|
@ -371,10 +296,6 @@ class Blueprint(Scaffold):
|
||||||
name the blueprint is registered with. This allows the same
|
name the blueprint is registered with. This allows the same
|
||||||
blueprint to be registered multiple times with unique names
|
blueprint to be registered multiple times with unique names
|
||||||
for ``url_for``.
|
for ``url_for``.
|
||||||
|
|
||||||
.. versionchanged:: 2.0.1
|
|
||||||
Registering the same blueprint with the same name multiple
|
|
||||||
times is deprecated and will become an error in Flask 2.1.
|
|
||||||
"""
|
"""
|
||||||
name_prefix = options.get("name_prefix", "")
|
name_prefix = options.get("name_prefix", "")
|
||||||
self_name = options.get("name", self.name)
|
self_name = options.get("name", self.name)
|
||||||
|
|
@ -634,29 +555,6 @@ class Blueprint(Scaffold):
|
||||||
)
|
)
|
||||||
return f
|
return f
|
||||||
|
|
||||||
@setupmethod
|
|
||||||
def before_app_first_request(
|
|
||||||
self, f: T_before_first_request
|
|
||||||
) -> T_before_first_request:
|
|
||||||
"""Register a function to run before the first request to the application is
|
|
||||||
handled by the worker. Equivalent to :meth:`.Flask.before_first_request`.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Run setup code when creating
|
|
||||||
the application instead.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'before_app_first_request' is deprecated and will be"
|
|
||||||
" removed in Flask 2.3. Use 'record_once' instead to run"
|
|
||||||
" setup code when registering the blueprint.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
self.record_once(lambda s: s.app.before_first_request_funcs.append(f))
|
|
||||||
return f
|
|
||||||
|
|
||||||
@setupmethod
|
@setupmethod
|
||||||
def after_app_request(self, f: T_after_request) -> T_after_request:
|
def after_app_request(self, f: T_after_request) -> T_after_request:
|
||||||
"""Like :meth:`after_request`, but after every request, not only those handled
|
"""Like :meth:`after_request`, but after every request, not only those handled
|
||||||
|
|
|
||||||
|
|
@ -234,6 +234,7 @@ class Config(dict):
|
||||||
filename: str,
|
filename: str,
|
||||||
load: t.Callable[[t.IO[t.Any]], t.Mapping],
|
load: t.Callable[[t.IO[t.Any]], t.Mapping],
|
||||||
silent: bool = False,
|
silent: bool = False,
|
||||||
|
text: bool = True,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Update the values in the config from a file that is loaded
|
"""Update the values in the config from a file that is loaded
|
||||||
using the ``load`` parameter. The loaded data is passed to the
|
using the ``load`` parameter. The loaded data is passed to the
|
||||||
|
|
@ -244,8 +245,8 @@ class Config(dict):
|
||||||
import json
|
import json
|
||||||
app.config.from_file("config.json", load=json.load)
|
app.config.from_file("config.json", load=json.load)
|
||||||
|
|
||||||
import toml
|
import tomllib
|
||||||
app.config.from_file("config.toml", load=toml.load)
|
app.config.from_file("config.toml", load=tomllib.load, text=False)
|
||||||
|
|
||||||
:param filename: The path to the data file. This can be an
|
:param filename: The path to the data file. This can be an
|
||||||
absolute path or relative to the config root path.
|
absolute path or relative to the config root path.
|
||||||
|
|
@ -254,14 +255,18 @@ class Config(dict):
|
||||||
:type load: ``Callable[[Reader], Mapping]`` where ``Reader``
|
:type load: ``Callable[[Reader], Mapping]`` where ``Reader``
|
||||||
implements a ``read`` method.
|
implements a ``read`` method.
|
||||||
:param silent: Ignore the file if it doesn't exist.
|
:param silent: Ignore the file if it doesn't exist.
|
||||||
|
:param text: Open the file in text or binary mode.
|
||||||
:return: ``True`` if the file was loaded successfully.
|
:return: ``True`` if the file was loaded successfully.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.3
|
||||||
|
The ``text`` parameter was added.
|
||||||
|
|
||||||
.. versionadded:: 2.0
|
.. versionadded:: 2.0
|
||||||
"""
|
"""
|
||||||
filename = os.path.join(self.root_path, filename)
|
filename = os.path.join(self.root_path, filename)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(filename) as f:
|
with open(filename, "r" if text else "rb") as f:
|
||||||
obj = load(f)
|
obj = load(f)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
|
if silent and e.errno in (errno.ENOENT, errno.EISDIR):
|
||||||
|
|
|
||||||
|
|
@ -17,30 +17,17 @@ class _FakeStack:
|
||||||
self.name = name
|
self.name = name
|
||||||
self.cv = cv
|
self.cv = cv
|
||||||
|
|
||||||
def _warn(self):
|
@property
|
||||||
|
def top(self) -> t.Optional[t.Any]:
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
f"'_{self.name}_ctx_stack' is deprecated and will be"
|
f"'_{self.name}_ctx_stack' is deprecated and will be removed in Flask 2.4."
|
||||||
" removed in Flask 2.3. Use 'g' to store data, or"
|
f" Use 'g' to store data, or '{self.name}_ctx' to access the current"
|
||||||
f" '{self.name}_ctx' to access the current context.",
|
" context.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=3,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
def push(self, obj: t.Any) -> None:
|
|
||||||
self._warn()
|
|
||||||
self.cv.set(obj)
|
|
||||||
|
|
||||||
def pop(self) -> t.Any:
|
|
||||||
self._warn()
|
|
||||||
ctx = self.cv.get(None)
|
|
||||||
self.cv.set(None)
|
|
||||||
return ctx
|
|
||||||
|
|
||||||
@property
|
|
||||||
def top(self) -> t.Optional[t.Any]:
|
|
||||||
self._warn()
|
|
||||||
return self.cv.get(None)
|
return self.cv.get(None)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -88,7 +75,7 @@ def __getattr__(name: str) -> t.Any:
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"'_app_ctx_stack' is deprecated and will be removed in Flask 2.3.",
|
"'_app_ctx_stack' is deprecated and will be removed in Flask 2.4.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
|
|
@ -98,7 +85,7 @@ def __getattr__(name: str) -> t.Any:
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"'_request_ctx_stack' is deprecated and will be removed in Flask 2.3.",
|
"'_request_ctx_stack' is deprecated and will be removed in Flask 2.4.",
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
stacklevel=2,
|
stacklevel=2,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,45 +25,12 @@ if t.TYPE_CHECKING: # pragma: no cover
|
||||||
import typing_extensions as te
|
import typing_extensions as te
|
||||||
|
|
||||||
|
|
||||||
def get_env() -> str:
|
|
||||||
"""Get the environment the app is running in, indicated by the
|
|
||||||
:envvar:`FLASK_ENV` environment variable. The default is
|
|
||||||
``'production'``.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'FLASK_ENV' and 'get_env' are deprecated and will be removed"
|
|
||||||
" in Flask 2.3. Use 'FLASK_DEBUG' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return os.environ.get("FLASK_ENV") or "production"
|
|
||||||
|
|
||||||
|
|
||||||
def get_debug_flag() -> bool:
|
def get_debug_flag() -> bool:
|
||||||
"""Get whether debug mode should be enabled for the app, indicated by the
|
"""Get whether debug mode should be enabled for the app, indicated by the
|
||||||
:envvar:`FLASK_DEBUG` environment variable. The default is ``False``.
|
:envvar:`FLASK_DEBUG` environment variable. The default is ``False``.
|
||||||
"""
|
"""
|
||||||
val = os.environ.get("FLASK_DEBUG")
|
val = os.environ.get("FLASK_DEBUG")
|
||||||
|
return bool(val and val.lower() not in {"0", "false", "no"})
|
||||||
if not val:
|
|
||||||
env = os.environ.get("FLASK_ENV")
|
|
||||||
|
|
||||||
if env is not None:
|
|
||||||
print(
|
|
||||||
"'FLASK_ENV' is deprecated and will not be used in"
|
|
||||||
" Flask 2.3. Use 'FLASK_DEBUG' instead.",
|
|
||||||
file=sys.stderr,
|
|
||||||
)
|
|
||||||
return env == "development"
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
return val.lower() not in {"0", "false", "no"}
|
|
||||||
|
|
||||||
|
|
||||||
def get_load_dotenv(default: bool = True) -> bool:
|
def get_load_dotenv(default: bool = True) -> bool:
|
||||||
|
|
@ -646,6 +613,10 @@ class locked_cached_property(werkzeug.utils.cached_property):
|
||||||
:class:`werkzeug.utils.cached_property` except access uses a lock
|
:class:`werkzeug.utils.cached_property` except access uses a lock
|
||||||
for thread safety.
|
for thread safety.
|
||||||
|
|
||||||
|
.. deprecated:: 2.3
|
||||||
|
Will be removed in Flask 2.4. Use a lock inside the decorated function if
|
||||||
|
locking is needed.
|
||||||
|
|
||||||
.. versionchanged:: 2.0
|
.. versionchanged:: 2.0
|
||||||
Inherits from Werkzeug's ``cached_property`` (and ``property``).
|
Inherits from Werkzeug's ``cached_property`` (and ``property``).
|
||||||
"""
|
"""
|
||||||
|
|
@ -656,6 +627,14 @@ class locked_cached_property(werkzeug.utils.cached_property):
|
||||||
name: t.Optional[str] = None,
|
name: t.Optional[str] = None,
|
||||||
doc: t.Optional[str] = None,
|
doc: t.Optional[str] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"'locked_cached_property' is deprecated and will be removed in Flask 2.4."
|
||||||
|
" Use a lock inside the decorated function if locking is needed.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
super().__init__(fget, name=name, doc=doc)
|
super().__init__(fget, name=name, doc=doc)
|
||||||
self.lock = RLock()
|
self.lock = RLock()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,85 +3,14 @@ from __future__ import annotations
|
||||||
import json as _json
|
import json as _json
|
||||||
import typing as t
|
import typing as t
|
||||||
|
|
||||||
from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps
|
|
||||||
|
|
||||||
from ..globals import current_app
|
from ..globals import current_app
|
||||||
from .provider import _default
|
from .provider import _default
|
||||||
|
|
||||||
if t.TYPE_CHECKING: # pragma: no cover
|
if t.TYPE_CHECKING: # pragma: no cover
|
||||||
from ..app import Flask
|
|
||||||
from ..wrappers import Response
|
from ..wrappers import Response
|
||||||
|
|
||||||
|
|
||||||
class JSONEncoder(_json.JSONEncoder):
|
def dumps(obj: t.Any, **kwargs: t.Any) -> str:
|
||||||
"""The default JSON encoder. Handles extra types compared to the
|
|
||||||
built-in :class:`json.JSONEncoder`.
|
|
||||||
|
|
||||||
- :class:`datetime.datetime` and :class:`datetime.date` are
|
|
||||||
serialized to :rfc:`822` strings. This is the same as the HTTP
|
|
||||||
date format.
|
|
||||||
- :class:`decimal.Decimal` is serialized to a string.
|
|
||||||
- :class:`uuid.UUID` is serialized to a string.
|
|
||||||
- :class:`dataclasses.dataclass` is passed to
|
|
||||||
:func:`dataclasses.asdict`.
|
|
||||||
- :class:`~markupsafe.Markup` (or any object with a ``__html__``
|
|
||||||
method) will call the ``__html__`` method to get a string.
|
|
||||||
|
|
||||||
Assign a subclass of this to :attr:`flask.Flask.json_encoder` or
|
|
||||||
:attr:`flask.Blueprint.json_encoder` to override the default.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Use ``app.json`` instead.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'JSONEncoder' is deprecated and will be removed in"
|
|
||||||
" Flask 2.3. Use 'Flask.json' to provide an alternate"
|
|
||||||
" JSON implementation instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=3,
|
|
||||||
)
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
|
|
||||||
def default(self, o: t.Any) -> t.Any:
|
|
||||||
"""Convert ``o`` to a JSON serializable type. See
|
|
||||||
:meth:`json.JSONEncoder.default`. Python does not support
|
|
||||||
overriding how basic types like ``str`` or ``list`` are
|
|
||||||
serialized, they are handled before this method.
|
|
||||||
"""
|
|
||||||
return _default(o)
|
|
||||||
|
|
||||||
|
|
||||||
class JSONDecoder(_json.JSONDecoder):
|
|
||||||
"""The default JSON decoder.
|
|
||||||
|
|
||||||
This does not change any behavior from the built-in
|
|
||||||
:class:`json.JSONDecoder`.
|
|
||||||
|
|
||||||
Assign a subclass of this to :attr:`flask.Flask.json_decoder` or
|
|
||||||
:attr:`flask.Blueprint.json_decoder` to override the default.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. Use ``app.json`` instead.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, **kwargs) -> None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'JSONDecoder' is deprecated and will be removed in"
|
|
||||||
" Flask 2.3. Use 'Flask.json' to provide an alternate"
|
|
||||||
" JSON implementation instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=3,
|
|
||||||
)
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def dumps(obj: t.Any, *, app: Flask | None = None, **kwargs: t.Any) -> str:
|
|
||||||
"""Serialize data as JSON.
|
"""Serialize data as JSON.
|
||||||
|
|
||||||
If :data:`~flask.current_app` is available, it will use its
|
If :data:`~flask.current_app` is available, it will use its
|
||||||
|
|
@ -91,13 +20,13 @@ def dumps(obj: t.Any, *, app: Flask | None = None, **kwargs: t.Any) -> str:
|
||||||
:param obj: The data to serialize.
|
:param obj: The data to serialize.
|
||||||
:param kwargs: Arguments passed to the ``dumps`` implementation.
|
:param kwargs: Arguments passed to the ``dumps`` implementation.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.3
|
||||||
|
The ``app`` parameter was removed.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
.. versionchanged:: 2.2
|
||||||
Calls ``current_app.json.dumps``, allowing an app to override
|
Calls ``current_app.json.dumps``, allowing an app to override
|
||||||
the behavior.
|
the behavior.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
|
||||||
The ``app`` parameter will be removed in Flask 2.3.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.0.2
|
.. versionchanged:: 2.0.2
|
||||||
:class:`decimal.Decimal` is supported by converting to a string.
|
:class:`decimal.Decimal` is supported by converting to a string.
|
||||||
|
|
||||||
|
|
@ -108,28 +37,14 @@ def dumps(obj: t.Any, *, app: Flask | None = None, **kwargs: t.Any) -> str:
|
||||||
``app`` can be passed directly, rather than requiring an app
|
``app`` can be passed directly, rather than requiring an app
|
||||||
context for configuration.
|
context for configuration.
|
||||||
"""
|
"""
|
||||||
if app is not None:
|
if current_app:
|
||||||
import warnings
|
return current_app.json.dumps(obj, **kwargs)
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"The 'app' parameter is deprecated and will be removed in"
|
|
||||||
" Flask 2.3. Call 'app.json.dumps' directly instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
app = current_app
|
|
||||||
|
|
||||||
if app:
|
|
||||||
return app.json.dumps(obj, **kwargs)
|
|
||||||
|
|
||||||
kwargs.setdefault("default", _default)
|
kwargs.setdefault("default", _default)
|
||||||
return _json.dumps(obj, **kwargs)
|
return _json.dumps(obj, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def dump(
|
def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None:
|
||||||
obj: t.Any, fp: t.IO[str], *, app: Flask | None = None, **kwargs: t.Any
|
|
||||||
) -> None:
|
|
||||||
"""Serialize data as JSON and write to a file.
|
"""Serialize data as JSON and write to a file.
|
||||||
|
|
||||||
If :data:`~flask.current_app` is available, it will use its
|
If :data:`~flask.current_app` is available, it will use its
|
||||||
|
|
@ -141,37 +56,25 @@ def dump(
|
||||||
encoding to be valid JSON.
|
encoding to be valid JSON.
|
||||||
:param kwargs: Arguments passed to the ``dump`` implementation.
|
:param kwargs: Arguments passed to the ``dump`` implementation.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.3
|
||||||
|
The ``app`` parameter was removed.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
.. versionchanged:: 2.2
|
||||||
Calls ``current_app.json.dump``, allowing an app to override
|
Calls ``current_app.json.dump``, allowing an app to override
|
||||||
the behavior.
|
the behavior.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
|
||||||
The ``app`` parameter will be removed in Flask 2.3.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.0
|
.. versionchanged:: 2.0
|
||||||
Writing to a binary file, and the ``encoding`` argument, will be
|
Writing to a binary file, and the ``encoding`` argument, will be
|
||||||
removed in Flask 2.1.
|
removed in Flask 2.1.
|
||||||
"""
|
"""
|
||||||
if app is not None:
|
if current_app:
|
||||||
import warnings
|
current_app.json.dump(obj, fp, **kwargs)
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"The 'app' parameter is deprecated and will be removed in"
|
|
||||||
" Flask 2.3. Call 'app.json.dump' directly instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
app = current_app
|
|
||||||
|
|
||||||
if app:
|
|
||||||
app.json.dump(obj, fp, **kwargs)
|
|
||||||
else:
|
else:
|
||||||
kwargs.setdefault("default", _default)
|
kwargs.setdefault("default", _default)
|
||||||
_json.dump(obj, fp, **kwargs)
|
_json.dump(obj, fp, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def loads(s: str | bytes, *, app: Flask | None = None, **kwargs: t.Any) -> t.Any:
|
def loads(s: str | bytes, **kwargs: t.Any) -> t.Any:
|
||||||
"""Deserialize data as JSON.
|
"""Deserialize data as JSON.
|
||||||
|
|
||||||
If :data:`~flask.current_app` is available, it will use its
|
If :data:`~flask.current_app` is available, it will use its
|
||||||
|
|
@ -181,13 +84,13 @@ def loads(s: str | bytes, *, app: Flask | None = None, **kwargs: t.Any) -> t.Any
|
||||||
:param s: Text or UTF-8 bytes.
|
:param s: Text or UTF-8 bytes.
|
||||||
:param kwargs: Arguments passed to the ``loads`` implementation.
|
:param kwargs: Arguments passed to the ``loads`` implementation.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.3
|
||||||
|
The ``app`` parameter was removed.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
.. versionchanged:: 2.2
|
||||||
Calls ``current_app.json.loads``, allowing an app to override
|
Calls ``current_app.json.loads``, allowing an app to override
|
||||||
the behavior.
|
the behavior.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
|
||||||
The ``app`` parameter will be removed in Flask 2.3.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.0
|
.. versionchanged:: 2.0
|
||||||
``encoding`` will be removed in Flask 2.1. The data must be a
|
``encoding`` will be removed in Flask 2.1. The data must be a
|
||||||
string or UTF-8 bytes.
|
string or UTF-8 bytes.
|
||||||
|
|
@ -196,25 +99,13 @@ def loads(s: str | bytes, *, app: Flask | None = None, **kwargs: t.Any) -> t.Any
|
||||||
``app`` can be passed directly, rather than requiring an app
|
``app`` can be passed directly, rather than requiring an app
|
||||||
context for configuration.
|
context for configuration.
|
||||||
"""
|
"""
|
||||||
if app is not None:
|
if current_app:
|
||||||
import warnings
|
return current_app.json.loads(s, **kwargs)
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"The 'app' parameter is deprecated and will be removed in"
|
|
||||||
" Flask 2.3. Call 'app.json.loads' directly instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
app = current_app
|
|
||||||
|
|
||||||
if app:
|
|
||||||
return app.json.loads(s, **kwargs)
|
|
||||||
|
|
||||||
return _json.loads(s, **kwargs)
|
return _json.loads(s, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **kwargs: t.Any) -> t.Any:
|
def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any:
|
||||||
"""Deserialize data as JSON read from a file.
|
"""Deserialize data as JSON read from a file.
|
||||||
|
|
||||||
If :data:`~flask.current_app` is available, it will use its
|
If :data:`~flask.current_app` is available, it will use its
|
||||||
|
|
@ -224,6 +115,9 @@ def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **kwargs: t.Any) -> t.
|
||||||
:param fp: A file opened for reading text or UTF-8 bytes.
|
:param fp: A file opened for reading text or UTF-8 bytes.
|
||||||
:param kwargs: Arguments passed to the ``load`` implementation.
|
:param kwargs: Arguments passed to the ``load`` implementation.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.3
|
||||||
|
The ``app`` parameter was removed.
|
||||||
|
|
||||||
.. versionchanged:: 2.2
|
.. versionchanged:: 2.2
|
||||||
Calls ``current_app.json.load``, allowing an app to override
|
Calls ``current_app.json.load``, allowing an app to override
|
||||||
the behavior.
|
the behavior.
|
||||||
|
|
@ -235,78 +129,12 @@ def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **kwargs: t.Any) -> t.
|
||||||
``encoding`` will be removed in Flask 2.1. The file must be text
|
``encoding`` will be removed in Flask 2.1. The file must be text
|
||||||
mode, or binary mode with UTF-8 bytes.
|
mode, or binary mode with UTF-8 bytes.
|
||||||
"""
|
"""
|
||||||
if app is not None:
|
if current_app:
|
||||||
import warnings
|
return current_app.json.load(fp, **kwargs)
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"The 'app' parameter is deprecated and will be removed in"
|
|
||||||
" Flask 2.3. Call 'app.json.load' directly instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
app = current_app
|
|
||||||
|
|
||||||
if app:
|
|
||||||
return app.json.load(fp, **kwargs)
|
|
||||||
|
|
||||||
return _json.load(fp, **kwargs)
|
return _json.load(fp, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str:
|
|
||||||
"""Serialize an object to a string of JSON with :func:`dumps`, then
|
|
||||||
replace HTML-unsafe characters with Unicode escapes and mark the
|
|
||||||
result safe with :class:`~markupsafe.Markup`.
|
|
||||||
|
|
||||||
This is available in templates as the ``|tojson`` filter.
|
|
||||||
|
|
||||||
The returned string is safe to render in HTML documents and
|
|
||||||
``<script>`` tags. The exception is in HTML attributes that are
|
|
||||||
double quoted; either use single quotes or the ``|forceescape``
|
|
||||||
filter.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3. This is built-in to Jinja now.
|
|
||||||
|
|
||||||
.. versionchanged:: 2.0
|
|
||||||
Uses :func:`jinja2.utils.htmlsafe_json_dumps`. The returned
|
|
||||||
value is marked safe by wrapping in :class:`~markupsafe.Markup`.
|
|
||||||
|
|
||||||
.. versionchanged:: 0.10
|
|
||||||
Single quotes are escaped, making this safe to use in HTML,
|
|
||||||
``<script>`` tags, and single-quoted attributes without further
|
|
||||||
escaping.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'htmlsafe_dumps' is deprecated and will be removed in Flask"
|
|
||||||
" 2.3. Use 'jinja2.utils.htmlsafe_json_dumps' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
return _jinja_htmlsafe_dumps(obj, dumps=dumps, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def htmlsafe_dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None:
|
|
||||||
"""Serialize an object to JSON written to a file object, replacing
|
|
||||||
HTML-unsafe characters with Unicode escapes. See
|
|
||||||
:func:`htmlsafe_dumps` and :func:`dumps`.
|
|
||||||
|
|
||||||
.. deprecated:: 2.2
|
|
||||||
Will be removed in Flask 2.3.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"'htmlsafe_dump' is deprecated and will be removed in Flask"
|
|
||||||
" 2.3. Use 'jinja2.utils.htmlsafe_json_dumps' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
stacklevel=2,
|
|
||||||
)
|
|
||||||
fp.write(htmlsafe_dumps(obj, **kwargs))
|
|
||||||
|
|
||||||
|
|
||||||
def jsonify(*args: t.Any, **kwargs: t.Any) -> Response:
|
def jsonify(*args: t.Any, **kwargs: t.Any) -> Response:
|
||||||
"""Serialize the given arguments as JSON, and return a
|
"""Serialize the given arguments as JSON, and return a
|
||||||
:class:`~flask.Response` object with the ``application/json``
|
:class:`~flask.Response` object with the ``application/json``
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,6 @@ from datetime import date
|
||||||
|
|
||||||
from werkzeug.http import http_date
|
from werkzeug.http import http_date
|
||||||
|
|
||||||
from ..globals import request
|
|
||||||
|
|
||||||
if t.TYPE_CHECKING: # pragma: no cover
|
if t.TYPE_CHECKING: # pragma: no cover
|
||||||
from ..app import Flask
|
from ..app import Flask
|
||||||
from ..wrappers import Response
|
from ..wrappers import Response
|
||||||
|
|
@ -176,57 +174,9 @@ class DefaultJSONProvider(JSONProvider):
|
||||||
:param obj: The data to serialize.
|
:param obj: The data to serialize.
|
||||||
:param kwargs: Passed to :func:`json.dumps`.
|
:param kwargs: Passed to :func:`json.dumps`.
|
||||||
"""
|
"""
|
||||||
cls = self._app._json_encoder
|
|
||||||
bp = self._app.blueprints.get(request.blueprint) if request else None
|
|
||||||
|
|
||||||
if bp is not None and bp._json_encoder is not None:
|
|
||||||
cls = bp._json_encoder
|
|
||||||
|
|
||||||
if cls is not None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"Setting 'json_encoder' on the app or a blueprint is"
|
|
||||||
" deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
kwargs.setdefault("cls", cls)
|
|
||||||
|
|
||||||
if "default" not in cls.__dict__:
|
|
||||||
kwargs.setdefault("default", self.default)
|
kwargs.setdefault("default", self.default)
|
||||||
else:
|
kwargs.setdefault("ensure_ascii", self.ensure_ascii)
|
||||||
kwargs.setdefault("default", self.default)
|
kwargs.setdefault("sort_keys", self.sort_keys)
|
||||||
|
|
||||||
ensure_ascii = self._app.config["JSON_AS_ASCII"]
|
|
||||||
sort_keys = self._app.config["JSON_SORT_KEYS"]
|
|
||||||
|
|
||||||
if ensure_ascii is not None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"The 'JSON_AS_ASCII' config key is deprecated and will"
|
|
||||||
" be removed in Flask 2.3. Set 'app.json.ensure_ascii'"
|
|
||||||
" instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
ensure_ascii = self.ensure_ascii
|
|
||||||
|
|
||||||
if sort_keys is not None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"The 'JSON_SORT_KEYS' config key is deprecated and will"
|
|
||||||
" be removed in Flask 2.3. Set 'app.json.sort_keys'"
|
|
||||||
" instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
sort_keys = self.sort_keys
|
|
||||||
|
|
||||||
kwargs.setdefault("ensure_ascii", ensure_ascii)
|
|
||||||
kwargs.setdefault("sort_keys", sort_keys)
|
|
||||||
return json.dumps(obj, **kwargs)
|
return json.dumps(obj, **kwargs)
|
||||||
|
|
||||||
def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any:
|
def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any:
|
||||||
|
|
@ -235,23 +185,6 @@ class DefaultJSONProvider(JSONProvider):
|
||||||
:param s: Text or UTF-8 bytes.
|
:param s: Text or UTF-8 bytes.
|
||||||
:param kwargs: Passed to :func:`json.loads`.
|
:param kwargs: Passed to :func:`json.loads`.
|
||||||
"""
|
"""
|
||||||
cls = self._app._json_decoder
|
|
||||||
bp = self._app.blueprints.get(request.blueprint) if request else None
|
|
||||||
|
|
||||||
if bp is not None and bp._json_decoder is not None:
|
|
||||||
cls = bp._json_decoder
|
|
||||||
|
|
||||||
if cls is not None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"Setting 'json_decoder' on the app or a blueprint is"
|
|
||||||
" deprecated and will be removed in Flask 2.3."
|
|
||||||
" Customize 'app.json' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
kwargs.setdefault("cls", cls)
|
|
||||||
|
|
||||||
return json.loads(s, **kwargs)
|
return json.loads(s, **kwargs)
|
||||||
|
|
||||||
def response(self, *args: t.Any, **kwargs: t.Any) -> Response:
|
def response(self, *args: t.Any, **kwargs: t.Any) -> Response:
|
||||||
|
|
@ -272,39 +205,12 @@ class DefaultJSONProvider(JSONProvider):
|
||||||
"""
|
"""
|
||||||
obj = self._prepare_response_obj(args, kwargs)
|
obj = self._prepare_response_obj(args, kwargs)
|
||||||
dump_args: t.Dict[str, t.Any] = {}
|
dump_args: t.Dict[str, t.Any] = {}
|
||||||
pretty = self._app.config["JSONIFY_PRETTYPRINT_REGULAR"]
|
|
||||||
mimetype = self._app.config["JSONIFY_MIMETYPE"]
|
|
||||||
|
|
||||||
if pretty is not None:
|
if (self.compact is None and self._app.debug) or self.compact is False:
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"The 'JSONIFY_PRETTYPRINT_REGULAR' config key is"
|
|
||||||
" deprecated and will be removed in Flask 2.3. Set"
|
|
||||||
" 'app.json.compact' instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
compact: bool | None = not pretty
|
|
||||||
else:
|
|
||||||
compact = self.compact
|
|
||||||
|
|
||||||
if (compact is None and self._app.debug) or compact is False:
|
|
||||||
dump_args.setdefault("indent", 2)
|
dump_args.setdefault("indent", 2)
|
||||||
else:
|
else:
|
||||||
dump_args.setdefault("separators", (",", ":"))
|
dump_args.setdefault("separators", (",", ":"))
|
||||||
|
|
||||||
if mimetype is not None:
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
warnings.warn(
|
|
||||||
"The 'JSONIFY_MIMETYPE' config key is deprecated and"
|
|
||||||
" will be removed in Flask 2.3. Set 'app.json.mimetype'"
|
|
||||||
" instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
mimetype = self.mimetype
|
|
||||||
|
|
||||||
return self._app.response_class(
|
return self._app.response_class(
|
||||||
f"{self.dumps(obj, **dump_args)}\n", mimetype=mimetype
|
f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import pkgutil
|
import pkgutil
|
||||||
|
|
@ -12,12 +11,12 @@ from functools import update_wrapper
|
||||||
from jinja2 import FileSystemLoader
|
from jinja2 import FileSystemLoader
|
||||||
from werkzeug.exceptions import default_exceptions
|
from werkzeug.exceptions import default_exceptions
|
||||||
from werkzeug.exceptions import HTTPException
|
from werkzeug.exceptions import HTTPException
|
||||||
|
from werkzeug.utils import cached_property
|
||||||
|
|
||||||
from . import typing as ft
|
from . import typing as ft
|
||||||
from .cli import AppGroup
|
from .cli import AppGroup
|
||||||
from .globals import current_app
|
from .globals import current_app
|
||||||
from .helpers import get_root_path
|
from .helpers import get_root_path
|
||||||
from .helpers import locked_cached_property
|
|
||||||
from .helpers import send_from_directory
|
from .helpers import send_from_directory
|
||||||
from .templating import _default_template_ctx_processor
|
from .templating import _default_template_ctx_processor
|
||||||
|
|
||||||
|
|
@ -74,20 +73,6 @@ class Scaffold:
|
||||||
_static_folder: t.Optional[str] = None
|
_static_folder: t.Optional[str] = None
|
||||||
_static_url_path: t.Optional[str] = None
|
_static_url_path: t.Optional[str] = None
|
||||||
|
|
||||||
#: JSON encoder class used by :func:`flask.json.dumps`. If a
|
|
||||||
#: blueprint sets this, it will be used instead of the app's value.
|
|
||||||
#:
|
|
||||||
#: .. deprecated:: 2.2
|
|
||||||
#: Will be removed in Flask 2.3.
|
|
||||||
json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None
|
|
||||||
|
|
||||||
#: JSON decoder class used by :func:`flask.json.loads`. If a
|
|
||||||
#: blueprint sets this, it will be used instead of the app's value.
|
|
||||||
#:
|
|
||||||
#: .. deprecated:: 2.2
|
|
||||||
#: Will be removed in Flask 2.3.
|
|
||||||
json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
import_name: str,
|
import_name: str,
|
||||||
|
|
@ -332,7 +317,7 @@ class Scaffold:
|
||||||
t.cast(str, self.static_folder), filename, max_age=max_age
|
t.cast(str, self.static_folder), filename, max_age=max_age
|
||||||
)
|
)
|
||||||
|
|
||||||
@locked_cached_property
|
@cached_property
|
||||||
def jinja_loader(self) -> t.Optional[FileSystemLoader]:
|
def jinja_loader(self) -> t.Optional[FileSystemLoader]:
|
||||||
"""The Jinja loader for this object's templates. By default this
|
"""The Jinja loader for this object's templates. By default this
|
||||||
is a class :class:`jinja2.loaders.FileSystemLoader` to
|
is a class :class:`jinja2.loaders.FileSystemLoader` to
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ from contextlib import contextmanager
|
||||||
from contextlib import ExitStack
|
from contextlib import ExitStack
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import werkzeug.test
|
import werkzeug.test
|
||||||
from click.testing import CliRunner
|
from click.testing import CliRunner
|
||||||
from werkzeug.test import Client
|
from werkzeug.test import Client
|
||||||
from werkzeug.urls import url_parse
|
|
||||||
from werkzeug.wrappers import Request as BaseRequest
|
from werkzeug.wrappers import Request as BaseRequest
|
||||||
|
|
||||||
from .cli import ScriptInfo
|
from .cli import ScriptInfo
|
||||||
|
|
@ -68,7 +68,7 @@ class EnvironBuilder(werkzeug.test.EnvironBuilder):
|
||||||
if url_scheme is None:
|
if url_scheme is None:
|
||||||
url_scheme = app.config["PREFERRED_URL_SCHEME"]
|
url_scheme = app.config["PREFERRED_URL_SCHEME"]
|
||||||
|
|
||||||
url = url_parse(path)
|
url = urlsplit(path)
|
||||||
base_url = (
|
base_url = (
|
||||||
f"{url.scheme or url_scheme}://{url.netloc or http_host}"
|
f"{url.scheme or url_scheme}://{url.netloc or http_host}"
|
||||||
f"/{app_root.lstrip('/')}"
|
f"/{app_root.lstrip('/')}"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ def _standard_os_environ():
|
||||||
out = (
|
out = (
|
||||||
(os.environ, "FLASK_ENV_FILE", monkeypatch.notset),
|
(os.environ, "FLASK_ENV_FILE", monkeypatch.notset),
|
||||||
(os.environ, "FLASK_APP", monkeypatch.notset),
|
(os.environ, "FLASK_APP", monkeypatch.notset),
|
||||||
(os.environ, "FLASK_ENV", monkeypatch.notset),
|
|
||||||
(os.environ, "FLASK_DEBUG", monkeypatch.notset),
|
(os.environ, "FLASK_DEBUG", monkeypatch.notset),
|
||||||
(os.environ, "FLASK_RUN_FROM_CLI", monkeypatch.notset),
|
(os.environ, "FLASK_RUN_FROM_CLI", monkeypatch.notset),
|
||||||
(os.environ, "WERKZEUG_RUN_MAIN", monkeypatch.notset),
|
(os.environ, "WERKZEUG_RUN_MAIN", monkeypatch.notset),
|
||||||
|
|
|
||||||
2
tests/static/config.toml
Normal file
2
tests/static/config.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
TEST_KEY="foo"
|
||||||
|
SECRET_KEY="config"
|
||||||
|
|
@ -95,7 +95,6 @@ def test_async_error_handler(path, async_app):
|
||||||
|
|
||||||
|
|
||||||
def test_async_before_after_request():
|
def test_async_before_after_request():
|
||||||
app_first_called = False
|
|
||||||
app_before_called = False
|
app_before_called = False
|
||||||
app_after_called = False
|
app_after_called = False
|
||||||
bp_before_called = False
|
bp_before_called = False
|
||||||
|
|
@ -107,13 +106,6 @@ def test_async_before_after_request():
|
||||||
def index():
|
def index():
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
with pytest.deprecated_call():
|
|
||||||
|
|
||||||
@app.before_first_request
|
|
||||||
async def before_first():
|
|
||||||
nonlocal app_first_called
|
|
||||||
app_first_called = True
|
|
||||||
|
|
||||||
@app.before_request
|
@app.before_request
|
||||||
async def before():
|
async def before():
|
||||||
nonlocal app_before_called
|
nonlocal app_before_called
|
||||||
|
|
@ -146,7 +138,6 @@ def test_async_before_after_request():
|
||||||
|
|
||||||
test_client = app.test_client()
|
test_client = app.test_client()
|
||||||
test_client.get("/")
|
test_client.get("/")
|
||||||
assert app_first_called
|
|
||||||
assert app_before_called
|
assert app_before_called
|
||||||
assert app_after_called
|
assert app_after_called
|
||||||
test_client.get("/bp/")
|
test_client.get("/bp/")
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
import gc
|
import gc
|
||||||
import re
|
import re
|
||||||
import time
|
|
||||||
import uuid
|
import uuid
|
||||||
import warnings
|
import warnings
|
||||||
import weakref
|
import weakref
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timezone
|
from datetime import timezone
|
||||||
from platform import python_implementation
|
from platform import python_implementation
|
||||||
from threading import Thread
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import werkzeug.serving
|
import werkzeug.serving
|
||||||
|
from markupsafe import Markup
|
||||||
from werkzeug.exceptions import BadRequest
|
from werkzeug.exceptions import BadRequest
|
||||||
from werkzeug.exceptions import Forbidden
|
from werkzeug.exceptions import Forbidden
|
||||||
from werkzeug.exceptions import NotFound
|
from werkzeug.exceptions import NotFound
|
||||||
|
|
@ -474,7 +473,7 @@ def test_session_special_types(app, client):
|
||||||
def dump_session_contents():
|
def dump_session_contents():
|
||||||
flask.session["t"] = (1, 2, 3)
|
flask.session["t"] = (1, 2, 3)
|
||||||
flask.session["b"] = b"\xff"
|
flask.session["b"] = b"\xff"
|
||||||
flask.session["m"] = flask.Markup("<html>")
|
flask.session["m"] = Markup("<html>")
|
||||||
flask.session["u"] = the_uuid
|
flask.session["u"] = the_uuid
|
||||||
flask.session["d"] = now
|
flask.session["d"] = now
|
||||||
flask.session["t_tag"] = {" t": "not-a-tuple"}
|
flask.session["t_tag"] = {" t": "not-a-tuple"}
|
||||||
|
|
@ -488,8 +487,8 @@ def test_session_special_types(app, client):
|
||||||
assert s["t"] == (1, 2, 3)
|
assert s["t"] == (1, 2, 3)
|
||||||
assert type(s["b"]) == bytes
|
assert type(s["b"]) == bytes
|
||||||
assert s["b"] == b"\xff"
|
assert s["b"] == b"\xff"
|
||||||
assert type(s["m"]) == flask.Markup
|
assert type(s["m"]) == Markup
|
||||||
assert s["m"] == flask.Markup("<html>")
|
assert s["m"] == Markup("<html>")
|
||||||
assert s["u"] == the_uuid
|
assert s["u"] == the_uuid
|
||||||
assert s["d"] == now
|
assert s["d"] == now
|
||||||
assert s["t_tag"] == {" t": "not-a-tuple"}
|
assert s["t_tag"] == {" t": "not-a-tuple"}
|
||||||
|
|
@ -613,7 +612,7 @@ def test_extended_flashing(app):
|
||||||
def index():
|
def index():
|
||||||
flask.flash("Hello World")
|
flask.flash("Hello World")
|
||||||
flask.flash("Hello World", "error")
|
flask.flash("Hello World", "error")
|
||||||
flask.flash(flask.Markup("<em>Testing</em>"), "warning")
|
flask.flash(Markup("<em>Testing</em>"), "warning")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@app.route("/test/")
|
@app.route("/test/")
|
||||||
|
|
@ -622,7 +621,7 @@ def test_extended_flashing(app):
|
||||||
assert list(messages) == [
|
assert list(messages) == [
|
||||||
"Hello World",
|
"Hello World",
|
||||||
"Hello World",
|
"Hello World",
|
||||||
flask.Markup("<em>Testing</em>"),
|
Markup("<em>Testing</em>"),
|
||||||
]
|
]
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
@ -633,7 +632,7 @@ def test_extended_flashing(app):
|
||||||
assert list(messages) == [
|
assert list(messages) == [
|
||||||
("message", "Hello World"),
|
("message", "Hello World"),
|
||||||
("error", "Hello World"),
|
("error", "Hello World"),
|
||||||
("warning", flask.Markup("<em>Testing</em>")),
|
("warning", Markup("<em>Testing</em>")),
|
||||||
]
|
]
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
@ -652,7 +651,7 @@ def test_extended_flashing(app):
|
||||||
)
|
)
|
||||||
assert list(messages) == [
|
assert list(messages) == [
|
||||||
("message", "Hello World"),
|
("message", "Hello World"),
|
||||||
("warning", flask.Markup("<em>Testing</em>")),
|
("warning", Markup("<em>Testing</em>")),
|
||||||
]
|
]
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
@ -661,7 +660,7 @@ def test_extended_flashing(app):
|
||||||
messages = flask.get_flashed_messages(category_filter=["message", "warning"])
|
messages = flask.get_flashed_messages(category_filter=["message", "warning"])
|
||||||
assert len(messages) == 2
|
assert len(messages) == 2
|
||||||
assert messages[0] == "Hello World"
|
assert messages[0] == "Hello World"
|
||||||
assert messages[1] == flask.Markup("<em>Testing</em>")
|
assert messages[1] == Markup("<em>Testing</em>")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
# Create new test client on each test to clean flashed messages.
|
# Create new test client on each test to clean flashed messages.
|
||||||
|
|
@ -1658,7 +1657,6 @@ def test_no_setup_after_first_request(app, client):
|
||||||
def index():
|
def index():
|
||||||
return "Awesome"
|
return "Awesome"
|
||||||
|
|
||||||
assert not app.got_first_request
|
|
||||||
assert client.get("/").data == b"Awesome"
|
assert client.get("/").data == b"Awesome"
|
||||||
|
|
||||||
with pytest.raises(AssertionError) as exc_info:
|
with pytest.raises(AssertionError) as exc_info:
|
||||||
|
|
@ -1667,43 +1665,6 @@ def test_no_setup_after_first_request(app, client):
|
||||||
assert "setup method 'add_url_rule'" in str(exc_info.value)
|
assert "setup method 'add_url_rule'" in str(exc_info.value)
|
||||||
|
|
||||||
|
|
||||||
def test_before_first_request_functions(app, client):
|
|
||||||
got = []
|
|
||||||
|
|
||||||
with pytest.deprecated_call():
|
|
||||||
|
|
||||||
@app.before_first_request
|
|
||||||
def foo():
|
|
||||||
got.append(42)
|
|
||||||
|
|
||||||
client.get("/")
|
|
||||||
assert got == [42]
|
|
||||||
client.get("/")
|
|
||||||
assert got == [42]
|
|
||||||
assert app.got_first_request
|
|
||||||
|
|
||||||
|
|
||||||
def test_before_first_request_functions_concurrent(app, client):
|
|
||||||
got = []
|
|
||||||
|
|
||||||
with pytest.deprecated_call():
|
|
||||||
|
|
||||||
@app.before_first_request
|
|
||||||
def foo():
|
|
||||||
time.sleep(0.2)
|
|
||||||
got.append(42)
|
|
||||||
|
|
||||||
def get_and_assert():
|
|
||||||
client.get("/")
|
|
||||||
assert got == [42]
|
|
||||||
|
|
||||||
t = Thread(target=get_and_assert)
|
|
||||||
t.start()
|
|
||||||
get_and_assert()
|
|
||||||
t.join()
|
|
||||||
assert app.got_first_request
|
|
||||||
|
|
||||||
|
|
||||||
def test_routing_redirect_debugging(monkeypatch, app, client):
|
def test_routing_redirect_debugging(monkeypatch, app, client):
|
||||||
app.config["DEBUG"] = True
|
app.config["DEBUG"] = True
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,11 @@ def test_dotted_name_not_allowed(app, client):
|
||||||
flask.Blueprint("app.ui", __name__)
|
flask.Blueprint("app.ui", __name__)
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty_name_not_allowed(app, client):
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
flask.Blueprint("", __name__)
|
||||||
|
|
||||||
|
|
||||||
def test_dotted_names_from_app(app, client):
|
def test_dotted_names_from_app(app, client):
|
||||||
test = flask.Blueprint("test", __name__)
|
test = flask.Blueprint("test", __name__)
|
||||||
|
|
||||||
|
|
@ -722,12 +727,6 @@ def test_app_request_processing(app, client):
|
||||||
bp = flask.Blueprint("bp", __name__)
|
bp = flask.Blueprint("bp", __name__)
|
||||||
evts = []
|
evts = []
|
||||||
|
|
||||||
with pytest.deprecated_call():
|
|
||||||
|
|
||||||
@bp.before_app_first_request
|
|
||||||
def before_first_request():
|
|
||||||
evts.append("first")
|
|
||||||
|
|
||||||
@bp.before_app_request
|
@bp.before_app_request
|
||||||
def before_app():
|
def before_app():
|
||||||
evts.append("before")
|
evts.append("before")
|
||||||
|
|
@ -755,12 +754,12 @@ def test_app_request_processing(app, client):
|
||||||
# first request
|
# first request
|
||||||
resp = client.get("/").data
|
resp = client.get("/").data
|
||||||
assert resp == b"request|after"
|
assert resp == b"request|after"
|
||||||
assert evts == ["first", "before", "after", "teardown"]
|
assert evts == ["before", "after", "teardown"]
|
||||||
|
|
||||||
# second request
|
# second request
|
||||||
resp = client.get("/").data
|
resp = client.get("/").data
|
||||||
assert resp == b"request|after"
|
assert resp == b"request|after"
|
||||||
assert evts == ["first"] + ["before", "after", "teardown"] * 2
|
assert evts == ["before", "after", "teardown"] * 2
|
||||||
|
|
||||||
|
|
||||||
def test_app_url_processors(app, client):
|
def test_app_url_processors(app, client):
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import pytest
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
|
|
||||||
|
|
||||||
# config keys used for the TestConfig
|
# config keys used for the TestConfig
|
||||||
TEST_KEY = "foo"
|
TEST_KEY = "foo"
|
||||||
SECRET_KEY = "config"
|
SECRET_KEY = "config"
|
||||||
|
|
@ -30,13 +29,23 @@ def test_config_from_object():
|
||||||
common_object_test(app)
|
common_object_test(app)
|
||||||
|
|
||||||
|
|
||||||
def test_config_from_file():
|
def test_config_from_file_json():
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
app.config.from_file(os.path.join(current_dir, "static", "config.json"), json.load)
|
app.config.from_file(os.path.join(current_dir, "static", "config.json"), json.load)
|
||||||
common_object_test(app)
|
common_object_test(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_from_file_toml():
|
||||||
|
tomllib = pytest.importorskip("tomllib", reason="tomllib added in 3.11")
|
||||||
|
app = flask.Flask(__name__)
|
||||||
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
app.config.from_file(
|
||||||
|
os.path.join(current_dir, "static", "config.toml"), tomllib.load, text=False
|
||||||
|
)
|
||||||
|
common_object_test(app)
|
||||||
|
|
||||||
|
|
||||||
def test_from_prefixed_env(monkeypatch):
|
def test_from_prefixed_env(monkeypatch):
|
||||||
monkeypatch.setenv("FLASK_STRING", "value")
|
monkeypatch.setenv("FLASK_STRING", "value")
|
||||||
monkeypatch.setenv("FLASK_BOOL", "true")
|
monkeypatch.setenv("FLASK_BOOL", "true")
|
||||||
|
|
|
||||||
|
|
@ -302,24 +302,18 @@ class TestStreaming:
|
||||||
|
|
||||||
class TestHelpers:
|
class TestHelpers:
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"debug, expected_flag, expected_default_flag",
|
("debug", "expect"),
|
||||||
[
|
[
|
||||||
("", False, False),
|
("", False),
|
||||||
("0", False, False),
|
("0", False),
|
||||||
("False", False, False),
|
("False", False),
|
||||||
("No", False, False),
|
("No", False),
|
||||||
("True", True, True),
|
("True", True),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_get_debug_flag(
|
def test_get_debug_flag(self, monkeypatch, debug, expect):
|
||||||
self, monkeypatch, debug, expected_flag, expected_default_flag
|
|
||||||
):
|
|
||||||
monkeypatch.setenv("FLASK_DEBUG", debug)
|
monkeypatch.setenv("FLASK_DEBUG", debug)
|
||||||
if expected_flag is None:
|
assert get_debug_flag() == expect
|
||||||
assert get_debug_flag() is None
|
|
||||||
else:
|
|
||||||
assert get_debug_flag() == expected_flag
|
|
||||||
assert get_debug_flag() == expected_default_flag
|
|
||||||
|
|
||||||
def test_make_response(self):
|
def test_make_response(self):
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ from datetime import timezone
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from markupsafe import Markup
|
||||||
|
|
||||||
from flask import Markup
|
|
||||||
from flask.json.tag import JSONTag
|
from flask.json.tag import JSONTag
|
||||||
from flask.json.tag import TaggedJSONSerializer
|
from flask.json.tag import TaggedJSONSerializer
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import logging
|
||||||
import pytest
|
import pytest
|
||||||
import werkzeug.serving
|
import werkzeug.serving
|
||||||
from jinja2 import TemplateNotFound
|
from jinja2 import TemplateNotFound
|
||||||
|
from markupsafe import Markup
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
|
|
||||||
|
|
@ -73,7 +74,7 @@ def test_escaping(app, client):
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"escaping_template.html", text=text, html=flask.Markup(text)
|
"escaping_template.html", text=text, html=Markup(text)
|
||||||
)
|
)
|
||||||
|
|
||||||
lines = client.get("/").data.splitlines()
|
lines = client.get("/").data.splitlines()
|
||||||
|
|
@ -93,7 +94,7 @@ def test_no_escaping(app, client):
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"non_escaping_template.txt", text=text, html=flask.Markup(text)
|
"non_escaping_template.txt", text=text, html=Markup(text)
|
||||||
)
|
)
|
||||||
|
|
||||||
lines = client.get("/").data.splitlines()
|
lines = client.get("/").data.splitlines()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue