Merge branch 'stable'
pre-commit / main (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (3.10) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (3.11) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (3.12) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (3.13) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (3.9) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (Development Versions, 3.9, py-dev) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (Mac, macos-latest, 3.12) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (Minimum Versions, 3.12, py-min) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (PyPy, pypy-3.10, pypy310) (push) Has been cancelled Details
Tests / ${{ matrix.name || matrix.python }} (Windows, windows-latest, 3.12) (push) Has been cancelled Details
Tests / typing (push) Has been cancelled Details
Lock inactive closed issues / lock (push) Has been cancelled Details

This commit is contained in:
David Lord 2025-03-30 13:17:17 -07:00
commit b78b5a210b
No known key found for this signature in database
GPG Key ID: 43368A7AA8CC5926
21 changed files with 89 additions and 112 deletions

View File

@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with: with:
python-version: 3.x python-version: 3.x
- uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1

View File

@ -10,7 +10,7 @@ jobs:
hash: ${{ steps.hash.outputs.hash }} hash: ${{ steps.hash.outputs.hash }}
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with: with:
python-version: '3.x' python-version: '3.x'
cache: pip cache: pip
@ -23,7 +23,7 @@ jobs:
- name: generate hash - name: generate hash
id: hash id: hash
run: cd dist && echo "hash=$(sha256sum * | base64 -w0)" >> $GITHUB_OUTPUT run: cd dist && echo "hash=$(sha256sum * | base64 -w0)" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with: with:
path: ./dist path: ./dist
provenance: provenance:
@ -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@v2.0.0 uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
with: with:
base64-subjects: ${{ needs.build.outputs.hash }} base64-subjects: ${{ needs.build.outputs.hash }}
create-release: create-release:
@ -44,7 +44,7 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
- name: create release - name: create release
run: > run: >
gh release create --draft --repo ${{ github.repository }} gh release create --draft --repo ${{ github.repository }}
@ -63,7 +63,7 @@ jobs:
permissions: permissions:
id-token: write id-token: write
steps: steps:
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1
- uses: pypa/gh-action-pypi-publish@15c56dba361d8335944d31a2ecd17d700fc7bcbc # v1.12.2 - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
with: with:
packages-dir: artifact/ packages-dir: artifact/

View File

@ -25,7 +25,7 @@ jobs:
- {name: Development Versions, python: '3.9', tox: py-dev} - {name: Development Versions, python: '3.9', tox: py-dev}
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
allow-prereleases: true allow-prereleases: true
@ -37,13 +37,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 - uses: actions/setup-python@8d9ed9ac5c53483de85588cdf95a591a75ab9f55 # v5.5.0
with: with:
python-version: '3.x' python-version: '3.x'
cache: pip cache: pip
cache-dependency-path: requirements*/*.txt cache-dependency-path: requirements*/*.txt
- name: cache mypy - name: cache mypy
uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with: with:
path: ./.mypy_cache path: ./.mypy_cache
key: mypy|${{ hashFiles('pyproject.toml') }} key: mypy|${{ hashFiles('pyproject.toml') }}

View File

@ -1,6 +1,6 @@
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.7.3 rev: v0.11.2
hooks: hooks:
- id: ruff - id: ruff
- id: ruff-format - id: ruff-format

View File

@ -9,5 +9,6 @@ python:
- method: pip - method: pip
path: . path: .
sphinx: sphinx:
configuration: docs/conf.py
builder: dirhtml builder: dirhtml
fail_on_warning: true fail_on_warning: true

View File

@ -12,6 +12,11 @@ Version 3.1.1
Unreleased Unreleased
- Fix type hint for `cli_runner.invoke`. :issue:`5645` - Fix type hint for `cli_runner.invoke`. :issue:`5645`
- ``flask --help`` loads the app and plugins first to make sure all commands
are shown. :issue:5673`
- Mark sans-io base class as being able to handle views that return
``AsyncIterable``. This is not accurate for Flask, but makes typing easier
for Quart. :pr:`5659`
Version 3.1.0 Version 3.1.0
@ -113,6 +118,7 @@ Released 2023-05-01
- Set ``Vary: Cookie`` header when the session is accessed, modified, or refreshed. - Set ``Vary: Cookie`` header when the session is accessed, modified, or refreshed.
- Update Werkzeug requirement to >=2.3.3 to apply recent bug fixes. - Update Werkzeug requirement to >=2.3.3 to apply recent bug fixes.
:ghsa:`m2qf-hxjv-5gpq`
Version 2.3.1 Version 2.3.1

View File

@ -26,6 +26,7 @@ autodoc_preserve_defaults = True
extlinks = { extlinks = {
"issue": ("https://github.com/pallets/flask/issues/%s", "#%s"), "issue": ("https://github.com/pallets/flask/issues/%s", "#%s"),
"pr": ("https://github.com/pallets/flask/pull/%s", "#%s"), "pr": ("https://github.com/pallets/flask/pull/%s", "#%s"),
"ghsa": ("https://github.com/pallets/flask/security/advisories/GHSA-%s", "GHSA-%s"),
} }
intersphinx_mapping = { intersphinx_mapping = {
"python": ("https://docs.python.org/3/", None), "python": ("https://docs.python.org/3/", None),

View File

@ -99,9 +99,9 @@ to the factory like this:
.. code-block:: text .. code-block:: text
$ flask --app hello:create_app(local_auth=True) run $ flask --app 'hello:create_app(local_auth=True)' run
Then the ``create_app`` factory in ``myapp`` is called with the keyword Then the ``create_app`` factory in ``hello`` is called with the keyword
argument ``local_auth=True``. See :doc:`/cli` for more detail. argument ``local_auth=True``. See :doc:`/cli` for more detail.
Factory Improvements Factory Improvements

View File

@ -24,8 +24,11 @@ the root path of the domain you either need to configure the web server to
serve the icon at the root or if you can't do that you're out of luck. If serve the icon at the root or if you can't do that you're out of luck. If
however your application is the root you can simply route a redirect:: however your application is the root you can simply route a redirect::
app.add_url_rule('/favicon.ico', app.add_url_rule(
redirect_to=url_for('static', filename='favicon.ico')) "/favicon.ico",
endpoint="favicon",
redirect_to=url_for("static", filename="favicon.ico"),
)
If you want to save the extra redirect request you can also write a view If you want to save the extra redirect request you can also write a view
using :func:`~flask.send_from_directory`:: using :func:`~flask.send_from_directory`::

View File

@ -80,7 +80,7 @@ Queries
Use the class ``objects`` attribute to make queries. A keyword argument Use the class ``objects`` attribute to make queries. A keyword argument
looks for an equal value on the field. :: looks for an equal value on the field. ::
bttf = Movies.objects(title="Back To The Future").get_or_404() bttf = Movie.objects(title="Back To The Future").get_or_404()
Query operators may be used by concatenating them with the field name Query operators may be used by concatenating them with the field name
using a double-underscore. ``objects``, and queries returned by using a double-underscore. ``objects``, and queries returned by

View File

@ -269,19 +269,6 @@ values (or any values that need secure signatures).
.. _samesite_support: https://caniuse.com/#feat=same-site-cookie-attribute .. _samesite_support: https://caniuse.com/#feat=same-site-cookie-attribute
HTTP Public Key Pinning (HPKP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This tells the browser to authenticate with the server using only the specific
certificate key to prevent MITM attacks.
.. warning::
Be careful when enabling this, as it is very difficult to undo if you set up
or upgrade your key incorrectly.
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning
Copy/Paste to Terminal Copy/Paste to Terminal
---------------------- ----------------------

View File

@ -12,13 +12,13 @@ asgiref==3.8.1
# via # via
# -r /Users/david/Projects/flask/requirements/tests.txt # -r /Users/david/Projects/flask/requirements/tests.txt
# -r /Users/david/Projects/flask/requirements/typing.txt # -r /Users/david/Projects/flask/requirements/typing.txt
babel==2.16.0 babel==2.17.0
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx # sphinx
cachetools==5.5.0 cachetools==5.5.2
# via tox # via tox
certifi==2024.8.30 certifi==2025.1.31
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# requests # requests
@ -30,13 +30,13 @@ cfgv==3.4.0
# via pre-commit # via pre-commit
chardet==5.2.0 chardet==5.2.0
# via tox # via tox
charset-normalizer==3.4.0 charset-normalizer==3.4.1
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# requests # requests
colorama==0.4.6 colorama==0.4.6
# via tox # via tox
cryptography==43.0.3 cryptography==44.0.2
# via -r /Users/david/Projects/flask/requirements/typing.txt # via -r /Users/david/Projects/flask/requirements/typing.txt
distlib==0.3.9 distlib==0.3.9
# via virtualenv # via virtualenv
@ -45,11 +45,11 @@ docutils==0.21.2
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx # sphinx
# sphinx-tabs # sphinx-tabs
filelock==3.16.1 filelock==3.18.0
# via # via
# tox # tox
# virtualenv # virtualenv
identify==2.6.2 identify==2.6.9
# via pre-commit # via pre-commit
idna==3.10 idna==3.10
# via # via
@ -59,12 +59,12 @@ imagesize==1.4.1
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx # sphinx
iniconfig==2.0.0 iniconfig==2.1.0
# via # via
# -r /Users/david/Projects/flask/requirements/tests.txt # -r /Users/david/Projects/flask/requirements/tests.txt
# -r /Users/david/Projects/flask/requirements/typing.txt # -r /Users/david/Projects/flask/requirements/typing.txt
# pytest # pytest
jinja2==3.1.4 jinja2==3.1.6
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx # sphinx
@ -72,7 +72,7 @@ markupsafe==3.0.2
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# jinja2 # jinja2
mypy==1.13.0 mypy==1.15.0
# via -r /Users/david/Projects/flask/requirements/typing.txt # via -r /Users/david/Projects/flask/requirements/typing.txt
mypy-extensions==1.0.0 mypy-extensions==1.0.0
# via # via
@ -95,7 +95,7 @@ packaging==24.2
# tox # tox
pallets-sphinx-themes==2.3.0 pallets-sphinx-themes==2.3.0
# via -r /Users/david/Projects/flask/requirements/docs.txt # via -r /Users/david/Projects/flask/requirements/docs.txt
platformdirs==4.3.6 platformdirs==4.3.7
# via # via
# tox # tox
# virtualenv # virtualenv
@ -105,26 +105,26 @@ pluggy==1.5.0
# -r /Users/david/Projects/flask/requirements/typing.txt # -r /Users/david/Projects/flask/requirements/typing.txt
# pytest # pytest
# tox # tox
pre-commit==4.0.1 pre-commit==4.2.0
# via -r dev.in # via -r dev.in
pycparser==2.22 pycparser==2.22
# via # via
# -r /Users/david/Projects/flask/requirements/typing.txt # -r /Users/david/Projects/flask/requirements/typing.txt
# cffi # cffi
pygments==2.18.0 pygments==2.19.1
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx # sphinx
# sphinx-tabs # sphinx-tabs
pyproject-api==1.8.0 pyproject-api==1.9.0
# via tox # via tox
pyright==1.1.389 pyright==1.1.398
# via -r /Users/david/Projects/flask/requirements/typing.txt # via -r /Users/david/Projects/flask/requirements/typing.txt
pytest==8.3.3 pytest==8.3.5
# via # via
# -r /Users/david/Projects/flask/requirements/tests.txt # -r /Users/david/Projects/flask/requirements/tests.txt
# -r /Users/david/Projects/flask/requirements/typing.txt # -r /Users/david/Projects/flask/requirements/typing.txt
python-dotenv==1.0.1 python-dotenv==1.1.0
# via # via
# -r /Users/david/Projects/flask/requirements/tests.txt # -r /Users/david/Projects/flask/requirements/tests.txt
# -r /Users/david/Projects/flask/requirements/typing.txt # -r /Users/david/Projects/flask/requirements/typing.txt
@ -134,18 +134,22 @@ requests==2.32.3
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx # sphinx
roman-numerals-py==3.1.0
# via
# -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx
snowballstemmer==2.2.0 snowballstemmer==2.2.0
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx # sphinx
sphinx==8.1.3 sphinx==8.2.3
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# pallets-sphinx-themes # pallets-sphinx-themes
# sphinx-notfound-page # sphinx-notfound-page
# sphinx-tabs # sphinx-tabs
# sphinxcontrib-log-cabinet # sphinxcontrib-log-cabinet
sphinx-notfound-page==1.0.4 sphinx-notfound-page==1.1.0
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# pallets-sphinx-themes # pallets-sphinx-themes
@ -177,22 +181,22 @@ sphinxcontrib-serializinghtml==2.0.0
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# sphinx # sphinx
tox==4.23.2 tox==4.25.0
# via -r dev.in # via -r dev.in
types-contextvars==2.4.7.3 types-contextvars==2.4.7.3
# via -r /Users/david/Projects/flask/requirements/typing.txt # via -r /Users/david/Projects/flask/requirements/typing.txt
types-dataclasses==0.6.6 types-dataclasses==0.6.6
# via -r /Users/david/Projects/flask/requirements/typing.txt # via -r /Users/david/Projects/flask/requirements/typing.txt
typing-extensions==4.12.2 typing-extensions==4.13.0
# via # via
# -r /Users/david/Projects/flask/requirements/typing.txt # -r /Users/david/Projects/flask/requirements/typing.txt
# mypy # mypy
# pyright # pyright
urllib3==2.2.3 urllib3==2.3.0
# via # via
# -r /Users/david/Projects/flask/requirements/docs.txt # -r /Users/david/Projects/flask/requirements/docs.txt
# requests # requests
virtualenv==20.27.1 virtualenv==20.29.3
# via # via
# pre-commit # pre-commit
# tox # tox

View File

@ -6,11 +6,11 @@
# #
alabaster==1.0.0 alabaster==1.0.0
# via sphinx # via sphinx
babel==2.16.0 babel==2.17.0
# via sphinx # via sphinx
certifi==2024.8.30 certifi==2025.1.31
# via requests # via requests
charset-normalizer==3.4.0 charset-normalizer==3.4.1
# via requests # via requests
docutils==0.21.2 docutils==0.21.2
# via # via
@ -20,7 +20,7 @@ idna==3.10
# via requests # via requests
imagesize==1.4.1 imagesize==1.4.1
# via sphinx # via sphinx
jinja2==3.1.4 jinja2==3.1.6
# via sphinx # via sphinx
markupsafe==3.0.2 markupsafe==3.0.2
# via jinja2 # via jinja2
@ -30,22 +30,24 @@ packaging==24.2
# sphinx # sphinx
pallets-sphinx-themes==2.3.0 pallets-sphinx-themes==2.3.0
# via -r docs.in # via -r docs.in
pygments==2.18.0 pygments==2.19.1
# via # via
# sphinx # sphinx
# sphinx-tabs # sphinx-tabs
requests==2.32.3 requests==2.32.3
# via sphinx # via sphinx
roman-numerals-py==3.1.0
# via sphinx
snowballstemmer==2.2.0 snowballstemmer==2.2.0
# via sphinx # via sphinx
sphinx==8.1.3 sphinx==8.2.3
# via # via
# -r docs.in # -r docs.in
# pallets-sphinx-themes # pallets-sphinx-themes
# sphinx-notfound-page # sphinx-notfound-page
# sphinx-tabs # sphinx-tabs
# sphinxcontrib-log-cabinet # sphinxcontrib-log-cabinet
sphinx-notfound-page==1.0.4 sphinx-notfound-page==1.1.0
# via pallets-sphinx-themes # via pallets-sphinx-themes
sphinx-tabs==3.4.7 sphinx-tabs==3.4.7
# via -r docs.in # via -r docs.in
@ -63,5 +65,5 @@ sphinxcontrib-qthelp==2.0.0
# via sphinx # via sphinx
sphinxcontrib-serializinghtml==2.0.0 sphinxcontrib-serializinghtml==2.0.0
# via sphinx # via sphinx
urllib3==2.2.3 urllib3==2.3.0
# via requests # via requests

View File

@ -6,13 +6,13 @@
# #
asgiref==3.8.1 asgiref==3.8.1
# via -r tests.in # via -r tests.in
iniconfig==2.0.0 iniconfig==2.1.0
# via pytest # via pytest
packaging==24.2 packaging==24.2
# via pytest # via pytest
pluggy==1.5.0 pluggy==1.5.0
# via pytest # via pytest
pytest==8.3.3 pytest==8.3.5
# via -r tests.in # via -r tests.in
python-dotenv==1.0.1 python-dotenv==1.1.0
# via -r tests.in # via -r tests.in

View File

@ -8,11 +8,11 @@ asgiref==3.8.1
# via -r typing.in # via -r typing.in
cffi==1.17.1 cffi==1.17.1
# via cryptography # via cryptography
cryptography==43.0.3 cryptography==44.0.2
# via -r typing.in # via -r typing.in
iniconfig==2.0.0 iniconfig==2.1.0
# via pytest # via pytest
mypy==1.13.0 mypy==1.15.0
# via -r typing.in # via -r typing.in
mypy-extensions==1.0.0 mypy-extensions==1.0.0
# via mypy # via mypy
@ -24,17 +24,17 @@ pluggy==1.5.0
# via pytest # via pytest
pycparser==2.22 pycparser==2.22
# via cffi # via cffi
pyright==1.1.389 pyright==1.1.398
# via -r typing.in # via -r typing.in
pytest==8.3.3 pytest==8.3.5
# via -r typing.in # via -r typing.in
python-dotenv==1.0.1 python-dotenv==1.1.0
# via -r typing.in # via -r typing.in
types-contextvars==2.4.7.3 types-contextvars==2.4.7.3
# via -r typing.in # via -r typing.in
types-dataclasses==0.6.6 types-dataclasses==0.6.6
# via -r typing.in # via -r typing.in
typing-extensions==4.12.2 typing-extensions==4.13.0
# via # via
# mypy # mypy
# pyright # pyright

View File

@ -265,9 +265,9 @@ class Flask(App):
# For one, it might be created while the server is running (e.g. during # For one, it might be created while the server is running (e.g. during
# development). Also, Google App Engine stores static files somewhere # development). Also, Google App Engine stores static files somewhere
if self.has_static_folder: if self.has_static_folder:
assert ( assert bool(static_host) == host_matching, (
bool(static_host) == host_matching "Invalid static_host/host_matching combination"
), "Invalid static_host/host_matching combination" )
# Use a weakref to avoid creating a reference cycle between the app # Use a weakref to avoid creating a reference cycle between the app
# and the view function (see #3761). # and the view function (see #3761).
self_ref = weakref.ref(self) self_ref = weakref.ref(self)

View File

@ -684,7 +684,9 @@ class FlaskGroup(AppGroup):
return super().make_context(info_name, args, parent=parent, **extra) return super().make_context(info_name, args, parent=parent, **extra)
def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]: def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]:
if not args and self.no_args_is_help: if (not args and self.no_args_is_help) or (
len(args) == 1 and args[0] in self.get_help_option_names(ctx)
):
# Attempt to load --env-file and --app early in case they # Attempt to load --env-file and --app early in case they
# were given as env vars. Otherwise no_args_is_help will not # were given as env vars. Otherwise no_args_is_help will not
# see commands from app.cli. # see commands from app.cli.

View File

@ -58,9 +58,9 @@ class EnvironBuilder(werkzeug.test.EnvironBuilder):
) -> None: ) -> None:
assert not (base_url or subdomain or url_scheme) or ( assert not (base_url or subdomain or url_scheme) or (
base_url is not None base_url is not None
) != bool( ) != bool(subdomain or url_scheme), (
subdomain or url_scheme 'Cannot pass "subdomain" or "url_scheme" with "base_url".'
), 'Cannot pass "subdomain" or "url_scheme" with "base_url".' )
if base_url is None: if base_url is None:
http_host = app.config.get("SERVER_NAME") or "localhost" http_host = app.config.get("SERVER_NAME") or "localhost"

View File

@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import collections.abc as cabc
import typing as t import typing as t
if t.TYPE_CHECKING: # pragma: no cover if t.TYPE_CHECKING: # pragma: no cover
@ -17,6 +18,8 @@ ResponseValue = t.Union[
t.Mapping[str, t.Any], t.Mapping[str, t.Any],
t.Iterator[str], t.Iterator[str],
t.Iterator[bytes], t.Iterator[bytes],
cabc.AsyncIterable[str], # for Quart, until App is generic.
cabc.AsyncIterable[bytes],
] ]
# the possible types for an individual HTTP header # the possible types for an individual HTTP header

View File

@ -1,5 +1,4 @@
import os import os
import pkgutil
import sys import sys
import pytest import pytest
@ -96,37 +95,6 @@ def leak_detector():
assert leaks == [] assert leaks == []
@pytest.fixture(params=(True, False))
def limit_loader(request, monkeypatch):
"""Patch pkgutil.get_loader to give loader without get_filename or archive.
This provides for tests where a system has custom loaders, e.g. Google App
Engine's HardenedModulesHook, which have neither the `get_filename` method
nor the `archive` attribute.
This fixture will run the testcase twice, once with and once without the
limitation/mock.
"""
if not request.param:
return
class LimitedLoader:
def __init__(self, loader):
self.loader = loader
def __getattr__(self, name):
if name in {"archive", "get_filename"}:
raise AttributeError(f"Mocking a loader which does not have {name!r}.")
return getattr(self.loader, name)
old_get_loader = pkgutil.get_loader
def get_loader(*args, **kwargs):
return LimitedLoader(old_get_loader(*args, **kwargs))
monkeypatch.setattr(pkgutil, "get_loader", get_loader)
@pytest.fixture @pytest.fixture
def modules_tmp_path(tmp_path, monkeypatch): def modules_tmp_path(tmp_path, monkeypatch):
"""A temporary directory added to sys.path.""" """A temporary directory added to sys.path."""

View File

@ -63,7 +63,7 @@ def test_uninstalled_namespace_paths(tmp_path, monkeypatch, purge_module):
def test_installed_module_paths( def test_installed_module_paths(
modules_tmp_path, modules_tmp_path_prefix, purge_module, site_packages, limit_loader modules_tmp_path, modules_tmp_path_prefix, purge_module, site_packages
): ):
(site_packages / "site_app.py").write_text( (site_packages / "site_app.py").write_text(
"import flask\napp = flask.Flask(__name__)\n" "import flask\napp = flask.Flask(__name__)\n"
@ -78,7 +78,7 @@ def test_installed_module_paths(
def test_installed_package_paths( def test_installed_package_paths(
limit_loader, modules_tmp_path, modules_tmp_path_prefix, purge_module, monkeypatch modules_tmp_path, modules_tmp_path_prefix, purge_module, monkeypatch
): ):
installed_path = modules_tmp_path / "path" installed_path = modules_tmp_path / "path"
installed_path.mkdir() installed_path.mkdir()
@ -97,7 +97,7 @@ def test_installed_package_paths(
def test_prefix_package_paths( def test_prefix_package_paths(
limit_loader, modules_tmp_path, modules_tmp_path_prefix, purge_module, site_packages modules_tmp_path, modules_tmp_path_prefix, purge_module, site_packages
): ):
app = site_packages / "site_package" app = site_packages / "site_package"
app.mkdir() app.mkdir()