Merge pull request #1 from pallets/main

das
This commit is contained in:
blindspotdemo 2023-11-26 11:37:19 +02:00 committed by GitHub
commit d2cb6a8a67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 367 additions and 289 deletions

25
.flake8
View file

@ -1,25 +0,0 @@
[flake8]
extend-select =
# bugbear
B
# bugbear opinions
B9
# implicit str concat
ISC
extend-ignore =
# slice notation whitespace, invalid
E203
# line length, handled by bugbear B950
E501
# bare except, handled by bugbear B001
E722
# zip with strict=, requires python >= 3.10
B905
# string formatting opinion, B028 renamed to B907
B028
B907
# up to 88 allowed by bugbear B950
max-line-length = 80
per-file-ignores =
# __init__ exports names
src/flask/__init__.py: F401

View file

@ -1,9 +1,18 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: "github-actions" - package-ecosystem: github-actions
directory: "/" directory: /
schedule: schedule:
interval: "monthly" interval: monthly
day: "monday" groups:
time: "16:00" github-actions:
timezone: "UTC" patterns:
- '*'
- package-ecosystem: pip
directory: /requirements/
schedule:
interval: monthly
groups:
python-requirements:
patterns:
- '*'

View file

@ -1,8 +1,8 @@
name: 'Lock threads' name: 'Lock inactive closed issues'
# Lock closed issues that have not received any further activity for # Lock closed issues that have not received any further activity for two weeks.
# two weeks. This does not close open issues, only humans may do that. # This does not close open issues, only humans may do that. We find that it is
# We find that it is easier to respond to new issues with fresh examples # easier to respond to new issues with fresh examples rather than continuing
# rather than continuing discussions on old issues. # discussions on old issues.
on: on:
schedule: schedule:

View file

@ -9,12 +9,12 @@ jobs:
outputs: outputs:
hash: ${{ steps.hash.outputs.hash }} hash: ${{ steps.hash.outputs.hash }}
steps: steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236
with: with:
python-version: '3.x' python-version: '3.x'
cache: 'pip' cache: pip
cache-dependency-path: 'requirements/*.txt' cache-dependency-path: requirements*/*.txt
- run: pip install -r requirements/build.txt - run: pip install -r requirements/build.txt
# Use the commit date instead of the current date during the build. # Use the commit date instead of the current date during the build.
- run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV - run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV
@ -23,11 +23,11 @@ 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@0b7f8abb1508181956e8e162db84b466c27e18ce - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
with: with:
path: ./dist path: ./dist
provenance: provenance:
needs: ['build'] needs: [build]
permissions: permissions:
actions: read actions: read
id-token: write id-token: write
@ -39,7 +39,7 @@ jobs:
create-release: create-release:
# Upload the sdist, wheels, and provenance to a GitHub release. They remain # Upload the sdist, wheels, and provenance to a GitHub release. They remain
# available as build artifacts for a while as well. # available as build artifacts for a while as well.
needs: ['provenance'] needs: [provenance]
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write
@ -53,16 +53,15 @@ jobs:
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
publish-pypi: publish-pypi:
needs: ['provenance'] needs: [provenance]
# Wait for approval before attempting to upload to PyPI. This allows reviewing the # Wait for approval before attempting to upload to PyPI. This allows reviewing the
# files in the draft release. # files in the draft release.
environment: 'publish' environment: publish
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
id-token: write id-token: write
steps: steps:
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
# Try uploading to Test PyPI first, in case something fails.
- uses: pypa/gh-action-pypi-publish@b7f401de30cb6434a1e19f805ff006643653240e - uses: pypa/gh-action-pypi-publish@b7f401de30cb6434a1e19f805ff006643653240e
with: with:
repository-url: https://test.pypi.org/legacy/ repository-url: https://test.pypi.org/legacy/

View file

@ -9,9 +9,6 @@ on:
- '*.md' - '*.md'
- '*.rst' - '*.rst'
pull_request: pull_request:
branches:
- main
- '*.x'
paths-ignore: paths-ignore:
- 'docs/**' - 'docs/**'
- '*.md' - '*.md'
@ -24,26 +21,26 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- {name: Linux, python: '3.11', os: ubuntu-latest, tox: py311} - {name: Linux, python: '3.12', os: ubuntu-latest, tox: py312}
- {name: Windows, python: '3.11', os: windows-latest, tox: py311} - {name: Windows, python: '3.12', os: windows-latest, tox: py312}
- {name: Mac, python: '3.11', os: macos-latest, tox: py311} - {name: Mac, python: '3.12', os: macos-latest, tox: py312}
- {name: '3.12-dev', python: '3.12-dev', os: ubuntu-latest, tox: py312} - {name: '3.11', python: '3.11', os: ubuntu-latest, tox: py311}
- {name: '3.10', python: '3.10', os: ubuntu-latest, tox: py310} - {name: '3.10', python: '3.10', os: ubuntu-latest, tox: py310}
- {name: '3.9', python: '3.9', os: ubuntu-latest, tox: py39} - {name: '3.9', python: '3.9', os: ubuntu-latest, tox: py39}
- {name: '3.8', python: '3.8', os: ubuntu-latest, tox: py38} - {name: '3.8', python: '3.8', os: ubuntu-latest, tox: py38}
- {name: 'PyPy', python: 'pypy-3.10', os: ubuntu-latest, tox: pypy310} - {name: 'PyPy', python: 'pypy-3.10', os: ubuntu-latest, tox: pypy310}
- {name: 'Minimum Versions', python: '3.11', os: ubuntu-latest, tox: py311-min} - {name: 'Minimum Versions', python: '3.12', os: ubuntu-latest, tox: py312-min}
- {name: 'Development Versions', python: '3.8', os: ubuntu-latest, tox: py38-dev} - {name: 'Development Versions', python: '3.8', os: ubuntu-latest, tox: py38-dev}
- {name: Typing, python: '3.11', os: ubuntu-latest, tox: typing} - {name: Typing, python: '3.12', os: ubuntu-latest, tox: typing}
steps: steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
- uses: actions/setup-python@61a6322f88396a6271a6ee3565807d608ecaddd1 - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236
with: with:
python-version: ${{ matrix.python }} python-version: ${{ matrix.python }}
cache: 'pip' cache: 'pip'
cache-dependency-path: 'requirements/*.txt' cache-dependency-path: requirements*/*.txt
- name: cache mypy - name: cache mypy
uses: actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8 uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84
with: with:
path: ./.mypy_cache path: ./.mypy_cache
key: mypy|${{ matrix.python }}|${{ hashFiles('pyproject.toml') }} key: mypy|${{ matrix.python }}|${{ hashFiles('pyproject.toml') }}

29
.gitignore vendored
View file

@ -1,25 +1,10 @@
.DS_Store
.env
.flaskenv
*.pyc
*.pyo
env/
venv/
.venv/
env*
dist/
build/
*.egg
*.egg-info/
.tox/
.cache/
.pytest_cache/
.idea/ .idea/
docs/_build/ .vscode/
.vscode __pycache__/
.tox/
# Coverage reports
htmlcov/
.coverage .coverage
.coverage.* .coverage.*
*,cover htmlcov/
docs/_build/
dist/
venv/

View file

@ -1,37 +1,16 @@
ci: ci:
autoupdate_branch: "2.3.x"
autoupdate_schedule: monthly autoupdate_schedule: monthly
repos: repos:
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v3.10.1 rev: v0.1.5
hooks: hooks:
- id: pyupgrade - id: ruff
args: ["--py38-plus"] - id: ruff-format
- repo: https://github.com/asottile/reorder-python-imports
rev: v3.10.0
hooks:
- id: reorder-python-imports
name: Reorder Python imports (src, tests)
files: "^(?!examples/)"
args: ["--application-directories", "src"]
- repo: https://github.com/psf/black
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- flake8-implicit-str-concat
- repo: https://github.com/peterdemin/pip-compile-multi
rev: v2.6.3
hooks:
- id: pip-compile-multi-verify
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 rev: v4.5.0
hooks: hooks:
- id: check-merge-conflict
- id: debug-statements
- id: fix-byte-order-marker - id: fix-byte-order-marker
- id: trailing-whitespace - id: trailing-whitespace
- id: end-of-file-fixer - id: end-of-file-fixer

View file

@ -1,8 +1,8 @@
version: 2 version: 2
build: build:
os: ubuntu-20.04 os: ubuntu-22.04
tools: tools:
python: "3.10" python: "3.12"
python: python:
install: install:
- requirements: requirements/docs.txt - requirements: requirements/docs.txt

View file

@ -1,13 +1,23 @@
Version 3.0.0 Version 3.0.1
------------- -------------
Unreleased Unreleased
- Correct type for ``path`` argument to ``send_file``. :issue:`5230`
Version 3.0.0
-------------
Released 2023-09-30
- Remove previously deprecated code. :pr:`5223` - Remove previously deprecated code. :pr:`5223`
- Deprecate the ``__version__`` attribute. Use feature detection, or - Deprecate the ``__version__`` attribute. Use feature detection, or
``importlib.metadata.version("flask")``, instead. :issue:`5230` ``importlib.metadata.version("flask")``, instead. :issue:`5230`
- Restructure the code such that the Flask (app) and Blueprint - Restructure the code such that the Flask (app) and Blueprint
classes have Sans-IO bases. :pr:`5127` classes have Sans-IO bases. :pr:`5127`
- Allow self as an argument to url_for. :pr:`5264`
- Require Werkzeug >= 3.0.0.
Version 2.3.3 Version 2.3.3

View file

@ -20,7 +20,7 @@ wrapping the Flask app,
asgi_app = WsgiToAsgi(app) asgi_app = WsgiToAsgi(app)
and then serving the ``asgi_app`` with the ASGI server, e.g. using and then serving the ``asgi_app`` with the ASGI server, e.g. using
`Hypercorn <https://gitlab.com/pgjones/hypercorn>`_, `Hypercorn <https://github.com/pgjones/hypercorn>`_,
.. sourcecode:: text .. sourcecode:: text

View file

@ -6,7 +6,11 @@ Welcome to Flask
.. image:: _static/flask-horizontal.png .. image:: _static/flask-horizontal.png
:align: center :align: center
Welcome to Flask's documentation. Get started with :doc:`installation` Welcome to Flask's documentation. Flask is a lightweight WSGI web application framework.
It is designed to make getting started quick and easy, with the ability to scale up to
complex applications.
Get started with :doc:`installation`
and then get an overview with the :doc:`quickstart`. There is also a and then get an overview with the :doc:`quickstart`. There is also a
more detailed :doc:`tutorial/index` that shows how to create a small but more detailed :doc:`tutorial/index` that shows how to create a small but
complete application with Flask. Common patterns are described in the complete application with Flask. Common patterns are described in the

View file

@ -197,7 +197,7 @@ in the previous section. The following example shows how to replace a
const geology_div = getElementById("geology-fact") const geology_div = getElementById("geology-fact")
fetch(geology_url) fetch(geology_url)
.then(response => response.text) .then(response => response.text)
.then(text => geology_div.innerHtml = text) .then(text => geology_div.innerHTML = text)
</script> </script>

View file

@ -192,7 +192,7 @@ which records the request that produced that response.
.. code-block:: python .. code-block:: python
def test_logout_redirect(client): def test_logout_redirect(client):
response = client.get("/logout") response = client.get("/logout", follow_redirects=True)
# Check that there was one redirect response. # Check that there was one redirect response.
assert len(response.history) == 1 assert len(response.history) == 1
# Check that the second request was to the index page. # Check that the second request was to the index page.

View file

@ -12,3 +12,6 @@ build-backend = "flit_core.buildapi"
[tool.flit.module] [tool.flit.module]
name = "task_app" name = "task_app"
[tool.ruff]
src = ["src"]

View file

@ -15,7 +15,7 @@ page. Demonstrates using |fetch|_, |XMLHttpRequest|_, and
.. |jQuery.ajax| replace:: ``jQuery.ajax`` .. |jQuery.ajax| replace:: ``jQuery.ajax``
.. _jQuery.ajax: https://api.jquery.com/jQuery.ajax/ .. _jQuery.ajax: https://api.jquery.com/jQuery.ajax/
.. _Flask docs: https://flask.palletsprojects.com/patterns/jquery/ .. _Flask docs: https://flask.palletsprojects.com/patterns/javascript/
Install Install

View file

@ -2,7 +2,7 @@ from flask import jsonify
from flask import render_template from flask import render_template
from flask import request from flask import request
from js_example import app from . import app
@app.route("/", defaults={"js": "fetch"}) @app.route("/", defaults={"js": "fetch"})

View file

@ -27,3 +27,6 @@ filterwarnings = ["error"]
[tool.coverage.run] [tool.coverage.run]
branch = true branch = true
source = ["js_example", "tests"] source = ["js_example", "tests"]
[tool.ruff]
src = ["src"]

View file

@ -31,12 +31,13 @@ def create_app(test_config=None):
return "Hello, World!" return "Hello, World!"
# register the database commands # register the database commands
from flaskr import db from . import db
db.init_app(app) db.init_app(app)
# apply the blueprints to the app # apply the blueprints to the app
from flaskr import auth, blog from . import auth
from . import blog
app.register_blueprint(auth.bp) app.register_blueprint(auth.bp)
app.register_blueprint(blog.bp) app.register_blueprint(blog.bp)

View file

@ -11,7 +11,7 @@ from flask import url_for
from werkzeug.security import check_password_hash from werkzeug.security import check_password_hash
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
from flaskr.db import get_db from .db import get_db
bp = Blueprint("auth", __name__, url_prefix="/auth") bp = Blueprint("auth", __name__, url_prefix="/auth")

View file

@ -7,8 +7,8 @@ from flask import request
from flask import url_for from flask import url_for
from werkzeug.exceptions import abort from werkzeug.exceptions import abort
from flaskr.auth import login_required from .auth import login_required
from flaskr.db import get_db from .db import get_db
bp = Blueprint("blog", __name__) bp = Blueprint("blog", __name__)

View file

@ -34,3 +34,6 @@ filterwarnings = ["error"]
[tool.coverage.run] [tool.coverage.run]
branch = true branch = true
source = ["flaskr", "tests"] source = ["flaskr", "tests"]
[tool.ruff]
src = ["src"]

View file

@ -1,6 +1,6 @@
[project] [project]
name = "Flask" name = "Flask"
version = "3.0.0.dev" version = "3.0.1.dev"
description = "A simple framework for building complex web applications." description = "A simple framework for building complex web applications."
readme = "README.rst" readme = "README.rst"
license = {file = "LICENSE.rst"} license = {file = "LICENSE.rst"}
@ -20,7 +20,7 @@ classifiers = [
] ]
requires-python = ">=3.8" requires-python = ">=3.8"
dependencies = [ dependencies = [
"Werkzeug>=2.3.7", "Werkzeug>=3.0.0",
"Jinja2>=3.1.2", "Jinja2>=3.1.2",
"itsdangerous>=2.1.2", "itsdangerous>=2.1.2",
"click>=8.1.3", "click>=8.1.3",
@ -106,3 +106,24 @@ module = [
"importlib_metadata", "importlib_metadata",
] ]
ignore_missing_imports = true ignore_missing_imports = true
[tool.ruff]
src = ["src"]
fix = true
show-fixes = true
show-source = true
[tool.ruff.lint]
select = [
"B", # flake8-bugbear
"E", # pycodestyle error
"F", # pyflakes
"I", # isort
"UP", # pyupgrade
"W", # pycodestyle warning
]
ignore-init-module-imports = true
[tool.ruff.lint.isort]
force-single-line = true
order-by-type = false

View file

@ -0,0 +1,2 @@
Dependabot will only update files in the `requirements` directory. This directory is
separate because the pins in here should not be updated automatically.

View file

@ -0,0 +1,6 @@
https://github.com/pallets/werkzeug/archive/refs/heads/main.tar.gz
https://github.com/pallets/jinja/archive/refs/heads/main.tar.gz
https://github.com/pallets/markupsafe/archive/refs/heads/main.tar.gz
https://github.com/pallets/itsdangerous/archive/refs/heads/main.tar.gz
https://github.com/pallets/click/archive/refs/heads/main.tar.gz
https://github.com/pallets-eco/blinker/archive/refs/heads/main.tar.gz

View file

@ -1,6 +1,6 @@
Werkzeug==2.3.7 werkzeug==3.0.0
Jinja2==3.1.2 jinja2==3.1.2
MarkupSafe==2.1.1 markupsafe==2.1.1
itsdangerous==2.1.2 itsdangerous==2.1.2
click==8.1.3 click==8.1.3
blinker==1.6.2 blinker==1.6.2

View file

@ -0,0 +1,21 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile tests-min.in
#
blinker==1.6.2
# via -r tests-min.in
click==8.1.3
# via -r tests-min.in
itsdangerous==2.1.2
# via -r tests-min.in
jinja2==3.1.2
# via -r tests-min.in
markupsafe==2.1.1
# via
# -r tests-min.in
# jinja2
# werkzeug
werkzeug==3.0.0
# via -r tests-min.in

View file

@ -1,13 +1,12 @@
# SHA1:80754af91bfb6d1073585b046fe0a474ce868509
# #
# This file is autogenerated by pip-compile-multi # This file is autogenerated by pip-compile with Python 3.11
# To update, run: # by the following command:
# #
# pip-compile-multi # pip-compile build.in
# #
build==0.10.0 build==1.0.3
# via -r requirements/build.in # via -r build.in
packaging==23.1 packaging==23.2
# via build # via build
pyproject-hooks==1.0.0 pyproject-hooks==1.0.0
# via build # via build

View file

@ -1,6 +1,6 @@
-r docs.in -r docs.in
-r tests.in -r tests.in
-r typing.in -r typing.in
pip-compile-multi pip-tools
pre-commit pre-commit
tox tox

View file

@ -1,62 +1,150 @@
# SHA1:54b5b77ec8c7a0064ffa93b2fd16cb0130ba177c
# #
# This file is autogenerated by pip-compile-multi # This file is autogenerated by pip-compile with Python 3.11
# To update, run: # by the following command:
# #
# pip-compile-multi # pip-compile dev.in
# #
-r docs.txt alabaster==0.7.13
-r tests.txt # via sphinx
-r typing.txt asgiref==3.7.2
build==0.10.0 # via -r tests.in
babel==2.13.1
# via sphinx
build==1.0.3
# via pip-tools # via pip-tools
cachetools==5.3.1 cachetools==5.3.2
# via tox # via tox
certifi==2023.7.22
# via requests
cffi==1.16.0
# via cryptography
cfgv==3.4.0 cfgv==3.4.0
# via pre-commit # via pre-commit
chardet==5.2.0 chardet==5.2.0
# via tox # via tox
click==8.1.6 charset-normalizer==3.3.2
# via # via requests
# pip-compile-multi click==8.1.7
# pip-tools # via pip-tools
colorama==0.4.6 colorama==0.4.6
# via tox # via tox
cryptography==41.0.5
# via -r typing.in
distlib==0.3.7 distlib==0.3.7
# via virtualenv # via virtualenv
filelock==3.12.2 docutils==0.18.1
# via
# sphinx
# sphinx-tabs
filelock==3.13.1
# via # via
# tox # tox
# virtualenv # virtualenv
identify==2.5.26 identify==2.5.31
# via pre-commit # via pre-commit
idna==3.4
# via requests
imagesize==1.4.1
# via sphinx
iniconfig==2.0.0
# via pytest
jinja2==3.1.2
# via sphinx
markupsafe==2.1.3
# via jinja2
mypy==1.6.1
# via -r typing.in
mypy-extensions==1.0.0
# via mypy
nodeenv==1.8.0 nodeenv==1.8.0
# via pre-commit # via pre-commit
pip-compile-multi==2.6.3 packaging==23.2
# via -r requirements/dev.in # via
# build
# pallets-sphinx-themes
# pyproject-api
# pytest
# sphinx
# tox
pallets-sphinx-themes==2.1.1
# via -r docs.in
pip-tools==7.3.0 pip-tools==7.3.0
# via pip-compile-multi # via -r dev.in
platformdirs==3.10.0 platformdirs==3.11.0
# via # via
# tox # tox
# virtualenv # virtualenv
pre-commit==3.3.3 pluggy==1.3.0
# via -r requirements/dev.in # via
pyproject-api==1.5.3 # pytest
# tox
pre-commit==3.5.0
# via -r dev.in
pycparser==2.21
# via cffi
pygments==2.16.1
# via
# sphinx
# sphinx-tabs
pyproject-api==1.6.1
# via tox # via tox
pyproject-hooks==1.0.0 pyproject-hooks==1.0.0
# via build # via build
pytest==7.4.3
# via -r tests.in
python-dotenv==1.0.0
# via -r tests.in
pyyaml==6.0.1 pyyaml==6.0.1
# via pre-commit # via pre-commit
toposort==1.10 requests==2.31.0
# via pip-compile-multi # via sphinx
tox==4.9.0 snowballstemmer==2.2.0
# via -r requirements/dev.in # via sphinx
virtualenv==20.24.3 sphinx==7.2.6
# via
# -r docs.in
# pallets-sphinx-themes
# sphinx-issues
# sphinx-tabs
# sphinxcontrib-applehelp
# sphinxcontrib-devhelp
# sphinxcontrib-htmlhelp
# sphinxcontrib-log-cabinet
# sphinxcontrib-qthelp
# sphinxcontrib-serializinghtml
sphinx-issues==3.0.1
# via -r docs.in
sphinx-tabs==3.4.4
# via -r docs.in
sphinxcontrib-applehelp==1.0.7
# via sphinx
sphinxcontrib-devhelp==1.0.5
# via sphinx
sphinxcontrib-htmlhelp==2.0.4
# via sphinx
sphinxcontrib-jsmath==1.0.1
# via sphinx
sphinxcontrib-log-cabinet==1.0.1
# via -r docs.in
sphinxcontrib-qthelp==1.0.6
# via sphinx
sphinxcontrib-serializinghtml==1.1.9
# via sphinx
tox==4.11.3
# via -r dev.in
types-contextvars==2.4.7.3
# via -r typing.in
types-dataclasses==0.6.6
# via -r typing.in
typing-extensions==4.8.0
# via mypy
urllib3==2.0.7
# via requests
virtualenv==20.24.6
# via # via
# pre-commit # pre-commit
# tox # tox
wheel==0.41.1 wheel==0.41.3
# via pip-tools # via pip-tools
# The following packages are considered to be unsafe in a requirements file: # The following packages are considered to be unsafe in a requirements file:

View file

@ -1,5 +1,5 @@
Pallets-Sphinx-Themes pallets-sphinx-themes
Sphinx sphinx
sphinx-issues sphinx-issues
sphinxcontrib-log-cabinet sphinxcontrib-log-cabinet
sphinx-tabs sphinx-tabs

View file

@ -1,17 +1,16 @@
# SHA1:34fd4ca6516e97c7348e6facdd9c4ebb68209d1c
# #
# This file is autogenerated by pip-compile-multi # This file is autogenerated by pip-compile with Python 3.11
# To update, run: # by the following command:
# #
# pip-compile-multi # pip-compile docs.in
# #
alabaster==0.7.13 alabaster==0.7.13
# via sphinx # via sphinx
babel==2.12.1 babel==2.13.1
# via sphinx # via sphinx
certifi==2023.7.22 certifi==2023.7.22
# via requests # via requests
charset-normalizer==3.2.0 charset-normalizer==3.3.2
# via requests # via requests
docutils==0.18.1 docutils==0.18.1
# via # via
@ -25,12 +24,12 @@ jinja2==3.1.2
# via sphinx # via sphinx
markupsafe==2.1.3 markupsafe==2.1.3
# via jinja2 # via jinja2
packaging==23.1 packaging==23.2
# via # via
# pallets-sphinx-themes # pallets-sphinx-themes
# sphinx # sphinx
pallets-sphinx-themes==2.1.1 pallets-sphinx-themes==2.1.1
# via -r requirements/docs.in # via -r docs.in
pygments==2.16.1 pygments==2.16.1
# via # via
# sphinx # sphinx
@ -39,9 +38,9 @@ requests==2.31.0
# via sphinx # via sphinx
snowballstemmer==2.2.0 snowballstemmer==2.2.0
# via sphinx # via sphinx
sphinx==7.1.2 sphinx==7.2.6
# via # via
# -r requirements/docs.in # -r docs.in
# pallets-sphinx-themes # pallets-sphinx-themes
# sphinx-issues # sphinx-issues
# sphinx-tabs # sphinx-tabs
@ -52,9 +51,9 @@ sphinx==7.1.2
# sphinxcontrib-qthelp # sphinxcontrib-qthelp
# sphinxcontrib-serializinghtml # sphinxcontrib-serializinghtml
sphinx-issues==3.0.1 sphinx-issues==3.0.1
# via -r requirements/docs.in # via -r docs.in
sphinx-tabs==3.4.1 sphinx-tabs==3.4.4
# via -r requirements/docs.in # via -r docs.in
sphinxcontrib-applehelp==1.0.7 sphinxcontrib-applehelp==1.0.7
# via sphinx # via sphinx
sphinxcontrib-devhelp==1.0.5 sphinxcontrib-devhelp==1.0.5
@ -64,10 +63,10 @@ sphinxcontrib-htmlhelp==2.0.4
sphinxcontrib-jsmath==1.0.1 sphinxcontrib-jsmath==1.0.1
# via sphinx # via sphinx
sphinxcontrib-log-cabinet==1.0.1 sphinxcontrib-log-cabinet==1.0.1
# via -r requirements/docs.in # via -r docs.in
sphinxcontrib-qthelp==1.0.6 sphinxcontrib-qthelp==1.0.6
# via sphinx # via sphinx
sphinxcontrib-serializinghtml==1.1.8 sphinxcontrib-serializinghtml==1.1.9
# via sphinx # via sphinx
urllib3==2.0.4 urllib3==2.0.7
# via requests # via requests

View file

@ -1,22 +0,0 @@
# SHA1:fe057f95a98251b053eec8fa27df0feb722c70e8
#
# This file is autogenerated by pip-compile-multi
# To update, run:
#
# pip-compile-multi
#
blinker==1.6.2
# via -r requirements/tests-pallets-min.in
click==8.1.3
# via -r requirements/tests-pallets-min.in
itsdangerous==2.1.2
# via -r requirements/tests-pallets-min.in
jinja2==3.1.2
# via -r requirements/tests-pallets-min.in
markupsafe==2.1.1
# via
# -r requirements/tests-pallets-min.in
# jinja2
# werkzeug
werkzeug==2.3.7
# via -r requirements/tests-pallets-min.in

View file

@ -1,19 +1,18 @@
# SHA1:42d37aff22e2f1fc447e20d483e13d6d4e066b10
# #
# This file is autogenerated by pip-compile-multi # This file is autogenerated by pip-compile with Python 3.11
# To update, run: # by the following command:
# #
# pip-compile-multi # pip-compile tests.in
# #
asgiref==3.7.2 asgiref==3.7.2
# via -r requirements/tests.in # via -r tests.in
iniconfig==2.0.0 iniconfig==2.0.0
# via pytest # via pytest
packaging==23.1 packaging==23.2
# via pytest # via pytest
pluggy==1.2.0 pluggy==1.3.0
# via pytest # via pytest
pytest==7.4.0 pytest==7.4.3
# via -r requirements/tests.in # via -r tests.in
python-dotenv==1.0.0 python-dotenv==1.0.0
# via -r requirements/tests.in # via -r tests.in

View file

@ -1,23 +1,22 @@
# SHA1:6a354b832686fd3ec017455769a0270953a1e225
# #
# This file is autogenerated by pip-compile-multi # This file is autogenerated by pip-compile with Python 3.11
# To update, run: # by the following command:
# #
# pip-compile-multi # pip-compile typing.in
# #
cffi==1.15.1 cffi==1.16.0
# via cryptography # via cryptography
cryptography==41.0.3 cryptography==41.0.5
# via -r requirements/typing.in # via -r typing.in
mypy==1.5.1 mypy==1.6.1
# via -r requirements/typing.in # via -r typing.in
mypy-extensions==1.0.0 mypy-extensions==1.0.0
# via mypy # via mypy
pycparser==2.21 pycparser==2.21
# via cffi # via cffi
types-contextvars==2.4.7.3 types-contextvars==2.4.7.3
# via -r requirements/typing.in # via -r typing.in
types-dataclasses==0.6.6 types-dataclasses==0.6.6
# via -r requirements/typing.in # via -r typing.in
typing-extensions==4.7.1 typing-extensions==4.8.0
# via mypy # via mypy

View file

@ -952,6 +952,7 @@ class Flask(App):
def url_for( def url_for(
self, self,
/,
endpoint: str, endpoint: str,
*, *,
_anchor: str | None = None, _anchor: str | None = None,
@ -1182,7 +1183,8 @@ class Flask(App):
# class to the correct type # class to the correct type
try: try:
rv = self.response_class.force_type( rv = self.response_class.force_type(
rv, request.environ # type: ignore[arg-type] rv, # type: ignore[arg-type]
request.environ,
) )
except TypeError as e: except TypeError as e:
raise TypeError( raise TypeError(
@ -1271,7 +1273,8 @@ class Flask(App):
return response return response
def do_teardown_request( def do_teardown_request(
self, exc: BaseException | None = _sentinel # type: ignore self,
exc: BaseException | None = _sentinel, # type: ignore[assignment]
) -> None: ) -> None:
"""Called after the request is dispatched and the response is """Called after the request is dispatched and the response is
returned, right before the request context is popped. returned, right before the request context is popped.
@ -1304,7 +1307,8 @@ class Flask(App):
request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc)
def do_teardown_appcontext( def do_teardown_appcontext(
self, exc: BaseException | None = _sentinel # type: ignore self,
exc: BaseException | None = _sentinel, # type: ignore[assignment]
) -> None: ) -> None:
"""Called right before the application context is popped. """Called right before the application context is popped.

View file

@ -21,6 +21,7 @@ from .signals import message_flashed
if t.TYPE_CHECKING: # pragma: no cover if t.TYPE_CHECKING: # pragma: no cover
from werkzeug.wrappers import Response as BaseResponse from werkzeug.wrappers import Response as BaseResponse
from .wrappers import Response from .wrappers import Response
@ -48,9 +49,7 @@ def get_load_dotenv(default: bool = True) -> bool:
def stream_with_context( def stream_with_context(
generator_or_function: ( generator_or_function: t.Iterator[t.AnyStr] | t.Callable[..., t.Iterator[t.AnyStr]]
t.Iterator[t.AnyStr] | t.Callable[..., t.Iterator[t.AnyStr]]
)
) -> t.Iterator[t.AnyStr]: ) -> t.Iterator[t.AnyStr]:
"""Request contexts disappear when the response is started on the server. """Request contexts disappear when the response is started on the server.
This is done for efficiency reasons and to make it less likely to encounter This is done for efficiency reasons and to make it less likely to encounter
@ -388,7 +387,7 @@ def _prepare_send_file_kwargs(**kwargs: t.Any) -> dict[str, t.Any]:
def send_file( def send_file(
path_or_file: os.PathLike | str | t.BinaryIO, path_or_file: os.PathLike[t.AnyStr] | str | t.BinaryIO,
mimetype: str | None = None, mimetype: str | None = None,
as_attachment: bool = False, as_attachment: bool = False,
download_name: str | None = None, download_name: str | None = None,

View file

@ -134,9 +134,7 @@ class DefaultJSONProvider(JSONProvider):
method) will call the ``__html__`` method to get a string. method) will call the ``__html__`` method to get a string.
""" """
default: t.Callable[[t.Any], t.Any] = staticmethod( default: t.Callable[[t.Any], t.Any] = staticmethod(_default) # type: ignore[assignment]
_default
) # type: ignore[assignment]
"""Apply this function to any object that :meth:`json.dumps` does """Apply this function to any object that :meth:`json.dumps` does
not know how to serialize. It should return a valid JSON type or not know how to serialize. It should return a valid JSON type or
raise a ``TypeError``. raise a ``TypeError``.

View file

@ -35,9 +35,10 @@ from .scaffold import setupmethod
if t.TYPE_CHECKING: # pragma: no cover if t.TYPE_CHECKING: # pragma: no cover
from werkzeug.wrappers import Response as BaseResponse from werkzeug.wrappers import Response as BaseResponse
from .blueprints import Blueprint
from ..testing import FlaskClient from ..testing import FlaskClient
from ..testing import FlaskCliRunner from ..testing import FlaskCliRunner
from .blueprints import Blueprint
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
@ -905,7 +906,9 @@ class App(Scaffold):
Moved from ``flask.redirect``, which calls this method. Moved from ``flask.redirect``, which calls this method.
""" """
return _wz_redirect( return _wz_redirect(
location, code=code, Response=self.response_class # type: ignore[arg-type] location,
code=code,
Response=self.response_class, # type: ignore[arg-type]
) )
def inject_url_defaults(self, endpoint: str, values: dict) -> None: def inject_url_defaults(self, endpoint: str, values: dict) -> None:

View file

@ -14,7 +14,8 @@ from .json.tag import TaggedJSONSerializer
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 Request, Response from .wrappers import Request
from .wrappers import Response
class SessionMixin(MutableMapping): class SessionMixin(MutableMapping):

View file

@ -6,7 +6,6 @@ from . import typing as ft
from .globals import current_app from .globals import current_app
from .globals import request from .globals import request
http_method_funcs = frozenset( http_method_funcs = frozenset(
["get", "post", "head", "options", "delete", "put", "trace", "patch"] ["get", "post", "head", "options", "delete", "put", "trace", "patch"]
) )

View file

@ -196,17 +196,14 @@ def test_clean_pop(app):
@app.teardown_request @app.teardown_request
def teardown_req(error=None): def teardown_req(error=None):
1 / 0 raise ZeroDivisionError
@app.teardown_appcontext @app.teardown_appcontext
def teardown_app(error=None): def teardown_app(error=None):
called.append("TEARDOWN") called.append("TEARDOWN")
try: with app.app_context():
with app.test_request_context(): called.append(flask.current_app.name)
called.append(flask.current_app.name)
except ZeroDivisionError:
pass
assert called == ["flask_test", "TEARDOWN"] assert called == ["flask_test", "TEARDOWN"]
assert not flask.current_app assert not flask.current_app

View file

@ -1,4 +1,3 @@
from flask import Module from flask import Module
mod = Module(__name__, "foo", subdomain="foo") mod = Module(__name__, "foo", subdomain="foo")

View file

@ -19,7 +19,6 @@ from werkzeug.routing import RequestRedirect
import flask import flask
require_cpython_gc = pytest.mark.skipif( require_cpython_gc = pytest.mark.skipif(
python_implementation() != "CPython", python_implementation() != "CPython",
reason="Requires CPython GC behavior", reason="Requires CPython GC behavior",
@ -190,7 +189,8 @@ def test_url_mapping(app, client):
def test_werkzeug_routing(app, client): def test_werkzeug_routing(app, client):
from werkzeug.routing import Submount, Rule from werkzeug.routing import Rule
from werkzeug.routing import Submount
app.url_map.add( app.url_map.add(
Submount("/foo", [Rule("/bar", endpoint="bar"), Rule("/", endpoint="index")]) Submount("/foo", [Rule("/bar", endpoint="bar"), Rule("/", endpoint="index")])
@ -210,7 +210,8 @@ def test_werkzeug_routing(app, client):
def test_endpoint_decorator(app, client): def test_endpoint_decorator(app, client):
from werkzeug.routing import Submount, Rule from werkzeug.routing import Rule
from werkzeug.routing import Submount
app.url_map.add( app.url_map.add(
Submount("/foo", [Rule("/bar", endpoint="bar"), Rule("/", endpoint="index")]) Submount("/foo", [Rule("/bar", endpoint="bar"), Rule("/", endpoint="index")])
@ -431,9 +432,9 @@ def test_session_special_types(app, client):
client.get("/") client.get("/")
s = flask.session s = flask.session
assert s["t"] == (1, 2, 3) assert s["t"] == (1, 2, 3)
assert type(s["b"]) is bytes assert type(s["b"]) is bytes # noqa: E721
assert s["b"] == b"\xff" assert s["b"] == b"\xff"
assert type(s["m"]) is Markup assert type(s["m"]) is Markup # noqa: E721
assert s["m"] == 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
@ -784,7 +785,7 @@ def test_teardown_request_handler_error(app, client):
@app.route("/") @app.route("/")
def fails(): def fails():
1 // 0 raise ZeroDivisionError
rv = client.get("/") rv = client.get("/")
assert rv.status_code == 500 assert rv.status_code == 500
@ -851,7 +852,7 @@ def test_error_handling(app, client):
@app.route("/error") @app.route("/error")
def error(): def error():
1 // 0 raise ZeroDivisionError
@app.route("/forbidden") @app.route("/forbidden")
def error2(): def error2():
@ -877,7 +878,7 @@ def test_error_handling_processing(app, client):
@app.route("/") @app.route("/")
def broken_func(): def broken_func():
1 // 0 raise ZeroDivisionError
@app.after_request @app.after_request
def after_request(resp): def after_request(resp):
@ -1047,12 +1048,13 @@ def test_error_handler_after_processor_error(app, client):
@app.before_request @app.before_request
def before_request(): def before_request():
if _trigger == "before": if _trigger == "before":
1 // 0 raise ZeroDivisionError
@app.after_request @app.after_request
def after_request(response): def after_request(response):
if _trigger == "after": if _trigger == "after":
1 // 0 raise ZeroDivisionError
return response return response
@app.route("/") @app.route("/")
@ -1507,7 +1509,7 @@ def test_exception_propagation(app, client, key):
@app.route("/") @app.route("/")
def index(): def index():
1 // 0 raise ZeroDivisionError
if key is not None: if key is not None:
app.config[key] = True app.config[key] = True

View file

@ -634,10 +634,11 @@ def test_add_template_test_with_name_and_template(app, client):
def test_context_processing(app, client): def test_context_processing(app, client):
answer_bp = flask.Blueprint("answer_bp", __name__) answer_bp = flask.Blueprint("answer_bp", __name__)
template_string = lambda: flask.render_template_string( # noqa: E731 def template_string():
"{% if notanswer %}{{ notanswer }} is not the answer. {% endif %}" return flask.render_template_string(
"{% if answer %}{{ answer }} is the answer.{% endif %}" "{% if notanswer %}{{ notanswer }} is not the answer. {% endif %}"
) "{% if answer %}{{ answer }} is the answer.{% endif %}"
)
# App global context processor # App global context processor
@answer_bp.app_context_processor @answer_bp.app_context_processor

View file

@ -161,6 +161,13 @@ class TestUrlFor:
assert flask.url_for("myview", id=42, _method="GET") == "/myview/42" assert flask.url_for("myview", id=42, _method="GET") == "/myview/42"
assert flask.url_for("myview", _method="POST") == "/myview/create" assert flask.url_for("myview", _method="POST") == "/myview/create"
def test_url_for_with_self(self, app, req_ctx):
@app.route("/<self>")
def index(self):
return "42"
assert flask.url_for("index", self="2") == "/2"
def test_redirect_no_app(): def test_redirect_no_app():
response = flask.redirect("https://localhost", 307) response = flask.redirect("https://localhost", 307)

View file

@ -98,7 +98,7 @@ def test_request_exception_signal():
@app.route("/") @app.route("/")
def index(): def index():
1 // 0 raise ZeroDivisionError
def record(sender, exception): def record(sender, exception):
recorded.append(exception) recorded.append(exception)
@ -169,7 +169,7 @@ def test_appcontext_tearing_down_signal(app, client):
@app.route("/") @app.route("/")
def index(): def index():
1 // 0 raise ZeroDivisionError
flask.appcontext_tearing_down.connect(record_teardown, app) flask.appcontext_tearing_down.connect(record_teardown, app)
try: try:

View file

@ -219,7 +219,7 @@ def test_test_client_context_binding(app, client):
@app.route("/other") @app.route("/other")
def other(): def other():
1 // 0 raise ZeroDivisionError
with client: with client:
resp = client.get("/") resp = client.get("/")
@ -227,18 +227,15 @@ def test_test_client_context_binding(app, client):
assert resp.data == b"Hello World!" assert resp.data == b"Hello World!"
assert resp.status_code == 200 assert resp.status_code == 200
with client:
resp = client.get("/other") resp = client.get("/other")
assert not hasattr(flask.g, "value") assert not hasattr(flask.g, "value")
assert b"Internal Server Error" in resp.data assert b"Internal Server Error" in resp.data
assert resp.status_code == 500 assert resp.status_code == 500
flask.g.value = 23 flask.g.value = 23
try: with pytest.raises(RuntimeError):
flask.g.value flask.g.value # noqa: B018
except (AttributeError, RuntimeError):
pass
else:
raise AssertionError("some kind of exception expected")
def test_reuse_client(client): def test_reuse_client(client):

View file

@ -41,10 +41,10 @@ def test_method_based_view(app):
def test_view_patching(app): def test_view_patching(app):
class Index(flask.views.MethodView): class Index(flask.views.MethodView):
def get(self): def get(self):
1 // 0 raise ZeroDivisionError
def post(self): def post(self):
1 // 0 raise ZeroDivisionError
class Other(Index): class Other(Index):
def get(self): def get(self):

View file

@ -1,7 +1,5 @@
from __future__ import annotations from __future__ import annotations
import typing as t
from flask import Flask from flask import Flask
from flask import Response from flask import Response
@ -29,10 +27,10 @@ async def before_async() -> None:
@app.teardown_appcontext @app.teardown_appcontext
def teardown_sync(exc: t.Optional[BaseException]) -> None: def teardown_sync(exc: BaseException | None) -> None:
... ...
@app.teardown_appcontext @app.teardown_appcontext
async def teardown_async(exc: t.Optional[BaseException]) -> None: async def teardown_async(exc: BaseException | None) -> None:
... ...

View file

@ -29,12 +29,12 @@ def hello_json() -> Response:
@app.route("/json/dict") @app.route("/json/dict")
def hello_json_dict() -> t.Dict[str, t.Any]: def hello_json_dict() -> dict[str, t.Any]:
return {"response": "Hello, World!"} return {"response": "Hello, World!"}
@app.route("/json/dict") @app.route("/json/dict")
def hello_json_list() -> t.List[t.Any]: def hello_json_list() -> list[t.Any]:
return [{"message": "Hello"}, {"message": "World"}] return [{"message": "Hello"}, {"message": "World"}]

11
tox.ini
View file

@ -17,15 +17,8 @@ constrain_package_deps = true
use_frozen_constraints = true use_frozen_constraints = true
deps = deps =
-r requirements/tests.txt -r requirements/tests.txt
min: -r requirements/tests-pallets-min.txt min: -r requirements-skip/tests-min.txt
dev: https://github.com/pallets/werkzeug/archive/refs/heads/main.tar.gz dev: -r requirements-skip/tests-dev.txt
dev: https://github.com/pallets/jinja/archive/refs/heads/main.tar.gz
dev: https://github.com/pallets/markupsafe/archive/refs/heads/main.tar.gz
dev: https://github.com/pallets/itsdangerous/archive/refs/heads/main.tar.gz
dev: https://github.com/pallets/click/archive/refs/heads/main.tar.gz
# examples/tutorial[test]
# examples/javascript[test]
# commands = pytest -v --tb=short --basetemp={envtmpdir} {posargs:tests examples}
commands = pytest -v --tb=short --basetemp={envtmpdir} {posargs:tests} commands = pytest -v --tb=short --basetemp={envtmpdir} {posargs:tests}
[testenv:style] [testenv:style]