Compare commits

...

857 commits
2.1.3 ... main

Author SHA1 Message Date
David Lord
36e4a824f3
Any for CertParamType type 2026-05-31 07:42:46 -07:00
David Lord
954f5684e4
update dev dependencies 2026-05-18 16:35:44 -07:00
David Lord
9fcd34c9f3
Merge branch 'stable' 2026-05-13 07:37:53 -07:00
David Lord
1d49747264
update flask-mongoengine link 2026-05-13 07:37:21 -07:00
David Lord
7374c85dde
remove leftover setuptools 2026-05-02 05:59:12 -07:00
David Lord
dcbede0cb0
autoescape selection uses case-insensitive comparison (#6013) 2026-05-01 20:58:56 -07:00
David Lord
9368fb3f3c
case-insensitive comparison 2026-05-01 20:56:39 -07:00
David Lord
06ea505ce2
separate copy per call 2026-05-01 20:31:50 -07:00
David Lord
2ac89889f4
Merge branch 'stable' 2026-04-08 21:04:03 -07:00
David Lord
689362089e
fix typo 2026-04-08 21:01:29 -07:00
David Lord
258d68b6ff
Merge branch 'stable' 2026-04-05 12:32:14 -07:00
David Lord
a31e6b7346
remove werkzeug host tests 2026-04-05 12:31:01 -07:00
David Lord
e4e4bf6543
Merge branch 'stable' 2026-04-05 11:24:48 -07:00
David Lord
b21425d6df
reduce venv size 2026-04-05 11:13:13 -07:00
David Lord
83dbcb222a
update dev dependencies 2026-04-03 15:59:16 -07:00
David Lord
7ef2946fb5
remove unicode host test (#5962) 2026-03-24 06:55:57 -07:00
David Lord
91c6b3fecf
remove unicode host test 2026-03-24 06:51:39 -07:00
David Lord
4cae5d8e41
Merge branch 'stable' 2026-03-08 16:21:50 -07:00
David Lord
a197702e2c
update dev dependencies 2026-03-08 16:20:07 -07:00
David Lord
4774385abd
add zizmor to scan workflows (#5945) 2026-03-08 16:15:00 -07:00
David Lord
560c119e3d
add zizmor to scan workflows 2026-03-08 16:05:00 -07:00
David Lord
3a9d54f3da
Merge branch 'stable' 2026-03-04 07:36:21 -08:00
David Lord
a29f88ce6f
document that headers must be set before streaming 2026-03-04 07:36:09 -08:00
David Lord
c34d6e81fd
all teardown callbacks are called despite errors (#5928) 2026-02-19 20:00:34 -08:00
David Lord
fbb6f0bc4c
all teardown callbacks are called despite errors 2026-02-19 19:41:50 -08:00
David Lord
7b0088693e
fix typing 2026-02-19 08:42:33 -08:00
David Lord
a411a2434b
add back opening session on context push 2026-02-19 08:35:48 -08:00
David Lord
daca74d93a
Merge branch 'stable' 2026-02-18 21:56:24 -08:00
David Lord
f00ad424ee
release version 3.1.3 (#5924) 2026-02-18 21:01:53 -08:00
David Lord
22d924701a
release version 3.1.3 2026-02-18 19:41:55 -08:00
David Lord
089cb86dd2
Merge commit from fork
request context tracks session access
2026-02-18 19:35:58 -08:00
David Lord
c17f379390
request context tracks session access 2026-02-18 19:02:54 -08:00
David Lord
27be933840
start version 3.1.3 2026-02-18 14:52:52 -08:00
David Lord
d98eb69a35
revert cli test change 2026-02-12 13:11:01 -08:00
David Lord
12e95c93b4
fix provide_automatic_options override (#5917) 2026-02-12 13:07:50 -08:00
David Lord
e82db2ca3a
fix provide_automatic_options override 2026-02-12 13:03:03 -08:00
David Lord
d3b78fd18a
Merge remote-tracking branch 'origin/stable' 2026-02-06 13:22:54 -08:00
David Lord
663198d7b4
update dev dependencies 2026-02-03 10:22:19 -08:00
David Lord
976459f7cb
fix editable werkzeug 2026-02-03 10:20:49 -08:00
David Lord
5e621a2801
update domain matching tests for Werkzeug 3.2 2026-02-03 10:19:45 -08:00
David Lord
4e652d3f68
Abort if the instance folder cannot be created (#5903) 2026-01-28 07:43:00 -08:00
Markus Heidelberg
3d03098a97 Abort if the instance folder cannot be created
According to the comment, the instance folder should exist in any case.
But a PermissionError was ignored silently.

Since Python 3.9 is the minimum required version, it is safe to use
"exist_ok" added in Python 3.2 and avoid exception handling.
2026-01-27 09:18:37 +01:00
David Lord
798e006f43
Merge branch 'stable' 2026-01-25 10:38:42 -08:00
David Lord
407eb76b27
document using gevent for async (#5900) 2026-01-25 10:35:12 -08:00
David Lord
ac5664d228
document using gevent for async 2026-01-25 10:33:13 -08:00
David Lord
23df07d799
Merge branch 'stable' 2026-01-24 19:55:36 -08:00
David Lord
4b8bde97d4
deprecate should_ignore_error (#5899) 2026-01-24 19:53:11 -08:00
David Lord
0292047b22
remove unused ruff check rule 2026-01-24 19:52:11 -08:00
David Lord
c77a520343
deprecate should_ignore_error 2026-01-24 19:50:30 -08:00
David Lord
9b74a90dd3
fix codespell findings 2026-01-24 19:11:02 -08:00
David Lord
5880befcd2
Merge branch 'stable' 2026-01-24 19:05:26 -08:00
David Lord
4f79d5b59a
Increase required flit_core version to 3.11 (#5865) 2026-01-24 19:04:07 -08:00
Markus Heidelberg
fe3b215d3a
Increase required flit_core version to 3.11
Needed since Flask 3.1.1 after having set the "license" keyword to an
SPDX license expression. Avoids this possible build error:

  flit_core.config.ConfigError: license field should be <class 'dict'>, not <class 'str'>

Fixes: 0109e496f ("use uv").
2026-01-24 19:02:37 -08:00
David Lord
5559ef42b5
pre-commit: Add codespell (#5844) 2026-01-24 19:00:23 -08:00
David Lord
3709c4a9a8
update ruff hook and noqa
co-authored-by: Christian Clauss <cclauss@me.com>
2026-01-24 18:58:45 -08:00
Christian Clauss
709f83f6a3
pre-commit: Add codespell 2026-01-24 18:53:30 -08:00
ADITYA SAH
30da640ffe
clarify 415 vs 400 errors for request.json (#5827) 2026-01-24 18:46:56 -08:00
David Lord
25642fd1fd
fix annotation for select_jinja_autoescape (#5808) 2026-01-24 18:25:31 -08:00
David Lord
809d5a8869
redirect defaults to 303 (#5898) 2026-01-24 17:18:35 -08:00
David Lord
eca5fd1dfd
redirect defaults to 303 2026-01-24 17:16:38 -08:00
David Lord
eb58d862cc
Merge branch 'stable' 2026-01-24 17:15:54 -08:00
David Lord
64dd0809c2
update dev dependencies 2026-01-24 17:14:20 -08:00
David Lord
97bddc1f61
update dev dependencies 2026-01-05 08:50:52 -08:00
David Lord
ad68a12645
drop experimental 3.13t test env 2025-11-28 11:05:52 -08:00
David Lord
2579ce9f18
Merge branch 'stable' 2025-11-17 10:05:51 -08:00
David Lord
607d1948b8
split free threading envs 2025-11-17 10:05:39 -08:00
David Lord
218880c7fd
Merge branch 'stable' 2025-11-17 10:03:42 -08:00
David Lord
917000097f
test py3.14 2025-11-17 10:02:53 -08:00
David Lord
96a01e420b
Merge branch 'stable' 2025-11-17 09:45:56 -08:00
David Lord
da6d075dfd
update dev dependencies 2025-11-17 09:43:40 -08:00
David Lord
70d04b5a26
pass context through dispatch methods (#5818) 2025-11-17 08:49:53 -08:00
Hynek Schlawack
88a65bb374
Docs typo/markup fixes (#5829) 2025-10-14 13:26:26 -07:00
David Lord
6a64969009
pass context through dispatch methods 2025-09-19 17:33:30 -07:00
David Lord
adf363679d
merge app and request context (#5812) 2025-09-19 16:45:27 -07:00
David Lord
c2705ffd9c
merge app and request context 2025-09-19 16:43:53 -07:00
subhajitsaha01
dbd4c28825 Changed the static annotated type of select_jinja_autoescape method in src/flask/sansio/app.py 2025-09-06 22:01:22 +05:30
David Lord
330123258e
Merge branch 'stable' 2025-08-19 14:09:56 -07:00
David Lord
85793d6c22
release version 3.1.2 (#5800) 2025-08-19 14:03:43 -07:00
David Lord
2c1b30d050
release version 3.1.2 2025-08-19 13:57:47 -07:00
David Lord
1292419ddf
Update GitHub Actions workflow for artifact handling (#5795) 2025-08-19 13:56:49 -07:00
Grant Birkinbine
4dd52ca9c7
Update GitHub Actions workflow for artifact handling 2025-08-19 13:50:03 -07:00
David Lord
55c6255657
update dev dependencies 2025-08-19 13:41:24 -07:00
David Lord
ed1c9e953e
support call template_filter without parens (#5736) 2025-08-19 12:36:00 -07:00
David Lord
edebd37044
rewrite docs, clean up typing for template decorators 2025-08-19 12:33:21 -07:00
kadai0308
daf1510a4b
use template_filter without parens 2025-08-19 12:33:21 -07:00
David Lord
d8259eb119
use Jinja name consistently 2025-08-19 10:43:16 -07:00
David Lord
38b4c1e19b
refactor stream_with_context for async views (#5799) 2025-08-19 08:23:51 -07:00
David Lord
9822a03515
refactor stream_with_context for async views 2025-08-19 08:18:55 -07:00
David Lord
49b7e7bc8f
security docs for TRUSTED_HOSTS (#5798) 2025-08-18 11:44:57 -07:00
David Lord
b228ca3d87
security docs for TRUSTED_HOSTS 2025-08-18 11:42:48 -07:00
David Lord
ff64079a51
update flask-talisman link 2025-08-18 10:51:12 -07:00
David Lord
1dfd7cd555
use IO[bytes] instead of BinaryIO for wider compatibility (#5777) 2025-08-18 10:26:12 -07:00
Tero Vuotila
d44f1c6523
relax type hint for bytes io 2025-08-18 10:22:59 -07:00
David Lord
c56c5ec7c4
Docs: Fix escaping in HTML escaping example (#5742) 2025-08-18 10:20:06 -07:00
Badhreesh
0f83958247
demonstrate escaping with query string
slash in value would be interpreted as a path separator in the URL
2025-08-18 10:19:18 -07:00
David Lord
7fea7cf156
Update macOS UI reference to “System Settings” (#5723) 2025-08-18 10:08:07 -07:00
David Lord
24824ff666
push preserved contexts in correct order (#5797) 2025-08-18 09:56:39 -07:00
David Lord
53b8f08218
push preserved contexts in correct order 2025-08-18 09:45:56 -07:00
David Lord
5addaf833b
start version 3.1.2 2025-08-18 09:42:21 -07:00
David Lord
85c5d93cbd
Merge branch 'stable' 2025-06-12 13:48:07 -07:00
David Lord
85cc710464
svg logo 2025-06-12 13:46:49 -07:00
David Lord
284273e3c5
Merge branch 'stable' 2025-06-10 13:18:26 -07:00
David Lord
f17d986948
cleanup svg 2025-06-10 13:18:15 -07:00
David Lord
d6009c0aeb
Merge branch 'stable' 2025-06-09 21:20:46 -07:00
David Lord
2b42a803a2
cleanup svg 2025-06-09 21:20:36 -07:00
David Lord
211cce038a
Merge branch 'stable' 2025-06-09 14:33:44 -07:00
David Lord
a7b67c99f9
svg logo (#5757) 2025-06-09 14:33:26 -07:00
David Lord
a758915893
svg logo 2025-06-09 14:31:31 -07:00
David Lord
e974128863
Merge branch 'stable' 2025-06-08 09:54:32 -07:00
David Lord
f04c5e6964
update dev dependencies 2025-06-08 09:52:11 -07:00
David Lord
c07b201ce3
Merge pull request #5754
remove slsa provenance
2025-06-08 09:47:45 -07:00
David Lord
adeea00707
remove slsa provenance
PyPI trusted publishing has its own attestation support now.
2025-06-08 09:43:05 -07:00
abhiram kamini
7bf3be8dfa
Update server.rst
made changes to rename system preferences to system settings according to new mac os name change
2025-06-04 17:24:45 -07:00
David Lord
a42c4d54a3
Fix global CONTRIBUTING link (#5737) 2025-05-20 12:30:04 -04:00
AJ Jordan
184ec3c545
Fix global CONTRIBUTING link 2025-05-20 12:26:17 -04:00
David Lord
a5f9742398
drop end of life python versions (#5731) 2025-05-13 08:35:41 -07:00
David Lord
52df9eed45
drop end of life python versions 2025-05-13 08:31:54 -07:00
David Lord
e7e5380776
Merge branch 'stable' 2025-05-13 08:10:30 -07:00
David Lord
bbaf13333f
fix syntax 2025-05-13 08:09:39 -07:00
David Lord
57e7286948
release version 3.1.1 (#5730) 2025-05-13 08:01:42 -07:00
David Lord
7fff56f517
release version 3.1.1 2025-05-13 07:51:12 -07:00
David Lord
73d6504063
Merge commit from fork
Sessions: fix signing key selection when key rotation is enabled
2025-05-13 07:46:54 -07:00
David Lord
cbb6c36692
update docs about fallback order 2025-05-12 18:30:27 -07:00
James Addison
fb54159861
secret key rotation: fix key list ordering
The `itsdangerous` serializer interface[1] expects keys to be
provided with the oldest key at index zero and the active signing key
at the end of the list.

We document[2] that `SECRET_KEY_FALLBACKS` should be configured with
the most recent first (at index zero), so to achieve the expected
behaviour, those should be inserted in reverse-order at the head of
the list.

[1] - https://itsdangerous.palletsprojects.com/en/stable/serializer/#itsdangerous.serializer.Serializer

[2] - https://flask.palletsprojects.com/en/stable/config/#SECRET_KEY_FALLBACKS
2025-05-12 18:30:27 -07:00
David Lord
bc143499cf
Merge branch 'stable' 2025-05-11 18:08:43 -07:00
David Lord
941efd4a36
use uv (#5727) 2025-05-11 18:04:35 -07:00
David Lord
0109e496f6
use uv 2025-05-11 17:58:53 -07:00
David Lord
11c45eeba3
update dev dependencies 2025-05-11 05:58:48 -07:00
David Lord
b78b5a210b
Merge branch 'stable' 2025-03-30 13:17:17 -07:00
David Lord
e785166507
Async Iterable Response (#5659) 2025-03-30 13:15:54 -07:00
CoolCat467
410e5ab7ed
Accept AsyncIterable for responses 2025-03-30 13:14:25 -07:00
David Lord
bfffe87d4c
add ghsa links 2025-03-29 15:57:16 -07:00
David Lord
73ce26c3e8
remove tests about deprecated pkgutil.get_loader (#5702) 2025-03-29 15:45:11 -07:00
David Lord
41ec5760a2
remove tests about deprecated pkgutil.get_loader 2025-03-29 15:42:58 -07:00
David Lord
2732c4db66
add endpoint name in favicon example (#5701) 2025-03-29 15:32:28 -07:00
David Lord
c94d2a77db
add endpoint name in favicon example 2025-03-29 15:30:56 -07:00
David Lord
315ebc1176
better type checking during deprecation (#5700) 2025-03-29 15:28:27 -07:00
David Lord
7d5d187458
better type checking during deprecation 2025-03-29 15:23:34 -07:00
David Lord
c7c8dc38ea
Remove HTTP Public Key Pinning from docs (#5695) 2025-03-29 15:17:48 -07:00
black
2ae36c8dd5
Remove HTTP Public Key Pinning from docs
The header is considered obsolete and no longer supported by any major
browser. MDN link is dead.
2025-03-29 15:16:24 -07:00
David Lord
5ea0ab8ea2
Handle help arg by itself the same as no args (#5674) 2025-03-29 15:15:04 -07:00
George Waters
da60039486
Handle help arg by itself the same as no args
When the 'flask' command is used with only the '--help' parameter, this
change will make sure to try and load the app before the help callback
is run. This was previously only being done when the 'flask' command was
used by itself. This meant when passing in '--help', any custom commands
were not getting shown in the help message. With this change, custom
commands will be included in the help message when running 'flask' on
the command line by itself or with the '--help' parameter.
2025-03-29 15:13:23 -07:00
David Lord
08c480b3b3
Update app factory docs (#5671) 2025-03-29 15:10:55 -07:00
kotvkvante
f51a23839a fix bash cli syntax error and app name 2025-03-29 15:09:26 -07:00
David Lord
04b070fa26
Fix typo in the docs (#5650) 2025-03-29 14:49:06 -07:00
zhuangzhuang
75a8327cfd
Update mongoengine.rst 2025-03-29 14:47:41 -07:00
David Lord
165af0a090
update dev dependencies 2025-03-29 14:44:59 -07:00
David Lord
235c52fa10
fix rtd build 2025-03-29 14:37:13 -07:00
David Lord
f61172b8dd
Merge branch 'stable' 2025-01-05 09:10:00 -08:00
David Lord
959052fb8d
use global contributing guide
Remove the per-project files so we don't have to
keep them in sync. GitHub's UI links to everything
except the contributing guide, so add a section
about that to the readme.

(cherry picked from commit 60a11a730e)
2025-01-05 09:09:33 -08:00
David Lord
5b525e9797
markdown formatting
(cherry picked from commit 6b361ce06b)
2025-01-05 09:09:32 -08:00
David Lord
60a11a730e
use global contributing guide
Remove the per-project files so we don't have to
keep them in sync. GitHub's UI links to everything
except the contributing guide, so add a section
about that to the readme.
2025-01-05 09:02:41 -08:00
David Lord
6b361ce06b
markdown formatting 2025-01-05 09:01:49 -08:00
David Lord
6b054f8f38
Merge branch 'stable' 2024-11-23 17:54:29 -08:00
David Lord
f2674c5bb4
fix type hint for cli_runner.invoke (#5647) 2024-11-23 17:52:56 -08:00
kurtatter
54c3f87af9
fix type hint for cli_runner.invoke 2024-11-23 17:50:40 -08:00
David Lord
ea08f155d8
update __version__ deprecation (#5649) 2024-11-23 16:06:37 -08:00
David Lord
b394a994e6
update __version__ deprecation 2024-11-23 16:03:47 -08:00
David Lord
dcbe86bd15
start version 3.1.1 2024-11-23 16:01:16 -08:00
David Lord
d5b7a05ab2
remove previously deprecated code (#5648) 2024-11-23 15:59:30 -08:00
David Lord
d22bfcd4cf
remove previously deprecated code 2024-11-23 15:41:36 -08:00
David Lord
4fec712f32
start version 3.2.0 2024-11-23 15:33:38 -08:00
David Lord
18ffe1eaf6
add gettext config for docs 2024-11-20 19:37:06 -08:00
David Lord
bc098406af
release version 3.1.0 (#5640) 2024-11-13 10:27:38 -08:00
David Lord
ab81496641
release version 3.1.0 2024-11-13 10:20:07 -08:00
David Lord
70602a196a
remove test pypi 2024-11-13 09:23:24 -08:00
David Lord
6748a09341
update dev dependencies 2024-11-13 08:48:10 -08:00
David Lord
22c48a738b
Merge remote-tracking branch 'origin/stable' 2024-11-13 08:43:48 -08:00
David Lord
2eab96a32a
use generic bases for session (#5638) 2024-11-13 08:27:11 -08:00
David Lord
f49dbfd3e4
use generic bases for session 2024-11-13 08:22:57 -08:00
David Lord
7b21d43d4c
configure and check request.trusted_hosts (#5637) 2024-11-12 21:03:23 -08:00
David Lord
4f7156f2c3
configure and check trusted_hosts 2024-11-12 21:01:55 -08:00
David Lord
10bdf61a0f
setting SERVER_NAME does not restrict routing for both subdomain_matching and host_matching (#5634) 2024-11-12 10:13:39 -08:00
David Lord
4995a775df
fix subdomain_matching=False behavior 2024-11-12 08:58:08 -08:00
David Lord
07c7d5730a
update min blinker version (#5633) 2024-11-08 09:55:00 -08:00
David Lord
470e2b8d17
update min blinker version 2024-11-08 09:48:59 -08:00
David Lord
a20bcff8dc
enable secret key rotation (#5632) 2024-11-08 08:16:04 -08:00
David Lord
e13373f838
enable secret key rotation 2024-11-08 08:09:01 -08:00
David Lord
7522c4bcdb
update env file precedence (#5630) 2024-11-07 11:56:26 -08:00
David Lord
2c31603042
update env file precedence 2024-11-07 11:54:29 -08:00
David
6c44dd4bb8
update helpers.send_from_directory docstring (#5599)
Update helpers.send_from_directory docstring to match werkzeug.utils.send_from_directory docstring on the :param directory: line.
2024-11-06 09:47:57 -08:00
David Lord
98ae718976
fix mypy finding 2024-11-01 18:06:34 -07:00
David Lord
c62b03bcfd
fix example and tutorial compatibility and update metadata (#5627) 2024-11-01 18:06:11 -07:00
David Lord
a9b99b3489
update example project metadata 2024-11-01 18:00:39 -07:00
David Lord
8aa161a437
add sqlite datetime converter 2024-11-01 17:18:52 -07:00
David Lord
df201ed152
fix js example test 2024-11-01 16:44:17 -07:00
David Lord
ce08bc704e
add SESSION_COOKIE_PARTITIONED config (#5499) 2024-11-01 16:26:37 -07:00
David Lord
9efc1ebeeb
add SESSION_COOKIE_PARTITIONED config
co-authored-by: Jose Cespedes <josecespedes@ibm.com>
2024-11-01 16:24:15 -07:00
David Lord
6f2014d353
add config and docs for limits (#5626) 2024-11-01 13:21:35 -07:00
David Lord
c7a53888a1
add config and docs for limits 2024-11-01 13:17:53 -07:00
David Lord
62c56e08c4
update minimum dependencies (#5624) 2024-10-31 13:15:29 -07:00
David Lord
8f37c82f61
update min dependencies 2024-10-31 13:11:06 -07:00
David Lord
39e7208366
update dev dependencies 2024-10-31 13:08:52 -07:00
David Lord
227838c472
no need for separate requirements-skip folder anymore 2024-10-31 13:08:52 -07:00
David Lord
99ce7ed0e4
drop support for Python 3.8 (#5623) 2024-10-31 12:32:10 -07:00
David Lord
1d610e44b3
drop support for Python 3.8 2024-10-31 12:30:53 -07:00
David Lord
e8b91cd38a
fix pyright type errors (#5620) 2024-10-24 14:54:53 -07:00
bre-17387639
9e831e915f
fix pyright type errors 2024-10-24 14:46:34 -07:00
David Lord
5e8cb74018
update test workflow trigger 2024-10-24 13:29:34 -07:00
David Lord
2778b7c23f
Merge branch 'stable' 2024-10-24 13:28:57 -07:00
David Lord
96800fb673
update test workflow trigger 2024-10-24 13:28:46 -07:00
David Lord
8f2bc008ad
update dev dependencies 2024-10-24 13:27:52 -07:00
David Lord
9b5549313e
Merge branch '3.0.x' 2024-10-23 13:45:17 -07:00
David Lord
68150d4caf
Fix the issue link in the Flask 3.0.1 Changelog in the send_file argu… (#5618) 2024-10-22 14:16:56 -07:00
Catarina Bressan
74721b48f0 Fix the issue link in the Flask 3.0.1 Changelog in the send_file argument type entry 2024-10-22 17:32:02 -03:00
David Lord
d273f87a41
use python 3.9 to test dev versions (#5615) 2024-10-18 13:22:45 -07:00
David Lord
52ccd66735
use python 3.9 to test dev versions 2024-10-18 13:19:51 -07:00
David Lord
dffe303482
fix mypy findings 2024-10-18 13:04:35 -07:00
David Lord
52c060f718
Fix typo in the changelog (#5609) 2024-10-18 12:59:21 -07:00
David Lord
c5a5576522
update CHANGES.rst 2024-10-18 10:03:49 -07:00
David Lord
bca18041b0
Merge branch '3.0.x' 2024-10-18 10:03:09 -07:00
David Lord
b337d21058
update dev dependencies 2024-10-18 10:02:35 -07:00
Grey Li
e63ead4208 Fix typo in the changelog 2024-09-24 08:54:01 +08:00
David Lord
2fec0b206c
set up pre-commit lite workflow
Committed via https://github.com/asottile/all-repos
2024-09-01 09:04:14 -07:00
David Lord
111e5bd312
set up pre-commit lite workflow
Committed via https://github.com/asottile/all-repos
2024-09-01 08:48:02 -07:00
David Lord
db49548d71
set up pre-commit lite workflow
Committed via https://github.com/asottile/all-repos
2024-09-01 08:32:27 -07:00
David Lord
f93dd6e826
remove pre-commit.ci update 2024-08-23 18:05:21 -07:00
David Lord
7e53070307
Merge branch '3.0.x' 2024-08-23 17:20:31 -07:00
David Lord
c77b099cbb
remove min python for pip-compile 2024-08-23 17:18:38 -07:00
David Lord
eeb5f95a0f
Merge branch '3.0.x' 2024-08-23 16:41:53 -07:00
David Lord
40b78fa2ea
fix min python for pip-compile 2024-08-23 16:41:39 -07:00
David Lord
4e6384da32
Merge branch '3.0.x' 2024-08-23 16:34:57 -07:00
David Lord
2c5d652493
remove unused config 2024-08-23 16:33:59 -07:00
David Lord
176fdfa000
fix mypy findings 2024-08-23 16:33:52 -07:00
David Lord
2d31dce826
remove dependabot 2024-08-23 16:33:40 -07:00
David Lord
29a94bd102
update dev dependencies 2024-08-23 16:33:27 -07:00
David Lord
0f2ae2b933
add gha-update 2024-08-23 16:33:00 -07:00
David Lord
8a6cdf1e2a
[pre-commit.ci] pre-commit autoupdate (#5541) 2024-08-06 08:31:00 -07:00
pre-commit-ci[bot]
326ad3f43c
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.5.0 → v0.5.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.5.0...v0.5.6)
2024-08-05 23:09:19 +00:00
David Lord
a791997041
Bump the github-actions group with 3 updates (#5539) 2024-08-03 07:28:45 -07:00
dependabot[bot]
4fe0aebab7
Bump the github-actions group with 3 updates
Bumps the github-actions group with 3 updates: [actions/setup-python](https://github.com/actions/setup-python), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/setup-python` from 5.1.0 to 5.1.1
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](82c7e631bb...39cd14951b)

Updates `actions/upload-artifact` from 4.3.3 to 4.3.4
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](65462800fd...0b2256b8c0)

Updates `actions/download-artifact` from 4.1.7 to 4.1.8
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](65a9edc588...fa0a91b85d)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-01 15:48:34 +00:00
David Lord
a8956feba1
Add encoding parameter to open resource (#5526) 2024-07-10 19:16:46 -07:00
David Lord
28d5a4d718
add encoding parameter to open_resource
co-authored-by: mark <lopkophacked@protonmail.com>
2024-07-10 19:14:06 -07:00
David Lord
5353f306fe
Update waitress.rst (#5522) 2024-07-10 18:08:49 -07:00
Amirreza A
321bd74b95
Update waitress.rst
fixed a small typo
2024-07-10 18:06:15 -07:00
David Lord
66af0e55ef
[pre-commit.ci] pre-commit autoupdate (#5517) 2024-07-02 04:17:59 -07:00
pre-commit-ci[bot]
3d357273b5
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.7 → v0.5.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.7...v0.5.0)
2024-07-02 00:15:33 +00:00
David Lord
926ab92118
Bump the python-requirements group in /requirements with 5 updates (#5514) 2024-07-01 16:14:08 -07:00
David Lord
088b58dbce
Bump the github-actions group with 2 updates (#5516) 2024-07-01 12:47:02 -07:00
dependabot[bot]
7621b3d96a
Bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish).


Updates `actions/checkout` from 4.1.6 to 4.1.7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](a5ac7e51b4...692973e3d9)

Updates `pypa/gh-action-pypi-publish` from 1.8.14 to 1.9.0
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](81e9d935c8...ec4db0b4dd)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 15:56:20 +00:00
dependabot[bot]
e165f3aef4
Bump the python-requirements group in /requirements with 5 updates
Bumps the python-requirements group in /requirements with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [cryptography](https://github.com/pyca/cryptography) | `42.0.7` | `42.0.8` |
| [mypy](https://github.com/python/mypy) | `1.10.0` | `1.10.1` |
| [pyright](https://github.com/RobertCraigie/pyright-python) | `1.1.365` | `1.1.369` |
| [pytest](https://github.com/pytest-dev/pytest) | `8.2.1` | `8.2.2` |
| [tox](https://github.com/tox-dev/tox) | `4.15.0` | `4.15.1` |


Updates `cryptography` from 42.0.7 to 42.0.8
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/42.0.7...42.0.8)

Updates `mypy` from 1.10.0 to 1.10.1
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.10.0...v1.10.1)

Updates `pyright` from 1.1.365 to 1.1.369
- [Release notes](https://github.com/RobertCraigie/pyright-python/releases)
- [Commits](https://github.com/RobertCraigie/pyright-python/compare/v1.1.365...v1.1.369)

Updates `pytest` from 8.2.1 to 8.2.2
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.2.1...8.2.2)

Updates `tox` from 4.15.0 to 4.15.1
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/4.15.0...4.15.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: pyright
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: tox
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: python-requirements
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 15:28:16 +00:00
pgjones
d718ecf6d3 Provide a configuration option to control automatic option responses
By default Flask will provide responses to OPTIONS requests that are
automatically generated. These responses list the valid methods in the
response headers. Whilst this is useful, it can be frowned on by
auditors hence an ability to disable it wholesale is useful.
2024-06-07 19:04:18 +00:00
David Lord
0ce27278d2
[pre-commit.ci] pre-commit autoupdate (#5495) 2024-06-03 15:25:32 -07:00
pre-commit-ci[bot]
07c8f19bfd
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.4.3 → v0.4.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.4.3...v0.4.7)
2024-06-03 22:10:27 +00:00
David Lord
0d2100ed17
Bump actions/checkout from 4.1.4 to 4.1.6 in the github-actions group (#5493) 2024-06-01 09:01:46 -07:00
dependabot[bot]
e3535f9971
Bump actions/checkout from 4.1.4 to 4.1.6 in the github-actions group
Bumps the github-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 4.1.4 to 4.1.6
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](0ad4b8fada...a5ac7e51b4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-01 15:55:45 +00:00
David Lord
422e05e28d
Bump the python-requirements group in /requirements with 3 updates (#5492) 2024-06-01 08:16:45 -07:00
dependabot[bot]
f567ab9068
Bump the python-requirements group in /requirements with 3 updates
Bumps the python-requirements group in /requirements with 3 updates: [pyright](https://github.com/RobertCraigie/pyright-python), [pytest](https://github.com/pytest-dev/pytest) and [pre-commit](https://github.com/pre-commit/pre-commit).


Updates `pyright` from 1.1.361 to 1.1.365
- [Release notes](https://github.com/RobertCraigie/pyright-python/releases)
- [Commits](https://github.com/RobertCraigie/pyright-python/compare/v1.1.361...v1.1.365)

Updates `pytest` from 8.2.0 to 8.2.1
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.2.0...8.2.1)

Updates `pre-commit` from 3.7.0 to 3.7.1
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v3.7.0...v3.7.1)

---
updated-dependencies:
- dependency-name: pyright
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: pre-commit
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: python-requirements
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-01 15:12:17 +00:00
David Lord
6d126e1013
Added python type annotation and return type. (#5485) 2024-05-25 11:32:15 -07:00
Heisenberg
c7da8c2aa3
Added python type annotation and return type. 2024-05-25 11:28:19 -07:00
David Lord
bb16048ad7
Edited variable names in quickstart guide (#5487) 2024-05-25 11:27:37 -07:00
Jake Tanis
767ad19b10
Edited variable names in the rendering templates section of the quickstart guide. 2024-05-25 11:25:24 -07:00
David Lord
a2f495b9ff
SESSION_COOKIE_DOMAIN caveat documentation (#5464) 2024-05-25 10:27:04 -07:00
Éloi Rivard
4a1766c252
document caveats on SESSION_COOKIE_DOMAIN
Changing this value might result in browsers with several competing session cookies. In
that situation there is no guarantee of which one will be sent first, and be used as the
session cookie.
2024-05-25 10:23:44 -07:00
David Lord
255c8d66af
Merge branch '3.0.x' 2024-05-11 08:40:26 -07:00
David Lord
bea5876e46
test with python 3.13 (#5481) 2024-05-11 08:39:30 -07:00
David Lord
9101439d7b
test with python 3.13 2024-05-11 08:37:47 -07:00
David Lord
67ed36910d
[pre-commit.ci] pre-commit autoupdate (#5477) 2024-05-06 15:28:44 -07:00
pre-commit-ci[bot]
4e894892bc
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.3.5 → v0.4.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.3.5...v0.4.3)
2024-05-06 22:05:35 +00:00
David Lord
d64ecfb244
Bump the python-requirements group across 1 directory with 6 updates (#5476) 2024-05-06 10:24:44 -07:00
David Lord
860a25c390
fix mypy finding 2024-05-06 10:23:10 -07:00
dependabot[bot]
273123f6b8
Bump the python-requirements group across 1 directory with 6 updates
Bumps the python-requirements group with 6 updates in the /requirements directory:

| Package | From | To |
| --- | --- | --- |
| [cryptography](https://github.com/pyca/cryptography) | `42.0.5` | `42.0.7` |
| [mypy](https://github.com/python/mypy) | `1.9.0` | `1.10.0` |
| [pallets-sphinx-themes](https://github.com/pallets/pallets-sphinx-themes) | `2.1.2` | `2.1.3` |
| [pyright](https://github.com/RobertCraigie/pyright-python) | `1.1.359` | `1.1.361` |
| [pytest](https://github.com/pytest-dev/pytest) | `8.1.1` | `8.2.0` |
| [tox](https://github.com/tox-dev/tox) | `4.14.2` | `4.15.0` |



Updates `cryptography` from 42.0.5 to 42.0.7
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/42.0.5...42.0.7)

Updates `mypy` from 1.9.0 to 1.10.0
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/1.9.0...v1.10.0)

Updates `pallets-sphinx-themes` from 2.1.2 to 2.1.3
- [Release notes](https://github.com/pallets/pallets-sphinx-themes/releases)
- [Changelog](https://github.com/pallets/pallets-sphinx-themes/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/pallets-sphinx-themes/compare/2.1.2...2.1.3)

Updates `pyright` from 1.1.359 to 1.1.361
- [Release notes](https://github.com/RobertCraigie/pyright-python/releases)
- [Commits](https://github.com/RobertCraigie/pyright-python/compare/v1.1.359...v1.1.361)

Updates `pytest` from 8.1.1 to 8.2.0
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.1.1...8.2.0)

Updates `tox` from 4.14.2 to 4.15.0
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/4.14.2...4.15.0)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-requirements
- dependency-name: pallets-sphinx-themes
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: pyright
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-requirements
- dependency-name: tox
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: python-requirements
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 17:19:27 +00:00
David Lord
fc605b575b
Bump the github-actions group with 2 updates (#5473) 2024-05-06 10:17:48 -07:00
dependabot[bot]
a936b0c610
Bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/checkout` from 4.1.3 to 4.1.4
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](1d96c772d1...0ad4b8fada)

Updates `actions/download-artifact` from 4.1.6 to 4.1.7
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](9c19ed7fe5...65a9edc588)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 17:16:26 +00:00
David Lord
4f42c64203
Merge branch '3.0.x' 2024-05-06 10:13:35 -07:00
David Lord
eb1182a10e
fix mypy finding 2024-05-06 10:12:32 -07:00
David Lord
a363642a32
fix mypy finding with new werkzeug endpoint type 2024-05-06 10:09:58 -07:00
David Lord
57add386c9
examples/javascript: Update Documentation URL in pyproject.toml (#5475) 2024-05-02 05:10:51 -07:00
JamesMRamm
823e279e0d
Update pyproject.toml
Correction to Documentation URL
2024-05-02 17:57:34 +10:00
David Lord
11c15ddfeb
Bump the python-requirements group in /requirements with 3 updates (#5468) 2024-04-23 16:54:09 -07:00
dependabot[bot]
224c639bf9
Bump the python-requirements group in /requirements with 3 updates
Bumps the python-requirements group in /requirements with 3 updates: [pallets-sphinx-themes](https://github.com/pallets/pallets-sphinx-themes), [sphinx](https://github.com/sphinx-doc/sphinx) and [pyright](https://github.com/RobertCraigie/pyright-python).


Updates `pallets-sphinx-themes` from 2.1.1 to 2.1.2
- [Release notes](https://github.com/pallets/pallets-sphinx-themes/releases)
- [Changelog](https://github.com/pallets/pallets-sphinx-themes/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/pallets-sphinx-themes/compare/2.1.1...2.1.2)

Updates `sphinx` from 7.2.6 to 7.3.7
- [Release notes](https://github.com/sphinx-doc/sphinx/releases)
- [Changelog](https://github.com/sphinx-doc/sphinx/blob/master/CHANGES.rst)
- [Commits](https://github.com/sphinx-doc/sphinx/compare/v7.2.6...v7.3.7)

Updates `pyright` from 1.1.357 to 1.1.359
- [Release notes](https://github.com/RobertCraigie/pyright-python/releases)
- [Commits](https://github.com/RobertCraigie/pyright-python/compare/v1.1.357...v1.1.359)

---
updated-dependencies:
- dependency-name: pallets-sphinx-themes
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: sphinx
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-requirements
- dependency-name: pyright
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-23 23:52:58 +00:00
David Lord
f48802acbb
Bump the github-actions group across 1 directory with 4 updates (#5470) 2024-04-23 16:52:13 -07:00
dependabot[bot]
b7278186c4
Bump the github-actions group across 1 directory with 4 updates
Bumps the github-actions group with 4 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/upload-artifact](https://github.com/actions/upload-artifact), [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/checkout` from 4.1.2 to 4.1.3
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](9bb56186c3...1d96c772d1)

Updates `actions/upload-artifact` from 3.1.3 to 4.3.3
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](a8a3f3ad30...65462800fd)

Updates `slsa-framework/slsa-github-generator` from 1.10.0 to 2.0.0
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slsa-framework/slsa-github-generator/compare/v1.10.0...v2.0.0)

Updates `actions/download-artifact` from 3.0.2 to 4.1.6
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](9bc31d5ccc...9c19ed7fe5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: slsa-framework/slsa-github-generator
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-23 23:50:43 +00:00
David Lord
ccf125bf30
fix mypy findings 2024-04-23 16:49:42 -07:00
David Lord
db0fe9436e
unignore upload/download-artifact 2024-04-23 16:31:03 -07:00
David Lord
2c7f57ad5b
Merge branch '3.0.x' 2024-04-08 15:29:31 -07:00
David Lord
f958b6500b
build docs from scratch each test 2024-04-08 15:28:57 -07:00
David Lord
346d1abaff
remove install and contribute sections
install leads people to install into the system instead of a virtualenv,
and readme isn't the place to teach that
contribute is now linked in the github interface above the readme
2024-04-08 15:28:28 -07:00
David Lord
19610a9e46
start version 3.1.0 2024-04-07 12:29:49 -07:00
David Lord
aee16df63b
Merge branch '3.0.x' 2024-04-07 12:28:51 -07:00
David Lord
61182249cb
release version 3.0.3 (#5461) 2024-04-07 12:27:04 -07:00
David Lord
c12a5d874c
release version 3.0.3 2024-04-07 12:17:41 -07:00
David Lord
5e22cc9eec
Don't set the cli attribute in the sansio scaffold (#5270) 2024-04-07 12:16:22 -07:00
pgjones
5fdce4c331
Don't set the cli attribute in the sansio scaffold
It is (currently) Flask specific and hence cannot be shared in the
sansio shared code.
2024-04-07 12:13:02 -07:00
David Lord
adb7dd99c2
don't access app.logger when configuring app.logger 2024-04-07 12:03:19 -07:00
David Lord
b739390955
support FIPS builds without SHA-1 (#5460) 2024-04-07 11:42:24 -07:00
David Lord
db461112c7
access sha1 lazily 2024-04-07 11:41:13 -07:00
David Lord
7320e311a0
start version 3.0.3 2024-04-07 11:22:02 -07:00
David Lord
a855756017
Bump the github-actions group with 3 updates (#5459) 2024-04-07 11:11:26 -07:00
dependabot[bot]
be508c6184
Bump the github-actions group with 3 updates
Bumps the github-actions group with 3 updates: [dessant/lock-threads](https://github.com/dessant/lock-threads), [actions/checkout](https://github.com/actions/checkout) and [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish).


Updates `dessant/lock-threads` from 7de207be1d3ce97a9abe6ff1306222982d1ca9f9 to 1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md)
- [Commits](7de207be1d...1bf7ec2505)

Updates `actions/checkout` from 4.1.1 to 4.1.2
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](b4ffde65f4...9bb56186c3)

Updates `pypa/gh-action-pypi-publish` from 68e62d4871ad9d14a9d55f114e6ac71f0b408ec0 to 81e9d935c883d0b210363ab89cf05f3894778450
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](68e62d4871...81e9d935c8)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-type: direct:production
  dependency-group: github-actions
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-07 18:04:59 +00:00
David Lord
6ab71ed7cf
Merge branch '3.0.x' 2024-04-07 11:03:46 -07:00
David Lord
87d5f5b9a9
update project files (#5457)
* update pre-commit hook
* upgrade pip with venv
* update description and version
* show url in publish environment
* update versions
* update versions, separate typing job
* use dependabot grouped updates
  ignore upload/download-artifact until slsa updates
* use sphinx.ext.extlinks instead of sphinx-issues
* update dev dependencies
* update editorconfig
* update gitignore
* update .readthedocs.yaml
* license is txt, readme is md
* update pyproject.toml
  add typed classifier
  add pyright config
  simplify urls
* tox builds docs in place
* update min test py version
* add tox env to update all dev dependencies
* update issue and pr templates
* rename security docs page to not conflict with org policy file
* simplify matrix
2024-04-07 10:24:40 -07:00
David Lord
98a7f9fcf0
Use per-release URLs in GH env UI when publishing to the PyPI (#5423) 2024-04-06 16:17:13 -07:00
Sviatoslav Sydorenko (Святослав Сидоренко)
0e59442f6c
Use per-release URLs in GH env UI when publishing to the PyPI
This essentially, makes the UI nicer in a few places with a clickable link to the released version being presented in the web interface of GitHub.
2024-02-27 01:24:27 +01:00
David Lord
b90a4f1f4a
[pre-commit.ci] pre-commit autoupdate (#5404) 2024-02-12 12:50:45 -08:00
pre-commit-ci[bot]
ad36383951
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.13 → v0.2.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.13...v0.2.0)
2024-02-05 20:28:43 +00:00
David Lord
6b422a05f3
Merge branch '3.0.x' 2024-02-03 13:13:41 -08:00
David Lord
d5e321b792
release version 3.0.2 (#5403) 2024-02-03 13:12:15 -08:00
David Lord
d2030595dc
release version 3.0.2 2024-02-03 12:54:41 -08:00
David Lord
d7209a9570
fix super call in list comprehension (#5393) 2024-02-03 12:39:33 -08:00
Tony Huang
1af8f95785
fix super call in list comprehension 2024-02-03 12:36:06 -08:00
David Lord
3435d2ff15
Fix jinja_loader typehint (#5389) 2024-02-03 12:18:40 -08:00
Cody Scott
ecc057dd48
fix jinja_loader annotation 2024-02-03 12:14:38 -08:00
David Lord
3207af8827
start version 3.0.2 2024-02-03 09:41:38 -08:00
David Lord
94e80b3da9
Bump the python-requirements group in /requirements with 6 updates (#5401) 2024-02-03 07:40:27 -08:00
David Lord
f32dddc71c
Bump the github-actions group with 2 updates (#5400) 2024-02-03 07:35:16 -08:00
dependabot[bot]
484a7cc9a7
Bump the python-requirements group in /requirements with 6 updates
Bumps the python-requirements group in /requirements with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [sphinx-issues](https://github.com/sloria/sphinx-issues) | `3.0.1` | `4.0.0` |
| [sphinx-tabs](https://github.com/executablebooks/sphinx-tabs) | `3.4.4` | `3.4.5` |
| [cryptography](https://github.com/pyca/cryptography) | `41.0.7` | `42.0.2` |
| [pytest](https://github.com/pytest-dev/pytest) | `7.4.4` | `8.0.0` |
| [python-dotenv](https://github.com/theskumar/python-dotenv) | `1.0.0` | `1.0.1` |
| [tox](https://github.com/tox-dev/tox) | `4.12.0` | `4.12.1` |


Updates `sphinx-issues` from 3.0.1 to 4.0.0
- [Commits](https://github.com/sloria/sphinx-issues/compare/3.0.1...4.0.0)

Updates `sphinx-tabs` from 3.4.4 to 3.4.5
- [Release notes](https://github.com/executablebooks/sphinx-tabs/releases)
- [Changelog](https://github.com/executablebooks/sphinx-tabs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/executablebooks/sphinx-tabs/compare/v3.4.4...v3.4.5)

Updates `cryptography` from 41.0.7 to 42.0.2
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/41.0.7...42.0.2)

Updates `pytest` from 7.4.4 to 8.0.0
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.4.4...8.0.0)

Updates `python-dotenv` from 1.0.0 to 1.0.1
- [Release notes](https://github.com/theskumar/python-dotenv/releases)
- [Changelog](https://github.com/theskumar/python-dotenv/blob/main/CHANGELOG.md)
- [Commits](https://github.com/theskumar/python-dotenv/compare/v1.0.0...v1.0.1)

Updates `tox` from 4.12.0 to 4.12.1
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/4.12.0...4.12.1)

---
updated-dependencies:
- dependency-name: sphinx-issues
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: python-requirements
- dependency-name: sphinx-tabs
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: python-requirements
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: python-requirements
- dependency-name: python-dotenv
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: tox
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: python-requirements
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 15:41:57 +00:00
dependabot[bot]
a4bada52d0
Bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [dessant/lock-threads](https://github.com/dessant/lock-threads) and [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish).


Updates `dessant/lock-threads` from 7de207be1d3ce97a9abe6ff1306222982d1ca9f9 to 1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md)
- [Commits](7de207be1d...1bf7ec2505)

Updates `pypa/gh-action-pypi-publish` from f946db0f765b9ae754e44bfd5ae5b8b91cfb37ef to 2f6f737ca5f74c637829c0f5c3acd0e29ea5e8bf
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](f946db0f76...2f6f737ca5)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-type: direct:production
  dependency-group: github-actions
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 15:31:35 +00:00
David Lord
4df377cfbf
Merge branch '3.0.x' 2024-01-18 12:20:56 -08:00
David Lord
233be7a0fa
release version 3.0.1 (#5386) 2024-01-18 12:03:25 -08:00
David Lord
f622b1cade
release version 3.0.1 2024-01-18 11:57:33 -08:00
David Lord
5fcc999b7d
fix create release action 2024-01-18 11:57:22 -08:00
David Lord
da3a0ddfe2
fix slsa generator version 2024-01-18 11:53:19 -08:00
David Lord
5e059be1b3
update actions versions 2024-01-18 11:41:38 -08:00
David Lord
bae6ee888f
address mypy strict findings (#5383) 2024-01-18 09:16:53 -08:00
David Lord
81b3c85f51
update requirements 2024-01-18 09:15:01 -08:00
David Lord
08d3185e87
update pre-commit hooks 2024-01-16 10:12:10 -08:00
David Lord
6000e80acf
address mypy strict findings 2024-01-16 10:11:13 -08:00
David Lord
7b5e176d1a
[pre-commit.ci] pre-commit autoupdate (#5377) 2024-01-15 07:52:57 -08:00
David Lord
5a48a0fe6b
untag without object_hook (#5382) 2024-01-15 07:52:35 -08:00
David Lord
700fc7d928
untag without object_hook 2024-01-15 07:49:02 -08:00
pre-commit-ci[bot]
8fdab74cc8 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2024-01-01 20:24:30 +00:00
pre-commit-ci[bot]
24ec38d6a0
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.6 → v0.1.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.6...v0.1.9)
2024-01-01 20:24:10 +00:00
David Lord
c2f65dd1cf
Bump the python-requirements group in /requirements with 3 updates (#5374) 2024-01-01 07:21:54 -08:00
dependabot[bot]
63ff4185f9
Bump the python-requirements group in /requirements with 3 updates
Bumps the python-requirements group in /requirements with 3 updates: [pytest](https://github.com/pytest-dev/pytest), [mypy](https://github.com/python/mypy) and [pre-commit](https://github.com/pre-commit/pre-commit).


Updates `pytest` from 7.4.3 to 7.4.4
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.4.3...7.4.4)

Updates `mypy` from 1.7.1 to 1.8.0
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.7.1...v1.8.0)

Updates `pre-commit` from 3.5.0 to 3.6.0
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v3.5.0...v3.6.0)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-requirements
- dependency-name: pre-commit
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: python-requirements
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 15:11:19 +00:00
David Lord
708d62d717
Merge branch '3.0.x' 2023-12-13 16:28:13 -08:00
David Lord
c275573147
run typing tests 2023-12-13 16:27:37 -08:00
David Lord
12a1c4940d
Merge branch '3.0.x' 2023-12-13 15:13:41 -08:00
David Lord
77f6c72cf9
Update docs to address redesigned macOS settings app (#5355) 2023-12-13 15:13:22 -08:00
Ben Huebscher
8a66990c61
Update docs to address redesigned macOS settings app 2023-12-13 15:10:47 -08:00
David Lord
05eebe36ab
fix missing quote in --key error message (#5344) 2023-12-13 15:06:37 -08:00
lizard
1d5abfadd7
Fixing issue 5342: 'The double quote is missing in the string' 2023-12-13 15:05:03 -08:00
David Lord
399aa8531c
Bump the python-requirements group in /requirements with 3 updates (#5351) 2023-12-13 15:01:14 -08:00
dependabot[bot]
b55ccae72a
Bump the python-requirements group in /requirements with 3 updates
Bumps the python-requirements group in /requirements with 3 updates: [cryptography](https://github.com/pyca/cryptography), [mypy](https://github.com/python/mypy) and [tox](https://github.com/tox-dev/tox).

Updates `cryptography` from 41.0.5 to 41.0.7
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/41.0.5...41.0.7)

Updates `mypy` from 1.6.1 to 1.7.1
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.6.1...v1.7.1)

Updates `tox` from 4.11.3 to 4.11.4
- [Release notes](https://github.com/tox-dev/tox/releases)
- [Changelog](https://github.com/tox-dev/tox/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/tox/compare/4.11.3...4.11.4)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: python-requirements
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: python-requirements
- dependency-name: tox
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: python-requirements
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-13 14:58:31 -08:00
David Lord
089f6a1c50
Bump the github-actions group with 2 updates (#5352) 2023-12-04 14:26:30 -08:00
David Lord
b64f848d2c
[pre-commit.ci] pre-commit autoupdate (#5354) 2023-12-04 14:26:15 -08:00
pre-commit-ci[bot]
452b78f243
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.1.5 → v0.1.6](https://github.com/astral-sh/ruff-pre-commit/compare/v0.1.5...v0.1.6)
2023-12-04 20:29:39 +00:00
dependabot[bot]
78ced0093a
Bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [dessant/lock-threads](https://github.com/dessant/lock-threads) and [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish).


Updates `dessant/lock-threads` from 4.0.1 to 5.0.1
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md)
- [Commits](be8aa5be94...1bf7ec2505)

Updates `pypa/gh-action-pypi-publish` from 1.8.10 to 1.8.11
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](b7f401de30...2f6f737ca5)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-01 15:47:14 +00:00
David Lord
d61198941a
Merge branch '3.0.x' 2023-11-15 13:03:05 -08:00
David Lord
b97165db75
type hint fix for flask.send_file (#5336) 2023-11-15 12:55:43 -08:00
Daniel Isaac
4104f29956
type hint fix for flask.send_file 2023-11-15 12:53:22 -08:00
David Lord
66743d4f9d
start version 3.0.1 2023-11-15 12:50:46 -08:00
David Lord
258311d098
Merge branch '3.0.x' 2023-11-15 12:48:42 -08:00
David Lord
5308db0637
update pre-commit hooks 2023-11-15 12:47:41 -08:00
David Lord
59fd6aa104
use pip-compile instead of pip-compile-multi 2023-11-15 12:44:20 -08:00
David Lord
560383fe14
update python version matrix
(cherry picked from commit 6ee5dcc0ec)
2023-11-15 12:19:59 -08:00
David Lord
6277036567
update read the docs env
(cherry picked from commit 29f1bd22d7)
2023-11-15 12:19:59 -08:00
David Lord
ce27ddeba1
Merge branch '3.0.x' 2023-11-15 12:14:51 -08:00
David Lord
54e05a2824
use ruff linter and formatter 2023-11-15 12:14:37 -08:00
David Lord
9a12f34bbe
use ruff linter and formatter (#5331) 2023-11-09 13:29:20 -08:00
David Lord
54ff9b2972
use ruff linter and formatter 2023-11-09 10:27:01 -08:00
David Lord
6edfd78c9f
Bump the github-actions group with 4 updates (#5330) 2023-11-09 09:04:52 -08:00
dependabot[bot]
4431ada1a2
Bump the github-actions group with 4 updates
Bumps the github-actions group with 4 updates: [actions/checkout](https://github.com/actions/checkout), [actions/setup-python](https://github.com/actions/setup-python), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/cache](https://github.com/actions/cache).


Updates `actions/checkout` from 3.6.0 to 4.1.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](f43a0e5ff2...b4ffde65f4)

Updates `actions/setup-python` from 4.7.0 to 4.7.1
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](61a6322f88...65d7f2d534)

Updates `actions/upload-artifact` from 3.1.2 to 3.1.3
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](0b7f8abb15...a8a3f3ad30)

Updates `actions/cache` from 3.3.1 to 3.3.2
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](88522ab9f3...704facf57e)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-09 17:01:38 +00:00
David Lord
24653528cc
use pip-compile and dependabot grouped updates (#5329) 2023-11-09 09:00:37 -08:00
David Lord
33d8886226
enable grouped updates for actions and python 2023-11-09 08:56:36 -08:00
David Lord
04920b3076
use pip-compile instead of pip-compile-multi 2023-11-09 08:56:36 -08:00
David Lord
6ee5dcc0ec
update python version matrix 2023-11-09 08:45:23 -08:00
David Lord
c4bfd367e2
update description 2023-11-09 08:40:39 -08:00
David Lord
29f1bd22d7
update read the docs env 2023-11-09 08:39:48 -08:00
David Lord
8d9519df09
Update link to hypercorn (#5313) 2023-10-28 08:42:53 -07:00
Resistor-git
7af0271f47 Initial commit 2023-10-28 08:04:03 +00:00
Resistor-git
be6ec06894 Fix link to Hypercorn in docs/deploying/asgi.rst - they moved from gitlab from github. 2023-10-28 07:38:33 +00:00
David Lord
beedaa4eff
docs/testing.rst: fix follow_redirects sample code (#5303) 2023-10-20 09:50:00 -07:00
Arnout Engelen
bb9937593d
docs/testing.rst: fix follow_redirects sample code 2023-10-20 17:17:24 +02:00
Iztok Fister Jr
541bc8dfc2
examples/javascript: replace obsolete link (#5287) 2023-10-06 17:36:39 -07:00
Akinola Abiodun Emmanuel
3652ecd9e0
Update index.rst (#5291)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2023-10-06 16:37:42 -07:00
pgjones
14232513fd Release version 3.0.0 2023-09-30 15:37:24 +01:00
pgjones
3252f2bc54 Bump Werkzeug 3.0.0 2023-09-30 15:37:24 +01:00
pgjones
438edcdf01 Allow self as an argument to url_for
This makes the Flask.url_for self argument positional only (Flask
supports Python 3.8+) thereby restoring the ability to pass self as a
value argument to url_for.
2023-09-30 15:25:31 +01:00
nick2202
b7c1290528 Fix wrong spelling of JS method .innerHTML 2023-09-24 15:58:22 +01:00
David Lord
8037487165
Bump pypa/gh-action-pypi-publish from 1.8.8 to 1.8.10 (#5248) 2023-09-05 14:02:38 -07:00
David Lord
e8076d9114
Bump slsa-framework/slsa-github-generator from 1.7.0 to 1.9.0 (#5247) 2023-09-05 14:02:28 -07:00
David Lord
ecc4a38b7c
Bump actions/checkout from 3.5.3 to 3.6.0 (#5246) 2023-09-05 14:01:15 -07:00
dependabot[bot]
24c6508d39
Bump pypa/gh-action-pypi-publish from 1.8.8 to 1.8.10
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.8 to 1.8.10.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](f8c70e705f...b7f401de30)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 16:30:35 +00:00
dependabot[bot]
98cef9fcca
Bump slsa-framework/slsa-github-generator from 1.7.0 to 1.9.0
Bumps [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) from 1.7.0 to 1.9.0.
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slsa-framework/slsa-github-generator/compare/v1.7.0...v1.9.0)

---
updated-dependencies:
- dependency-name: slsa-framework/slsa-github-generator
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 16:30:31 +00:00
dependabot[bot]
0c97a411b4
Bump actions/checkout from 3.5.3 to 3.6.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.3 to 3.6.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](c85c95e3d7...f43a0e5ff2)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-01 16:30:27 +00:00
David Lord
faef9a0fce
deprecate __version__ attribute (#5242) 2023-08-29 06:09:59 -07:00
David Lord
293041a290
deprecate __version__ attribute 2023-08-29 06:03:11 -07:00
David Lord
153433f612
Merge remote-tracking branch 'origin/2.3.x' 2023-08-27 09:21:54 -07:00
pgjones
65271c105f Remove print left in by accident
This was added as per 0ec7f713d6 by
mistake.
2023-08-27 07:12:04 -07:00
David Lord
a6007373b5
release version 2.3.3 (#5232) 2023-08-21 12:52:54 -07:00
David Lord
3205b53c7c
release version 2.3.3 2023-08-21 10:25:35 -07:00
David Lord
9f9550247a
bump werkzeug 2.3.7
use importlib.metadata.version
2023-08-21 10:12:54 -07:00
David Lord
90967ccb9a
bump werkzeug 2.3.7 (#5231) 2023-08-21 09:42:21 -07:00
David Lord
5bb30270d2
bump werkzeug 2.3.7
use importlib.metadata.version
2023-08-21 09:39:10 -07:00
David Lord
1d8b53f782
Split the App and Blueprint into Sansio and IO parts (#5127) 2023-08-20 09:32:09 -07:00
pgjones
bc5dd3894b Add a changelog for the sans-io changes 2023-08-19 19:25:36 +01:00
pgjones
318592511c Add a brief README to the sansio
This should hopefully explain what it is used for and why certain code
cannot be present in it.
2023-08-19 18:35:15 +01:00
pgjones
80cf589a26 Correct the error handler typing
It may also be awaitable, as invocations are wrapped in ensure_sync.
2023-08-19 18:35:15 +01:00
pgjones
cc80a47f5b Widen the response typing
Whilst not strictly true for Flask, it is true for Flask and Quart and
hence makes it much easier for Quart to extend Flask classes. The
alternatives are generic usage in the sansio codebase or mixed usage
within Flask. I think this is a good compromise.
2023-08-19 18:35:15 +01:00
pgjones
3f6b243cec Support async template context processors
This is useful as there is contextual information that could be loaded
via IO e.g. information from a database. This also matches Quart and
hence makes the shared signature easier to manage.
2023-08-19 18:35:15 +01:00
pgjones
72c85e80c8 Provide an extendable merge blueprint funcs method
This allows a Blueprint implementation that has additional funcs, such
as Quart with its before_websocket_funcs (as example), to extend the
merge method to also merge these functions.
2023-08-19 18:35:15 +01:00
pgjones
0ec7f713d6 Split the App and Blueprint into Sansio and IO parts
This follows a similar structure in Werkzeug and allows for async
based IO projects, specifically Quart, to base themselves on
Flask.

Note that the globals, and signals are specific to Flask and hence
specific to Flask's IO. This means they cannot be moved to the sansio
part of the codebase.
2023-08-19 18:35:14 +01:00
pgjones
a64588f87a Move file to sansio
This is preperation for refactoring the files so that there are sansio
and flask specific versions. This structure follows the Werkzeug
structure/pattern.
2023-08-19 18:35:00 +01:00
David Lord
0e0e8ddcdc
remove deprecated code (#5223) 2023-08-16 15:08:52 -07:00
David Lord
04994df59f
remove deprecated code 2023-08-16 15:00:49 -07:00
David Lord
6a12b191f7
start version 3.0.0 2023-08-16 14:41:57 -07:00
David Lord
9e9acfb3fe
Merge branch '2.3.x' 2023-08-16 14:30:03 -07:00
David Lord
0273664009
Update dispatch by path example (#5217) 2023-08-16 14:29:39 -07:00
David Lord
a887e179b8
clean up 2023-08-16 14:25:53 -07:00
pavithra
aa6d4c3e92
update dispatch-by-path example 2023-08-16 14:25:36 -07:00
David Lord
6d49a1e4b7
Merge branch '2.3.x' 2023-08-16 13:38:05 -07:00
David Lord
826514b8eb
fix flake8 bugbear findings 2023-08-16 13:37:56 -07:00
David Lord
c49ce2e1eb
fix flake8 bugbear findings 2023-08-16 13:37:26 -07:00
David Lord
3237fff4b8
Merge branch '2.3.x' 2023-08-16 13:35:46 -07:00
David Lord
6d266f6363
Pass maxsplit via kwarg to re.split (#5215) 2023-08-16 13:35:13 -07:00
hauntsaninja
17e146ad94
Pass maxsplit via kwarg to re.split 2023-08-16 13:33:13 -07:00
David Lord
80ae10f402
update dev requirements 2023-08-16 13:30:18 -07:00
David Lord
7d399e80c3
Merge branch '2.3.x' 2023-08-16 13:29:25 -07:00
David Lord
b1385919be
Bump pypa/gh-action-pypi-publish from 1.8.7 to 1.8.8 (#5213) 2023-08-01 09:59:06 -07:00
David Lord
6a5277d341
Bump actions/setup-python from 4.6.1 to 4.7.0 (#5212) 2023-08-01 09:58:55 -07:00
dependabot[bot]
dcc86ebfce
Bump pypa/gh-action-pypi-publish from 1.8.7 to 1.8.8
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.7 to 1.8.8.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](f5622bde02...f8c70e705f)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 16:56:22 +00:00
dependabot[bot]
180ff8853c
Bump actions/setup-python from 4.6.1 to 4.7.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.6.1 to 4.7.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](bd6b4b6205...61a6322f88)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-01 16:56:18 +00:00
David Lord
8a72b74161
[pre-commit.ci] pre-commit autoupdate (#5211) 2023-08-01 09:17:47 -07:00
pre-commit-ci[bot]
7255be9626
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.8.0 → v3.10.1](https://github.com/asottile/pyupgrade/compare/v3.8.0...v3.10.1)
- [github.com/psf/black: 23.3.0 → 23.7.0](https://github.com/psf/black/compare/23.3.0...23.7.0)
- [github.com/PyCQA/flake8: 6.0.0 → 6.1.0](https://github.com/PyCQA/flake8/compare/6.0.0...6.1.0)
2023-08-01 08:45:55 +00:00
David Lord
f215de030e
[pre-commit.ci] pre-commit autoupdate (#5187) 2023-07-04 06:18:22 -07:00
pre-commit-ci[bot]
65bc763634
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.7.0 → v3.8.0](https://github.com/asottile/pyupgrade/compare/v3.7.0...v3.8.0)
2023-07-04 06:36:29 +00:00
David Lord
a0db890853
Update install.rst with required description (#5182) 2023-07-03 05:58:14 -07:00
Pamela Fox
11da927fd9
Update install.rst with required description 2023-07-03 05:51:06 -07:00
David Lord
cb825687a5
Bump actions/checkout from 3.5.2 to 3.5.3 (#5186) 2023-07-01 09:24:20 -07:00
David Lord
51bf0fdd90
Bump slsa-framework/slsa-github-generator from 1.6.0 to 1.7.0 (#5185) 2023-07-01 09:24:11 -07:00
David Lord
0da5788efb
Bump dessant/lock-threads from 4.0.0 to 4.0.1 (#5184) 2023-07-01 09:23:57 -07:00
David Lord
326484a8d1
Bump pypa/gh-action-pypi-publish from 1.8.6 to 1.8.7 (#5183) 2023-07-01 09:23:35 -07:00
dependabot[bot]
1ce4d95de9
Bump actions/checkout from 3.5.2 to 3.5.3
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](8e5e7e5ab8...c85c95e3d7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 16:16:28 +00:00
dependabot[bot]
1fb188636e
Bump slsa-framework/slsa-github-generator from 1.6.0 to 1.7.0
Bumps [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slsa-framework/slsa-github-generator/compare/v1.6.0...v1.7.0)

---
updated-dependencies:
- dependency-name: slsa-framework/slsa-github-generator
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 16:16:25 +00:00
dependabot[bot]
f62580b947
Bump dessant/lock-threads from 4.0.0 to 4.0.1
Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md)
- [Commits](c1b35aecc5...be8aa5be94)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 16:16:22 +00:00
dependabot[bot]
47a89da558
Bump pypa/gh-action-pypi-publish from 1.8.6 to 1.8.7
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.6 to 1.8.7.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](a56da0b891...f5622bde02)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-01 16:16:19 +00:00
David Lord
09789f2a34
fix typo in errorhandling doc (#5180) 2023-06-29 17:28:25 -07:00
ToolMoney
aea13d5a10 fix typo in errorhandling doc 2023-06-29 17:20:35 -07:00
David Lord
15a0d4afd4
Merge branch '2.3.x' 2023-06-27 14:18:56 -07:00
David Lord
f39c71609e
remove manifest.in 2023-06-27 14:18:18 -07:00
David Lord
3c85ec953f
use flit_core as build backend (#5177) 2023-06-27 14:17:46 -07:00
David Lord
6b9acd565c
switch docs to flit 2023-06-27 14:13:56 -07:00
David Lord
46b328854a
switch examples to flit 2023-06-27 14:13:56 -07:00
David Lord
f38f3a745a
switch to flit build backend 2023-06-27 14:13:56 -07:00
David Lord
b1bdd97564
Merge branch '2.3.x' 2023-06-27 08:30:43 -07:00
David Lord
d67c47b81f
simplify tox config
envs inherit base testenv
2023-06-27 08:29:41 -07:00
David Lord
7bfbcfab87
Merge branch '2.3.x' 2023-06-27 07:42:06 -07:00
David Lord
8933d75443
update pypy test version 2023-06-27 07:41:15 -07:00
David Lord
cc55d7b3cf
Merge branch '2.3.x' 2023-06-27 07:11:37 -07:00
David Lord
aca7d5637d
update dependencies 2023-06-27 07:11:22 -07:00
David Lord
ec2b2394dc
update import of declarative_base from SQLAlchemy (#5171) 2023-06-21 09:32:37 -07:00
mohammad m. moniri
a7ae372f2f
update import of declarative_base from SQLAlchemy 2023-06-21 09:30:03 -07:00
David Lord
4bcd4be6b7
Merge branch '2.3.x' 2023-06-09 09:41:25 -07:00
David Lord
8e33b7b3e2
update werkzeug requirement 2023-06-09 09:41:17 -07:00
David Lord
4be9f52142
fix use of importlib.util.find_spec (#5161) 2023-06-09 09:38:59 -07:00
David Lord
bda295d37f
fix use of importlib.util.find_spec 2023-06-09 09:34:42 -07:00
David Lord
4d6ae8273a
Merge branch '2.3.x' 2023-06-08 14:33:28 -07:00
David Lord
c8cf4694c6
unpin sphinx and sphinx-tabs 2023-06-08 14:33:16 -07:00
David Lord
935ee742b4
Merge branch '2.3.x' 2023-06-07 13:22:15 -07:00
David Lord
9930b0fe8e
Python 3.12 compatibility (#5157) 2023-06-07 13:21:49 -07:00
David Lord
ed8ddb6a3a
update werkzeug to 2.3.5 2023-06-07 13:18:49 -07:00
David Lord
84e11a1e82
use importlib instead of pkgutil 2023-06-07 13:13:41 -07:00
David Lord
367e1df785
start version 2.3.3 2023-06-07 13:10:39 -07:00
David Lord
2be71d323d
[pre-commit.ci] pre-commit autoupdate (#5154) 2023-06-07 12:53:30 -07:00
David Lord
d614d6bf8c
ignore pytest ast warnings 2023-06-06 09:30:34 -07:00
pre-commit-ci[bot]
32d2f47ed1
[pre-commit.ci] pre-commit autoupdate
updates:
- https://github.com/asottile/reorder_python_importshttps://github.com/asottile/reorder-python-imports
2023-06-06 09:26:43 -07:00
David Lord
c9b6110dec
Merge branch '2.3.x' 2023-06-06 09:26:05 -07:00
David Lord
7dbb2f7e05
retarget pre-commit.ci 2023-06-06 09:25:47 -07:00
David Lord
a3e4013f89
Bump actions/setup-python from 4.6.0 to 4.6.1 (#5150) 2023-06-01 11:49:16 -07:00
David Lord
fb20cbbf1e
Bump pypa/gh-action-pypi-publish from 1.8.5 to 1.8.6 (#5149) 2023-06-01 11:47:53 -07:00
David Lord
c49757a459
Bump slsa-framework/slsa-github-generator from 1.5.0 to 1.6.0 (#5148) 2023-06-01 11:46:49 -07:00
dependabot[bot]
18e703bc93
Bump actions/setup-python from 4.6.0 to 4.6.1
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.6.0 to 4.6.1.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](57ded4d7d5...bd6b4b6205)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-01 16:56:50 +00:00
dependabot[bot]
fc74a114b3
Bump pypa/gh-action-pypi-publish from 1.8.5 to 1.8.6
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.5 to 1.8.6.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](0bf742be3e...a56da0b891)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-01 16:56:46 +00:00
dependabot[bot]
40f31c3078
Bump slsa-framework/slsa-github-generator from 1.5.0 to 1.6.0
Bumps [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) from 1.5.0 to 1.6.0.
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slsa-framework/slsa-github-generator/compare/v1.5.0...v1.6.0)

---
updated-dependencies:
- dependency-name: slsa-framework/slsa-github-generator
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-01 16:56:43 +00:00
David Lord
31fd9c8791
Merge branch '2.3.x' 2023-05-31 09:19:14 -07:00
David Lord
38f02e04f4
update metadata 2023-05-31 09:18:33 -07:00
David Lord
e7264776bd
update dependencies 2023-05-31 09:17:51 -07:00
David Lord
ae07dead24
Merge pull request #5140 from Jeroendevr/patch-1 2023-05-31 09:14:56 -07:00
Jeroendevr
0f477df86a
Config from Data Files to match from_file API
In the API docs using a TOML file to load config is referred to as https://flask.palletsprojects.com/en/2.3.x/api/#flask.Config.from_file

To keep docs consistent a small change to the config docs.
2023-05-24 11:13:36 +02:00
Pedro Guilherme S. Moreira
55332be325
docs: fix wrong JS syntax (#5136) 2023-05-18 14:33:44 +02:00
David Lord
b80baaf359
Merge pull request #5126 from pgjones/pathlike
Allow for PathLike types for config file variables
2023-05-14 09:43:35 -07:00
pgjones
2abb7513dc Allow for PathLike types for config file variables
This follows the Flask practice elsewhere and makes it clear PathLike
filenames are valid.
2023-05-14 16:09:25 +01:00
David Lord
d0bf462866
Merge branch '2.3.x' 2023-05-09 12:38:00 -07:00
David Lord
4911012cf4
update workflows
update publish parameter names
remove pip update
2023-05-09 12:37:33 -07:00
David Lord
57e926c791
Merge branch '2.3.x' 2023-05-02 10:42:04 -07:00
David Lord
859d63902e
Merge pull request #5111 from pallets/update-tests
update tests
2023-05-02 10:41:41 -07:00
David Lord
0a00e1b608
use tmp_path instead of tmpdir 2023-05-02 10:38:27 -07:00
David Lord
1d7281fe07
remove egg test
eggs aren't supported, and Python 3.12 removes setuptools
2023-05-02 09:53:31 -07:00
David Lord
e374853c75
Merge branch '2.3.x' 2023-05-02 07:52:49 -07:00
David Lord
97c830190f
Merge branch '2.2.x' into 2.3.x 2023-05-02 07:50:30 -07:00
David Lord
bda08b11c6
Merge pull request #5110 from pallets/release-2.2.5
release version 2.2.5
2023-05-02 07:43:48 -07:00
David Lord
47af817c8f
release version 2.2.5 2023-05-02 07:35:27 -07:00
David Lord
afd63b1617
Merge pull request #5109 from pallets/backport-vary-cookie
backport 2.2.x: set `Vary: Cookie` header consistently for session
2023-05-02 07:18:08 -07:00
David Lord
ca12e8ebb7
update dependencies 2023-05-02 07:17:52 -07:00
David Lord
8646edca6f
set Vary: Cookie header consistently for session 2023-05-02 07:14:15 -07:00
David Lord
a6367dac74
Merge pull request #5108 from pallets/werkzeug-compat
werkzeug 2.3.3 compatibility
2023-05-02 07:12:59 -07:00
David Lord
3fbfbad79f
werkzeug 2.3.3 compatibility 2023-05-02 07:09:36 -07:00
David Lord
726d3f4fa9
start version 2.2.5 2023-05-02 06:56:08 -07:00
David Lord
7b31099252
Merge pull request #5106 from pallets/dependabot/github_actions/pypa/gh-action-pypi-publish-1.8.5
Bump pypa/gh-action-pypi-publish from 1.8.4 to 1.8.5
2023-05-01 10:22:01 -07:00
David Lord
723091b903
Merge pull request #5104 from pallets/dependabot/github_actions/actions/checkout-3.5.2
Bump actions/checkout from 3.5.0 to 3.5.2
2023-05-01 10:21:02 -07:00
dependabot[bot]
dcd25d8f07
Bump actions/checkout from 3.5.0 to 3.5.2
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.0 to 3.5.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](8f4b7f8486...8e5e7e5ab8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 17:18:16 +00:00
David Lord
1e160c199b
Merge pull request #5105 from pallets/dependabot/github_actions/actions/setup-python-4.6.0
Bump actions/setup-python from 4.5.0 to 4.6.0
2023-05-01 10:17:25 -07:00
dependabot[bot]
ec8ca69195
Bump pypa/gh-action-pypi-publish from 1.8.4 to 1.8.5
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.8.4 to 1.8.5.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](29930c9cf5...0bf742be3e)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 16:57:14 +00:00
dependabot[bot]
b7b753b96c
Bump actions/setup-python from 4.5.0 to 4.6.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.5.0 to 4.6.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](d27e3f3d7c...57ded4d7d5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 16:57:10 +00:00
David Lord
0afeb1d11c
fix release date 2023-05-01 09:01:40 -07:00
David Lord
4cf8b78c6c
Merge pull request #5102 from pallets/release-2.3.2
release version 2.3.2
2023-05-01 08:42:27 -07:00
David Lord
f3b8f57054
release version 2.3.2 2023-05-01 08:35:10 -07:00
David Lord
c990bba94a
update min test env 2023-05-01 08:35:10 -07:00
David Lord
adedb2a64e
Merge pull request #5101 from pallets/update-werkzeug
update werkzeug to >=2.3.3
2023-05-01 08:22:58 -07:00
David Lord
e1aedecdc6
update werkzeug 2023-05-01 08:18:03 -07:00
David Lord
37badc3ce8
update changelog 2023-05-01 08:13:12 -07:00
David Lord
70f906c51c
Merge pull request from GHSA-m2qf-hxjv-5gpq
set `Vary: Cookie` header consistently for session
2023-05-01 08:11:41 -07:00
David Lord
8705dd39c4
set Vary: Cookie header consistently for session 2023-05-01 08:10:52 -07:00
David Lord
9532cba45d
fix mypy finding 2023-05-01 08:10:25 -07:00
David Lord
0bc7356ce1
start version 2.3.2 2023-05-01 08:02:46 -07:00
David Lord
f07fb2b607
Merge pull request #5086 from pallets/release-2.3.1
release version 2.3.1
2023-04-25 15:21:36 -06:00
David Lord
721abdc381
release version 2.3.1 2023-04-25 14:08:38 -06:00
David Lord
0867dce42c
Merge pull request #5085 from lucaswerkmeister/patch-1
Fix importing Markup from flask
2023-04-25 14:06:22 -06:00
Lucas Werkmeister
0ec9192cf2
fix importing Markup from flask 2023-04-25 13:50:43 -06:00
David Lord
345f18442c
start version 2.3.1 2023-04-25 13:48:16 -06:00
David Lord
5f4072423e
Merge pull request #5083 from pallets/release-2.3.0
release version 2.3.0
2023-04-25 12:42:22 -06:00
David Lord
8728c3e4cd
release version 2.3.0 2023-04-25 12:35:06 -06:00
David Lord
eb33b8c809
Merge pull request #5082 from pallets/minimum-requirements
update minimum requirements
2023-04-25 12:33:30 -06:00
David Lord
79ebf6c39c
update minimum requirements 2023-04-25 12:28:59 -06:00
David Lord
73739a29f4
Merge branch '2.2.x' 2023-04-25 11:55:41 -06:00
David Lord
ddc7accaa2
Merge pull request #5081 from pallets/release-2.2.4
release version 2.2.4
2023-04-25 11:53:09 -06:00
David Lord
cd1b68cf6e
Merge branch '2.2.x' 2023-04-25 11:41:20 -06:00
David Lord
74e0329820
release version 2.2.4 2023-04-25 11:41:10 -06:00
David Lord
2d460685b1
update dev env 2023-04-25 11:41:10 -06:00
David Lord
64bc45874d
update dev dependencies 2023-04-25 11:40:57 -06:00
David Lord
427e5dc4f3
update dev env 2023-04-25 11:00:01 -06:00
David Lord
0c5f18ab91
Merge pull request #5077 from EtiennePelletier/master
Remove double period in signals documentation page
2023-04-24 12:21:42 -06:00
EtiennePelletier
d48deba273 Remove double period in signals documentation page 2023-04-24 11:06:27 -06:00
David Lord
2b2a764143
Merge pull request #5073 from pallets/new-logo
use new logo
2023-04-20 11:49:26 -07:00
David Lord
83d777bebf
use new logo 2023-04-20 11:38:04 -07:00
David Lord
b4345cb4eb
Merge pull request #5072 from pallets/drop-py37
drop support for Python 3.7
2023-04-20 11:11:52 -07:00
David Lord
2e8fe7b2f2
drop support for python 3.7 2023-04-20 11:09:55 -07:00
David Lord
9659b11a45
remove pypy 3.8 and 3.7 from tests 2023-04-20 10:15:58 -07:00
David Lord
f139024b1c
remove old links 2023-04-20 09:53:38 -07:00
David Lord
a4ea5df5d5
Merge pull request #5071 from pallets/future-annotations
use postponed evaluation of annotations
2023-04-20 09:36:51 -07:00
David Lord
44ffe6c6d6
add __future__ annotations 2023-04-20 09:24:44 -07:00
David Lord
cfa863c357
Merge branch '2.2.x' 2023-04-15 12:30:20 -07:00
David Lord
db7d2d2d68
Merge pull request #5067 from pallets/tox-constraints
use tox 4.4 constraint feature
2023-04-15 12:27:24 -07:00
David Lord
a67195e059
update dependencies 2023-04-15 12:25:09 -07:00
David Lord
7e6e68aed9
enforce minimum versions in env 2023-04-15 12:20:57 -07:00
David Lord
a1d0eda789
Merge pull request #5066 from pallets/docs-passthrough
document passthrough_errors
2023-04-15 11:57:46 -07:00
David Lord
5bba529dfc
document passthrough_errors 2023-04-15 11:53:56 -07:00
David Lord
9a4d370ea2
fix typo 2023-04-15 07:39:35 -07:00
David Lord
6931b25293
Merge pull request #5063 from pallets/cli-routes-domain
show subdomain or host in routes output
2023-04-14 09:45:20 -07:00
David Lord
84c007d34f
show subdomain or host in routes output 2023-04-14 09:43:00 -07:00
emisargent
182ce3dd15
Add a devcontainer configuration (#4969) 2023-04-13 10:03:49 -07:00
David Lord
49498a323b
Merge pull request #5059 from pallets/oidc-publish
use OIDC instead of token for publishing
2023-04-13 08:24:58 -07:00
David Lord
f7d9956c0f
use oidc instead of token 2023-04-13 08:18:14 -07:00
David Lord
59f81950fe
Merge pull request #5049 from pgjones/signals
support async signal subscribers
2023-04-13 08:08:27 -07:00
pgjones
8239765a44
allow async signal receivers 2023-04-13 08:05:42 -07:00
David Lord
a05c0c6b72
Merge pull request #5058 from pallets/require-blinker
blinker is required, signals are always available
2023-04-13 07:51:11 -07:00
David Lord
9cb1a7a52d
blinker is required, signals are always available 2023-04-13 07:39:24 -07:00
David Lord
e1e4e82096
Merge pull request #5034 from adamtheturtle/default-mimetype-optional
Allow Response subclasses to set default_mimetype as None
2023-04-12 13:43:23 -07:00
Adam Dangoor
b626a93879
Allow Response subclasses to set default_mimetype as None
This matches the type - see 92c6380248/src/werkzeug/sansio/response.py (L94).
2023-04-12 13:30:28 -07:00
David Lord
87698a2d5d
Merge pull request #5029 from lettow-humain/main
Appending missing parentheses
2023-04-12 13:29:05 -07:00
lettow-humain
c67bfe551d
fix parentheses 2023-04-12 13:19:54 -07:00
David Lord
c9a5660cfd
Merge pull request #5054 from pallets/session-domain
no cookie domain by default
2023-04-12 13:10:34 -07:00
David Lord
c24f8c8199
no cookie domain by default 2023-04-12 12:38:22 -07:00
David Lord
fa0ceb62f2
Merge branch '2.2.x' 2023-04-12 10:57:53 -07:00
David Lord
694183ce22
Merge pull request #5053 from pallets/werkzeug-compat
update test cookie handling for Werkzeug 2.3
2023-04-12 10:57:14 -07:00
David Lord
04c21387db
update test cookie handling for Werkzeug 2.3 2023-04-12 10:55:00 -07:00
David Lord
67c4c7bac2
ignore warning from pytest due to change in Python 3.12 alpha 2023-04-11 15:34:39 -07:00
David Lord
e39d78a0ad
Merge branch '2.2.x' 2023-04-11 15:33:44 -07:00
David Lord
a30b6e723c
update dependencies 2023-04-11 15:33:34 -07:00
David Lord
daf6966c89
Merge pull request #5037 from pamelafox/patch-1
Fix typo in appfactories.rst code block
2023-04-05 14:56:26 -07:00
David Lord
c4f754cda3
Merge pull request #5041 from pallets/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2023-04-04 07:00:49 -07:00
pre-commit-ci[bot]
d2a6f5c572
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0)
2023-04-04 06:31:29 +00:00
David Lord
a361ef6368
Merge pull request #5038 from pallets/dependabot/github_actions/pypa/gh-action-pypi-publish-1.8.4
Bump pypa/gh-action-pypi-publish from 1.6.4 to 1.8.4
2023-04-03 06:19:09 -07:00
David Lord
c2688e4f06
Merge pull request #5040 from pallets/dependabot/github_actions/actions/cache-3.3.1
Bump actions/cache from 3.2.6 to 3.3.1
2023-04-03 06:18:57 -07:00
David Lord
e8178f7bfa
Merge pull request #5039 from pallets/dependabot/github_actions/actions/checkout-3.5.0
Bump actions/checkout from 3.3.0 to 3.5.0
2023-04-03 06:18:45 -07:00
dependabot[bot]
4909e8ff86
Bump actions/cache from 3.2.6 to 3.3.1
Bumps [actions/cache](https://github.com/actions/cache) from 3.2.6 to 3.3.1.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](69d9d449ac...88522ab9f3)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-01 16:57:11 +00:00
dependabot[bot]
6a6c83789f
Bump actions/checkout from 3.3.0 to 3.5.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.3.0 to 3.5.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](ac59398561...8f4b7f8486)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-01 16:57:06 +00:00
dependabot[bot]
29676a273a
Bump pypa/gh-action-pypi-publish from 1.6.4 to 1.8.4
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.6.4 to 1.8.4.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](c7f29f7ade...29930c9cf5)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-01 16:57:01 +00:00
Pamela Fox
15f2ca2c24
Update appfactories.rst
Remove unneeded backticks
2023-03-31 12:20:27 -07:00
David Lord
7ed89d3f9d
Merge pull request #5014 from evgenymozhaev/require-a-non-empty-name-for-blueprints
Require a non empty name for blueprints
2023-03-11 08:34:56 -08:00
Evgeny Mozhaev
b8b410014d
require a non-empty name for blueprints 2023-03-11 08:26:36 -08:00
David Lord
7ee9ceb71e
Merge branch '2.2.x' 2023-03-11 08:23:08 -08:00
David Lord
cac56a2b53
Merge pull request #5026 from pallets/werkzeug-compat
replace `werkzeug.urls` with `urllib.parse`
2023-03-11 08:21:58 -08:00
David Lord
c4b39ba2f3
replace werkzeug.urls with urllib.parse 2023-03-11 08:19:22 -08:00
David Lord
e7f8ae0166
Merge pull request #5025 from pallets/update-requirements
update requirements
2023-03-11 07:41:19 -08:00
David Lord
1432cddb13
update requirements 2023-03-11 07:38:14 -08:00
David Lord
c83f661427
Merge pull request #5024 from pallets/docs-sentry
remove broken link
2023-03-11 07:32:12 -08:00
David Lord
31022056ae
remove broken link 2023-03-11 07:30:21 -08:00
David Lord
a5f30b157d
Merge pull request #5020 from gultas/patch-1
Update installation.rst
2023-03-08 11:04:53 -08:00
martinamca
0bc6be604d
Update installation.rst
The link to Blinker does not work.
2023-03-08 21:28:33 +03:00
David Lord
2f67e0fe4a
Merge pull request #5005 from pallets/dependabot/github_actions/slsa-framework/slsa-github-generator-1.5.0
Bump slsa-framework/slsa-github-generator from 1.4.0 to 1.5.0
2023-03-01 09:04:40 -08:00
David Lord
bc3ec352f0
Merge pull request #5006 from pallets/dependabot/github_actions/actions/cache-3.2.6
Bump actions/cache from 3.2.4 to 3.2.6
2023-03-01 09:02:06 -08:00
dependabot[bot]
b8eb83940c
Bump actions/cache from 3.2.4 to 3.2.6
Bumps [actions/cache](https://github.com/actions/cache) from 3.2.4 to 3.2.6.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](627f0f41f6...69d9d449ac)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-01 16:57:34 +00:00
dependabot[bot]
3cdcc729a7
Bump slsa-framework/slsa-github-generator from 1.4.0 to 1.5.0
Bumps [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slsa-framework/slsa-github-generator/compare/v1.4.0...v1.5.0)

---
updated-dependencies:
- dependency-name: slsa-framework/slsa-github-generator
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-01 16:57:31 +00:00
David Lord
5cdfeae2e8
Merge branch '2.2.x' 2023-02-23 15:58:29 -08:00
David Lord
736b5f9ff8
update dependencies 2023-02-23 15:58:21 -08:00
David Lord
2ad4d8d717
Merge pull request #4992 from AntoineMath/file_mode 2023-02-23 11:13:18 -08:00
AntoineMath
b10b6d4af1
add text parameter to config.from_file 2023-02-23 11:10:21 -08:00
David Lord
4c288bc97e
Merge pull request #4998 from pallets/deprecate-locked_cached_property
deprecate `locked_cached_property`
2023-02-23 10:59:28 -08:00
David Lord
4256fc6304
deprecate locked_cached_property 2023-02-23 10:05:57 -08:00
David Lord
c690f529f2
Merge pull request #4997 from pallets/deprecate-got_first_request
deprecate `got_first_request`
2023-02-23 09:34:17 -08:00
David Lord
fc03d0dfab
setup method on registered blueprint is error 2023-02-23 09:29:36 -08:00
David Lord
2a33c17854
deprecate got_first_request property 2023-02-23 09:28:42 -08:00
David Lord
704b68948f
Merge pull request #4996 from pallets/deprecate-markupsafe-export
deprecate markupsafe exports
2023-02-23 08:59:37 -08:00
David Lord
9c02f07f9b
deprecate markupsafe exports 2023-02-23 08:55:01 -08:00
David Lord
1ee22e1736
Merge pull request #4995 from pallets/remove-deprecated
remove previously deprecated code
2023-02-23 08:45:38 -08:00
David Lord
6650764e97
remove previously deprecated code 2023-02-23 08:35:16 -08:00
David Lord
604de4b1dc
Merge branch '2.2.x' 2023-02-16 06:27:41 -08:00
David Lord
c4c7f504be
update dependencies 2023-02-16 06:27:25 -08:00
David Lord
ed5b240417
Merge branch '2.2.x' 2023-02-15 14:48:09 -08:00
David Lord
6a392afbb6
Merge pull request #4980 from pallets/release-2.2.3
release version 2.2.3
2023-02-15 14:44:24 -08:00
David Lord
41d4f62909
release version 2.2.3 2023-02-15 14:33:32 -08:00
David Lord
24df8fc89d
show 'run --debug' in docs
Reverts commit 4d69165ab6. Now that a
release has this option, it's ok to show it in the docs. It had been
reverted because the 2.2.x docs showed it before 2.2.3 was released.
2023-02-15 14:33:32 -08:00
David Lord
aa040c085c
run latest black format 2023-02-10 15:07:24 -08:00
David Lord
a18ae3d752
Merge branch '2.2.x' 2023-02-10 15:06:38 -08:00
David Lord
b945f988f9
Merge pull request #4973 from pallets/docs-lifetime
document the lifecycle of a flask application and request
2023-02-10 14:54:49 -08:00
David Lord
a6cd8f212e
document the lifecycle of a flask application and request 2023-02-10 14:48:02 -08:00
David Lord
f425c117e2
Merge pull request #4972 from pallets/docs-push-reqctx
fix test client arg for query string example
2023-02-10 10:53:02 -08:00
David Lord
ba2b3094d1
fix test client arg for query string example 2023-02-10 10:50:48 -08:00
David Lord
129568f7f4
Merge pull request #4971 from pallets/docs-blueprint-app-methods
point to app-scoped blueprint methods
2023-02-10 10:42:47 -08:00
David Lord
ab93222bd6
point to app-scoped blueprint methods 2023-02-10 10:38:44 -08:00
David Lord
d5527264f0
Merge pull request #4968 from pallets/docs-celery
rewrite celery docs, add example application
2023-02-10 09:35:31 -08:00
David Lord
3f195248dc
add celery example 2023-02-10 09:16:53 -08:00
David Lord
dca8cf013b
rewrite celery background tasks docs 2023-02-09 10:50:42 -08:00
David Lord
761e02ef67
Merge pull request #4966 from ivanovmg/fix/cmd-format
Fix command-line formatting
2023-02-08 18:44:10 -08:00
Maxim G. Ivanov
428d9430bc Fix command-line formatting 2023-02-09 09:38:57 +07:00
David Lord
4ddb3f73ba
Merge branch '2.2.x' 2023-02-07 07:18:54 -08:00
David Lord
dd2423ebde
Merge pull request #4963 from pallets/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2023-02-07 07:11:50 -08:00
pre-commit-ci[bot]
a15da89dbb [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-02-07 04:43:02 +00:00
pre-commit-ci[bot]
c1d01f6999
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.12.0 → 23.1.0](https://github.com/psf/black/compare/22.12.0...23.1.0)
2023-02-07 04:42:52 +00:00
David Lord
3502cc951b
Merge pull request #4952 from muffinmad/patch-1
Fix function argument name
2023-02-02 09:01:21 -08:00
David Lord
f45bc5995c
Merge pull request #4960 from owgreen/fix_appfactories_doc
Fix appfactories doc
2023-02-02 09:01:03 -08:00
owgreen
9abe28130d
fix doc 2023-02-02 08:57:38 -08:00
David Lord
88069bd417
Merge pull request #4959 from pallets/dependabot/github_actions/actions/cache-3.2.4
Bump actions/cache from 3.2.3 to 3.2.4
2023-02-01 08:55:09 -08:00
David Lord
f822891065
Merge pull request #4958 from pallets/dependabot/github_actions/actions/setup-python-4.5.0
Bump actions/setup-python from 4.4.0 to 4.5.0
2023-02-01 08:54:52 -08:00
dependabot[bot]
74c256872b
Bump actions/cache from 3.2.3 to 3.2.4
Bumps [actions/cache](https://github.com/actions/cache) from 3.2.3 to 3.2.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](58c146cc91...627f0f41f6)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 16:01:30 +00:00
dependabot[bot]
94a23a3e24
Bump actions/setup-python from 4.4.0 to 4.5.0
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4.4.0 to 4.5.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](5ccb29d877...d27e3f3d7c)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 16:01:23 +00:00
Andrii Kolomoiets
d93760d8bd
Fix function argument name 2023-01-23 17:01:49 +02:00
David Lord
ef85270d9a
Merge branch '2.2.x' 2023-01-20 13:50:23 -08:00
David Lord
39fc0c6bad
Merge pull request #4949 from pallets/publish-workflow
Publish workflow
2023-01-20 13:49:30 -08:00
David Lord
0b4b61146f
build, provenance, publish workflow 2023-01-20 13:45:15 -08:00
David Lord
99b34f7148
move and update flake8 config 2023-01-20 13:42:50 -08:00
David Lord
3a35977d5f
stop ignoring flake8 e402 2023-01-19 06:35:15 -08:00
David Lord
78b42b9ac2
Merge pull request #4947 from pallets/pyproject
switch to pyproject.toml
2023-01-18 10:38:38 -08:00
David Lord
261e4a6cf2
fix flake8 bugbear errors 2023-01-18 10:32:51 -08:00
David Lord
8f13f5b6d6
update docs and examples for pyproject
setup.py -> pyproject.toml
venv -> .venv
2023-01-18 10:32:51 -08:00
David Lord
6d6d986fc5
switch to pyproject.toml 2023-01-18 10:32:51 -08:00
David Lord
9da947a279
set workflow permissions 2023-01-09 12:45:16 -08:00
David Lord
3812a52e96
Merge branch '2.2.x' 2023-01-09 12:39:48 -08:00
David Lord
8bfc0581e7
Merge pull request #4942 from bhushan-mohanraj/patch-2
Clarify the docstring for `View.as_view`.
2023-01-09 11:11:02 -08:00
Bhushan Mohanraj
a748770199
clarify View.as_view docstring 2023-01-09 11:07:49 -08:00
David Lord
4a0f658897
Merge pull request #4943 from pallets/update-python
update tested python versions
2023-01-09 10:42:14 -08:00
David Lord
2a9d16d011
update tested python versions
test 3.11 final
test 3.12 dev
update for tox 4
2023-01-09 10:37:59 -08:00
David Lord
836866dc19
Merge pull request #4935 from pgjones/subdomain
Fix subdomain inheritance for nested blueprints
2023-01-04 14:06:35 -07:00
pgjones
cabda59353 Ensure that blueprint subdomains suffix-chain
This ensures that a child's subdomain prefixs any parent subdomain
such that the full domain is child.parent.domain.tld and onwards with
further nesting. This makes the most sense to users and mimics how
url_prefixes work (although subdomains suffix).
2023-01-04 18:06:04 +00:00
Josh Michael Karamuth
d7b6c1f670 Fix subdomain inheritance for nested blueprints.
Fixes #4834
2023-01-04 16:19:52 +00:00
David Lord
fa1ee70668
Merge pull request #4933 from pallets/dependabot/github_actions/dessant/lock-threads-4
Bump dessant/lock-threads from 3 to 4
2023-01-03 08:24:17 -07:00
dependabot[bot]
bb1f83c265
Bump dessant/lock-threads from 3 to 4
Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 3 to 4.
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/master/CHANGELOG.md)
- [Commits](https://github.com/dessant/lock-threads/compare/v3...v4)

---
updated-dependencies:
- dependency-name: dessant/lock-threads
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-01 16:01:00 +00:00
David Lord
74e5263c88
new run debug docs 2022-12-29 09:52:18 -08:00
David Lord
eeebb5adc7
Merge branch '2.2.x' 2022-12-29 09:51:58 -08:00
David Lord
4d69165ab6
revert run debug docs 2022-12-29 09:51:34 -08:00
David Lord
910179f9b0
Merge branch '2.2.x' 2022-12-24 15:31:07 -07:00
David Lord
229dcbb5ce
Merge pull request #4779 from greyli/add-debug-to-run
Add `--debug` option to flask run
2022-12-24 15:28:21 -07:00
Grey Li
bd26928fdb
Prefer flask run --debug in docs 2022-12-24 15:24:49 -07:00
Grey Li
4bc0e4943d
Add --debug option to flask run 2022-12-24 15:04:48 -07:00
Jonah Lawrence
79032ca5f1
Add .svg to select_jinja_autoescape (#4840)
As SVG files are a type of XML file and are similar in nearly
all aspects to XML, .svg should also be autoescaped.
2022-12-24 11:27:20 -07:00
David Lord
7464e17c5e
Merge branch '2.2.x' 2022-12-24 11:21:59 -07:00
David Lord
631b6dd546
Merge pull request #4921 from ivanovmg/fix/template_folder
Allow pathlib.Path for template_folder
2022-12-24 11:20:56 -07:00
Maxim G. Ivanov
09112cfc47
template_folder type allows pathlib 2022-12-24 11:17:52 -07:00
David Lord
d9e56c7f4b
Merge pull request #4920 from ivanovmg/fix/link
Fix URL "committing as you go"
2022-12-24 11:07:46 -07:00
Maxim G. Ivanov
677a046848
Fix URL "committing as you go" 2022-12-24 11:03:47 -07:00
David Lord
d8fe178aa6
Merge pull request #4920 from ivanovmg/fix/link
Fix URL "committing as you go"
2022-12-24 10:57:53 -07:00
Maxim G. Ivanov
6fcf6d00bd
Fix URL "committing as you go" 2022-12-24 10:56:00 -07:00
David Lord
55cdb420a0
Merge pull request #4926 from pallets/docs-inheritance
python 2 style inheritance clean up from docs
2022-12-24 10:36:40 -07:00
Asif Saif Uddin
1a68768e6b
python 2 style inheritance clean up from docs 2022-12-24 10:31:23 -07:00
David Lord
1373f70dc6
Merge pull request #4922 from pallets/update-requirements
update requirements
2022-12-24 10:25:43 -07:00
David Lord
8e3128b989
ignore flake8 b905 zip(strict=True) until python 3.10 2022-12-24 10:22:37 -07:00
David Lord
43bc7330ce
update requirements 2022-12-24 10:22:37 -07:00
Grey Li
d36a379a0f
Merge pull request #4913 from ivanovmg/fix/var-name 2022-12-22 21:48:45 +08:00
Maxim G. Ivanov
43ef559de3 Fix varname in docs 2022-12-22 21:28:18 +08:00
David Lord
dcdcac2f3a
Merge pull request #4907 from rayanth/patch-1
Update api.rst
2022-12-13 16:36:49 -08:00
rayanth
95b666871c
Update api.rst
Corrected typo in "tojson" example, `const names = {{ names|tojson }};` was `const names = {{ names|tosjon }};`
2022-12-13 13:27:38 -08:00
Grey Li
3d4acf0ca0
Merge pull request #4899 from pallets/pre-commit-ci-update-config 2022-12-10 13:42:03 +08:00
pre-commit-ci[bot]
3e932aa103
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.2.2 → v3.3.0](https://github.com/asottile/pyupgrade/compare/v3.2.2...v3.3.0)
2022-12-06 00:34:53 +00:00
David Lord
b5ec83b697
Merge pull request #4882 from Abdur-rahmaanJ/patch-4
Fix backtick not rendering.
2022-11-27 06:51:08 -08:00
David Lord
29697fffb4
Merge pull request #4883 from Dosenpfand/doc-extension-dev-2.2.x
Documentation: Fix class-based views example for Extension Development
2022-11-27 06:50:46 -08:00
Dosenpfand
9a294a6401 Fix class-based views example 2022-11-27 13:10:14 +01:00
Abdur-Rahmaan Janhangeer
d951a763fb
Fix backstick not rendering. 2022-11-27 13:51:09 +04:00
David Lord
066a35dd32
Merge branch '2.2.x' 2022-11-25 07:51:37 -08:00
David Lord
618fdc8600
Merge pull request #4879 from pallets/requirements
update requirements
2022-11-25 07:43:46 -08:00
David Lord
d178653b5f
update requirements 2022-11-25 07:39:54 -08:00
pre-commit-ci[bot]
9f99425aaf
[pre-commit.ci] pre-commit autoupdate (#4862)
updates:
- [github.com/peterdemin/pip-compile-multi: v2.4.6 → v2.5.0](https://github.com/peterdemin/pip-compile-multi/compare/v2.4.6...v2.5.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2022-11-07 20:38:32 -08:00
Grey Li
35c6595202
Merge pull request #4858 from pallets/pre-commit-ci-update-config 2022-11-01 09:41:21 +08:00
pre-commit-ci[bot]
9daddd1271
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.38.2 → v3.2.0](https://github.com/asottile/pyupgrade/compare/v2.38.2...v3.2.0)
- [github.com/asottile/reorder_python_imports: v3.8.3 → v3.9.0](https://github.com/asottile/reorder_python_imports/compare/v3.8.3...v3.9.0)
- [github.com/psf/black: 22.8.0 → 22.10.0](https://github.com/psf/black/compare/22.8.0...22.10.0)
2022-11-01 00:06:23 +00:00
Grey Li
2a54cfa5ce
Merge pull request #4847 from mhsmathew/patch-1 2022-10-30 23:00:37 +08:00
Jonah Lawrence
cc66213e57
Add .svg to select_jinja_autoescape (#4840)
As SVG files are a type of XML file and are similar in nearly 
all aspects to XML, .svg should also be autoescaped.
2022-10-30 14:55:51 +00:00
Mat Steininger
5dfd2126a6 Fixed inconsistent double spacing in docs/api.rst 2022-10-30 22:45:33 +08:00
David Lord
e7c82f9c47
Merge pull request #4833 from pallets/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-10-19 07:16:04 -07:00
David Lord
3dc6db9d0c
Merge pull request #4835 from TehBrian/2.2.x
fix typo in quickstart
2022-10-04 20:09:06 -07:00
TehBrian
75e92090ee
fix typo in quickstart 2022-10-04 21:12:13 -04:00
pre-commit-ci[bot]
c7da6d74a8
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.37.3 → v2.38.2](https://github.com/asottile/pyupgrade/compare/v2.37.3...v2.38.2)
- [github.com/asottile/reorder_python_imports: v3.8.2 → v3.8.3](https://github.com/asottile/reorder_python_imports/compare/v3.8.2...v3.8.3)
2022-10-03 23:30:28 +00:00
Yang Yang
0d8c8ba71b
Fix docstring of test_request_context (#4821)
Add missing `app.`.
2022-09-18 04:53:47 -07:00
Maksim Salau
9c3deeee96
Fix argument in register_api() in docs/view.rst (#4818) 2022-09-14 06:08:38 -07:00
waffle-stomper
2c78771238
Fix missing assignment in MethodView example (#4815) 2022-09-14 06:07:20 -07:00
David Lord
c34c84b690
Merge branch '2.2.x' 2022-09-11 06:33:56 -07:00
David Lord
7c01fbcd06
update requirements 2022-09-11 06:33:44 -07:00
pre-commit-ci[bot]
8811ae037a
[pre-commit.ci] pre-commit autoupdate (#4806)
updates:
- [github.com/psf/black: 22.6.0 → 22.8.0](https://github.com/psf/black/compare/22.6.0...22.8.0)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2022-09-07 12:07:20 -07:00
David Lord
00be8d24ac
Merge branch '2.2.x' 2022-09-02 08:53:04 -07:00
Isaac Woodruff
e7b2ce9a50
Add missing .dev to version (#4801) 2022-09-02 08:52:13 -07:00
David Lord
73b9bacbf7
Merge branch '2.2.x' 2022-08-27 06:04:55 -07:00
David Lord
ce6ad90ecf
remove heroku link 2022-08-27 06:03:46 -07:00
Kevin Kirsche
00bdc2b448
fix: remove obsolete zip_safe (#4783)
remove obsolete `zip_safe`
2022-08-22 09:05:52 -07:00
David Lord
212b72a1fe
start version 2.2.3 2022-08-22 09:00:33 -07:00
David Lord
56a95f6ff6
Merge pull request #4780 from tjrhines1/config-fix-docstring
Fix misrendered docstring
2022-08-21 07:56:09 -07:00
Thomas Rhines
746455d103 Fix misrendered docstring
The API reference for `flask.Config.from_mapping` needs a newline to separate
the summary from the return description.  I also wrapped the docstring at 72
characters as suggested in CONTRIBUTING.rst.
2022-08-21 10:24:03 -04:00
David Lord
e0c157f7ee
Merge pull request #4772 from DillonB07/patch-1
correct `waitress-serve` command
2022-08-17 09:24:58 -07:00
Dillon Barnes
86bf3f205f
Correct waitress-serve command 2022-08-17 17:00:25 +01:00
David Lord
2d3f72574d
fix typo 2022-08-15 12:37:11 -07:00
David Lord
d94634b1be
fix view docs 2022-08-15 07:34:50 -07:00
David Lord
1d07857b1d
fix typo 2022-08-15 07:29:34 -07:00
Grey Li
b0b27785ae
Merge pull request #4760 from oguzhancelikarslan/patch-1
Fix typo on qucikstart documentation
2022-08-13 10:22:10 +08:00
Oğuzhan Çelikarslan
77cdefccee Fix typo 2022-08-13 10:08:11 +08:00
Grey Li
062a096f40
Merge pull request #4758 from tautv/patch-1
Fix typo in docs/patterns/javascript.rst
2022-08-09 22:08:08 +08:00
Grey Li
5b2e9e946b
Merge pull request #4757 from prohde/fix-4756 2022-08-09 22:03:39 +08:00
tautv
22b6296830
Update javascript.rst
Spelling
2022-08-09 09:45:02 +01:00
Philipp Rohde
00b07c863e
fix typo
fixes #4756
2022-08-09 09:48:02 +02:00
David Lord
36af821edf
Merge branch '2.2.x' 2022-08-08 16:28:50 -07:00
David Lord
a1c478bc93
Merge pull request #4755 from pallets/release-2.2.2
release version 2.2.2
2022-08-08 16:24:25 -07:00
David Lord
43d2fff317
release version 2.2.2 2022-08-08 16:21:40 -07:00
David Lord
e9af7c23ae
Merge pull request #4754 from pallets/werkzeug-version
require werkzeug >= 2.2.2
2022-08-08 16:19:32 -07:00
David Lord
de16718b39
require werkzeug >= 2.2.2 2022-08-08 16:14:00 -07:00
David Lord
c779ac4f5f
Merge branch '2.2.x' 2022-08-08 10:28:08 -07:00
David Lord
6ab3cb8d0c
fix issue number 2022-08-08 10:27:57 -07:00
David Lord
87584e89fe
Merge branch '2.2.x' 2022-08-05 11:35:36 -07:00
David Lord
e3eaafb56e
Merge pull request #4749 from pallets/shell-env
remove env from shell banner
2022-08-05 11:35:15 -07:00
David Lord
e3df23374c
remove env from shell banner 2022-08-05 11:29:39 -07:00
David Lord
a0458efef6
refactor or remove old docs (#4748) 2022-08-05 11:28:22 -07:00
David Lord
795d3e25aa
Merge branch '2.2.x' 2022-08-04 07:33:17 -07:00
David Lord
45b2c99c1f
Merge pull request #4742 from pallets/env-default
fix default value of app.env
2022-08-04 07:27:50 -07:00
David Lord
a6a7a57380
fix default value of app.env 2022-08-04 07:24:20 -07:00
David Lord
4984753dbf
start version 2.2.2 2022-08-04 07:21:17 -07:00
David Lord
21aaf0ef9a
Merge branch '2.2.x' 2022-08-03 17:09:43 -07:00
David Lord
85f79e1a23
Merge pull request #4736 from pallets/release-2.2.1
release version 2.2.1
2022-08-03 16:51:22 -07:00
David Lord
52c54b2ce1
release version 2.2.1 2022-08-03 16:40:28 -07:00
David Lord
0d87b22314
update requirements 2022-08-03 16:39:35 -07:00
David Lord
723a3a6ffd
Merge pull request #4735 from pallets/json_encoder-warning
show deprecation warning when using json_encoder/decoder
2022-08-03 10:02:18 -07:00
David Lord
714ccefeca
show deprecation warning on json_encoder/decoder access 2022-08-03 09:22:03 -07:00
David Lord
9a1b25fce4
start version 2.2.1 2022-08-03 06:47:31 -07:00
David Lord
cb4ee20117
pre-commit updates latest release branch 2022-08-01 17:46:58 -07:00
David Lord
01dec18891
start version 2.3.0 2022-08-01 17:46:38 -07:00
David Lord
b17bb9ed56
Merge pull request #4710 from pallets/release-2.2.0
release version 2.2.0
2022-08-01 17:12:09 -07:00
David Lord
292c7e5c5d
release version 2.2.0 2022-08-01 17:09:49 -07:00
David Lord
f3bb9b2566
Merge branch '2.1.x' 2022-08-01 17:07:58 -07:00
David Lord
ac1bb97679
Merge pull request #4721 from pallets/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-08-01 17:07:27 -07:00
David Lord
cfd5783a98
Merge pull request #4722 from pallets/deprecate-config-attrs
deprecate config attributes
2022-08-01 17:04:12 -07:00
David Lord
bfdd37110c
deprecate config attributes 2022-08-01 16:58:55 -07:00
pre-commit-ci[bot]
6f9ef11286
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.37.1 → v2.37.3](https://github.com/asottile/pyupgrade/compare/v2.37.1...v2.37.3)
- [github.com/asottile/reorder_python_imports: v3.8.1 → v3.8.2](https://github.com/asottile/reorder_python_imports/compare/v3.8.1...v3.8.2)
- [github.com/PyCQA/flake8: 4.0.1 → 5.0.2](https://github.com/PyCQA/flake8/compare/4.0.1...5.0.2)
- [github.com/peterdemin/pip-compile-multi: v2.4.5 → v2.4.6](https://github.com/peterdemin/pip-compile-multi/compare/v2.4.5...v2.4.6)
2022-08-01 23:18:11 +00:00
David Lord
98ca00d545
Merge pull request #4720 from pallets/deprecate-env
deprecate `FLASK_ENV` and `app.env`
2022-08-01 15:19:16 -07:00
David Lord
30427a2090
remove FLASK_ENV from docs 2022-08-01 15:11:35 -07:00
David Lord
ef95998d79
deprecate FLASK_ENV 2022-08-01 15:11:21 -07:00
David Lord
4c08e3a2ba
update pycharm instructions 2022-08-01 11:39:31 -07:00
David Lord
3e5ca2902e
Merge pull request #4719 from pallets/remove-lazy-option
remove `__traceback_hide__`
2022-08-01 10:56:14 -07:00
David Lord
7d53a129cf
remove __traceback_hide__ 2022-08-01 10:52:12 -07:00
David Lord
633f421031
Merge pull request #4718 from pallets/remove-lazy-option
remove `--eager-loader/--lazy-loader` options
2022-08-01 10:44:31 -07:00
David Lord
5d8e35653f
refactor lazy loading
Remove the `--eager-loading/--lazy-loading` options and the
`DispatchingApp` middleware. The `run` command handles loading
exceptions directly. The reloader always prints out tracebacks
immediately and always defers raising the error.
2022-08-01 10:34:13 -07:00
David Lord
095651be9e
fix has_app_context and has_request_context 2022-07-25 07:35:17 -07:00
David Lord
02a0851252
Merge branch '2.1.x' 2022-07-24 19:37:30 -07:00
David Lord
363be75e84
remove reference links from changelog 2022-07-24 19:36:31 -07:00
David Lord
2869ddf50c
update blinker intersphinx link 2022-07-24 19:35:28 -07:00
David Lord
add53e190c
require Werkzeug 2.2 2022-07-24 18:42:11 -07:00
David Lord
900e11850a
Merge pull request #4695 from zr40/allow-typeddict-as-responsevalue
Allow TypedDict as a ResponseValue
2022-07-14 14:17:38 -07:00
Matthijs van der Vleuten
4bf7415a96
allow TypedDict as a response value 2022-07-14 14:15:05 -07:00
David Lord
76a6b4f2b5
Merge branch '2.1.x' 2022-07-13 14:03:01 -07:00
David Lord
4f01c68a4b
fix issue link 2022-07-13 14:02:50 -07:00
David Lord
48fe96588c
Merge branch '2.1.x' 2022-07-13 13:58:07 -07:00
David Lord
67310ab496
Merge pull request #4692 from pallets/json-provider
add JSON provider interface
2022-07-13 09:55:00 -07:00
David Lord
69f9845ef2
add json provider interface 2022-07-13 07:42:52 -07:00
David Lord
c356c6da5f
Merge pull request #4687 from Jalkhov/patch-1
Fix CHANGES.rst typo
2022-07-11 16:50:10 -07:00
Pedro Torcatt
03b410066b
Fix docs/CHANGES.rst typo 2022-07-11 18:02:00 -04:00
David Lord
4696156278
Merge pull request #4686 from Jalkhov/main
Small grammatical suggestion
2022-07-10 04:36:55 -07:00
Pedro Torcatt
58ecacd271
Change Roll back by Rever 2022-07-10 07:22:56 -04:00
David Lord
5775d1e9b1
Merge pull request #4685 from pgjones/name
Change _cv_req -> _cv_request
2022-07-09 05:44:52 -07:00
pgjones
91044c4d76 Change _cv_req -> _cv_request
This is a clearer name for the variable.
2022-07-09 13:41:35 +01:00
David Lord
979e0adbac
fix pr link 2022-07-08 12:02:18 -07:00
David Lord
cbebdae698
Merge pull request #4682 from pallets/refactor-context-stack
remove use of `LocalStack`
2022-07-08 11:58:44 -07:00
David Lord
e0dad45481
update docs about contexts 2022-07-08 11:13:09 -07:00
David Lord
82c2e0366c
remove uses of LocalStack 2022-07-08 11:13:09 -07:00
David Lord
d597db67de
contexts no longer use LocalStack 2022-07-08 11:13:09 -07:00
David Lord
0b2f809f9b
access names as proxies directly 2022-07-08 11:13:09 -07:00
David Lord
89463cb77c
require Werkzeug 2.2 2022-07-08 11:13:09 -07:00
David Lord
c757882808
Merge pull request #4680 from pgjones/typing-test
Add further typing tests
2022-07-08 06:41:56 -07:00
pgjones
2f1d1d6256 Add further typing tests
This should help ensure the app decorators are correctly typed.
2022-07-08 14:33:20 +01:00
Phil Jones
9b44bf2818
Improve decorator typing (#4676)
* Add a missing setupmethod decorator

* Improve the decorator typing

This will allow type checkers to understand that the decorators return
the same function signature as passed as an argument. This follows the
guidelines from
https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators.

I've chosen to keep a TypeVar per module and usage as I think
encouraged by PEP 695, which I hope is accepted as the syntax is much
nicer.
2022-07-06 14:05:20 -07:00
David Lord
d7482cd765
Merge branch '2.1.x' 2022-07-04 17:03:08 -07:00
David Lord
50df54e4c7
explain workflow 2022-07-04 08:35:36 -07:00
David Lord
559a8458c4
Merge pull request #4672 from greyli/return-list
Allow to return list as JSON
2022-07-02 21:48:06 -07:00
David Lord
60b845ebab
update typing tests for json 2022-07-02 21:41:37 -07:00
David Lord
f8cb0b0dd5
update docs about json 2022-07-02 21:41:37 -07:00
Grey Li
ca2bfbb0ac
Support returning list as JSON 2022-07-02 21:41:32 -07:00
David Lord
1626aff602
Merge branch '2.1.x' 2022-07-02 21:03:09 -07:00
David Lord
c99f07d3e4
Merge pull request #4667 from pallets/remove-deprecated-code
Remove deprecated code
2022-07-01 14:14:37 -07:00
David Lord
c2810ffdd2
remove deprecated send_file argument names 2022-07-01 13:59:44 -07:00
David Lord
9e686d93b6
remove deprecated RequestContext.g 2022-07-01 13:44:31 -07:00
David Lord
96d39c87a8
Merge remote-tracking branch 'origin/2.1.x' 2022-07-01 13:32:50 -07:00
David Lord
6916697a98
Merge pull request #4666 from pallets/debug-context
new preserve context implementation
2022-07-01 12:35:24 -07:00
David Lord
84c722044a
new debug/test preserve context implementation 2022-07-01 12:01:44 -07:00
David Lord
57a95e82b7
Merge pull request #4665 from pallets/dependabot/github_actions/actions/setup-python-4
Bump actions/setup-python from 3 to 4
2022-07-01 09:45:43 -07:00
dependabot[bot]
2589328485
Bump actions/setup-python from 3 to 4
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 3 to 4.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-01 16:05:52 +00:00
David Lord
3635583ce2
Merge pull request #4662 from pallets/fix-run-skip
re-add flag to skip unguarded app.run from CLI
2022-06-29 21:21:52 -07:00
David Lord
5544d09477
re-add flag to skip unguarded app.run from CLI 2022-06-29 21:19:28 -07:00
David Lord
ab36542260
Merge pull request #4629 from pgjones/generate
allow view to return generator
2022-06-18 12:24:13 -07:00
pgjones
46433e9807
add generate_template and generate_template_string functions 2022-06-18 12:20:53 -07:00
pgjones
762382e436
view functions can return generators as responses directly 2022-06-18 11:25:05 -07:00
David Lord
7f2a0f4806
Merge pull request #4645 from kkirsche/patch-2
Use timezone aware datetime object on session
2022-06-17 12:05:19 -07:00
Kevin Kirsche
ed42e92928
session expiration datetime is UTC timezone-aware 2022-06-17 12:01:48 -07:00
David Lord
cec5f74110
Merge pull request #4647 from pallets/cli-app_context
with_appcontext lasts for the lifetime of the click context
2022-06-17 11:57:22 -07:00
David Lord
c9e000b9ce
with_appcontext lasts for the lifetime of the click context 2022-06-17 11:52:01 -07:00
David Lord
ae547270e9
Merge pull request #4646 from pallets/cli-app-env 2022-06-17 09:30:28 -07:00
David Lord
ab1fbef29a
prefer --app over FLASK_APP in docs 2022-06-17 09:26:26 -07:00
David Lord
99fa3c36ab
add --app, --env, --debug, and --env-file CLI options 2022-06-17 08:19:55 -07:00
David Lord
fe4003b3c9
Merge pull request #4642 from pallets/cli-nest
`FlaskGroup` can be nested
2022-06-15 14:17:45 -07:00
David Lord
aa801c431a
FlaskGroup can be nested 2022-06-15 14:09:56 -07:00
David Lord
4f03a769d4
edit some cli messages
dev server message doesn't show one of the lines in grey
app.run message uses click.secho instead of warning
2022-06-15 12:45:22 -07:00
David Lord
97298e06fe
Merge branch '2.1.x' 2022-06-12 16:04:01 -07:00
David Lord
9139af1c62
Merge branch '2.1.x' 2022-06-12 14:10:51 -07:00
David Lord
dcd1a1e0b6
Merge branch '2.1.x' 2022-06-11 14:16:51 -07:00
David Lord
db3187fd7a
Merge pull request #4624 from pallets/view-init-scope
add `View.init_every_request` attribute
2022-06-06 15:52:48 -07:00
David Lord
45174bf9a1
use __init_subclass__ instead of metaclass for MethodView 2022-06-06 15:48:36 -07:00
David Lord
bab5a65e6e
rewrite class-based view docs 2022-06-06 15:33:46 -07:00
David Lord
6e23239567
add View.init_every_request attribute 2022-06-06 15:11:01 -07:00
David Lord
aab1d9935e
Merge pull request #4621 from pallets/deprecate-before_first_request
deprecate before_first_request
2022-06-06 10:11:00 -07:00
David Lord
96c97dec09
deprecate before_first_request 2022-06-06 10:04:05 -07:00
David Lord
7a2d5fb6df
Merge branch '2.1.x' 2022-06-06 09:30:30 -07:00
David Lord
9e2e1de2fc
Merge branch '2.1.x' 2022-06-01 11:27:08 -07:00
David Lord
c6e3fc8072
Merge pull request #4613 from citramon/test_for_from_mapping_config_skip_not_upper
Add test config.from_mapping method: ignoring items with non-upper keys
2022-05-31 09:10:36 -07:00
Stanislav Bushuev
3ecebcdf8d Add test config.from_mapping method: ignoring items with non-upper keys 2022-05-31 17:51:39 +02:00
David Lord
1888df3440
Merge remote-tracking branch 'origin/2.1.x' 2022-05-23 10:08:52 -07:00
David Lord
a52a7db6c9
Merge pull request #4577 from hallacy/hallacy/fix_4571
update setupmethod behavior
2022-05-23 09:12:45 -07:00
David Lord
e044b00047
avoid triggering setupmethod late in tests 2022-05-23 09:09:12 -07:00
David Lord
a406c297aa
apply setupmethod consistently 2022-05-23 09:09:12 -07:00
Chris Hallacy
eb36135cfe
always warn on blueprint setupmethod after registration 2022-05-23 09:09:12 -07:00
David Lord
ca8e6217fe
Merge pull request #4596 from pallets/url_for-template
use app.url_for as template global
2022-05-15 08:54:26 -07:00
David Lord
69e2300608
use app.url_for as template global
avoid extra call from helpers.url_for
update changelog for method moves
2022-05-15 08:48:30 -07:00
David Lord
00e2aac937
Merge pull request #4580 from ionesu/move_url_for_to_the_flask_app_object
Move url_for to the Flask app object
2022-05-14 12:50:37 -07:00
David Lord
39f9363296
finish moving url_for to app
move entire implementation to app
make special build args actual keyword-only args
handle no app context in method
mention other config in server_name error
implicit external with scheme
use adapter.build url_scheme argument
rewrite documentation
2022-05-14 12:46:01 -07:00
Ivan Sushkov
92acd05d9b
add url_for method to app 2022-05-14 12:45:18 -07:00
David Lord
fac630379d
update app.redirect docs 2022-05-12 16:33:40 -07:00
David Lord
5512a66881
Merge pull request #4576 from dzcode/dzcode/4567/abort-implementation
Add 'aborter' and 'aborter_class' attrs to 'Flask' object
2022-05-12 13:45:37 -07:00
dzcode
eb5dd9f5ef
add aborter object to app 2022-05-12 13:29:54 -07:00
David Lord
a25d234cdd
Merge remote-tracking branch 'origin/2.1.x' 2022-05-11 09:39:26 -07:00
David Lord
542cf30e48
Merge pull request #4575 from thoagland/Issue_4569_add_redirect_to_Flask_App
add `app.redirect` method
2022-05-11 09:22:19 -07:00
Tim Hoagland
fdab801fbb
add redirect method to app 2022-05-10 11:02:24 -07:00
David Lord
bd56d19b16
Merge pull request #4566 from citramon/improve_coverage 2022-05-03 12:17:03 -06:00
Stanislav Bushuev
a74e266474
skip coverage for TYPE_CHECKING 2022-05-03 12:11:55 -06:00
David Lord
127df57a06
Merge pull request #4560 from qingpeng9802/fix-old-behavior 2022-05-03 11:56:11 -06:00
Qingpeng Li
1e5dd43022
refactor error checks in register_error_handler
Co-authored-by: David Lord <davidism@gmail.com>
2022-05-03 11:52:11 -06:00
David Lord
f976d5bb88
Merge branch '2.1.x' 2022-04-28 10:48:05 -07:00
David Lord
918fc07dd9
Merge branch '2.1.x' 2022-04-28 08:59:47 -07:00
David Lord
2b0b77cc1a
Merge branch '2.1.x' 2022-04-24 10:20:07 -07:00
David Lord
cb4f742543
Merge branch '2.1.x' 2022-04-24 10:14:53 -07:00
David Lord
a03719b010
Merge branch '2.1.x' 2022-04-08 11:06:32 -07:00
David Lord
f59574f611
Merge branch '2.1.x' 2022-04-01 13:55:05 -07:00
David Lord
f70abe634a
Merge pull request #4515 from pallets/dependabot/github_actions/actions/checkout-3
Bump actions/checkout from 2 to 3
2022-04-01 09:08:47 -07:00
dependabot[bot]
9f4f559f59
Bump actions/checkout from 2 to 3
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-01 16:04:08 +00:00
David Lord
45fc77d926
Merge branch '2.1.x' 2022-03-30 14:39:31 -07:00
David Lord
b109b092a9
start version 2.2.0 2022-03-28 12:17:25 -07:00
192 changed files with 11538 additions and 9681 deletions

View file

@ -0,0 +1,17 @@
{
"name": "pallets/flask",
"image": "mcr.microsoft.com/devcontainers/python:3",
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "${workspaceFolder}/.venv",
"python.terminal.activateEnvInCurrentTerminal": true,
"python.terminal.launchArgs": [
"-X",
"dev"
]
}
}
},
"onCreateCommand": ".devcontainer/on-create-command.sh"
}

View file

@ -0,0 +1,7 @@
#!/bin/bash
set -e
python3 -m venv --upgrade-deps .venv
. .venv/bin/activate
pip install -r requirements/dev.txt
pip install -e .
pre-commit install --install-hooks

View file

@ -9,5 +9,5 @@ end_of_line = lf
charset = utf-8
max_line_length = 88
[*.{yml,yaml,json,js,css,html}]
[*.{css,html,js,json,jsx,scss,ts,tsx,yaml,yml}]
indent_size = 2

View file

@ -5,7 +5,7 @@ about: Report a bug in Flask (not other projects which depend on Flask)
<!--
This issue tracker is a tool to address bugs in Flask itself. Please use
Pallets Discord or Stack Overflow for questions about your own code.
GitHub Discussions or the Pallets Discord for questions about your own code.
Replace this comment with a clear outline of what the bug is.
-->

View file

@ -1,11 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Security issue
url: security@palletsprojects.com
about: Do not report security issues publicly. Email our security contact.
- name: Questions
url: https://stackoverflow.com/questions/tagged/flask?tab=Frequent
about: Search for and ask questions about your code on Stack Overflow.
- name: Questions and discussions
url: https://github.com/pallets/flask/security/advisories/new
about: Do not report security issues publicly. Create a private advisory.
- name: Questions on GitHub Discussions
url: https://github.com/pallets/flask/discussions/
about: Ask questions about your own code on the Discussions tab.
- name: Questions on Discord
url: https://discord.gg/pallets
about: Discuss questions about your code on our Discord chat.
about: Ask questions about your own code on our Discord chat.

19
.github/SECURITY.md vendored
View file

@ -1,19 +0,0 @@
# Security Policy
If you believe you have identified a security issue with a Pallets
project, **do not open a public issue**. To responsibly report a
security issue, please email security@palletsprojects.com. A security
team member will contact you acknowledging the report and how to
continue.
Be sure to include as much detail as necessary in your report. As with
reporting normal issues, a minimal reproducible example will help the
maintainers address the issue faster. If you are able, you may also
include a fix for the issue generated with `git format-patch`.
The current and previous release will receive security patches, with
older versions evaluated based on usage information and severity.
After fixing an issue, we will make a security release along with an
announcement on our blog. We may obtain a CVE id as well. You may
include a name and link if you would like to be credited for the report.

View file

@ -1,9 +0,0 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
day: "monday"
time: "16:00"
timezone: "UTC"

View file

@ -1,6 +1,7 @@
<!--
Before opening a PR, open a ticket describing the issue or feature the
PR will address. Follow the steps in CONTRIBUTING.rst.
PR will address. An issue is not required for fixing typos in
documentation, or other simple non-code changes.
Replace this comment with a description of the change. Describe how it
addresses the linked ticket.
@ -9,22 +10,16 @@ addresses the linked ticket.
<!--
Link to relevant issues or previous PRs, one per line. Use "fixes" to
automatically close an issue.
-->
- fixes #<issue number>
fixes #<issue number>
-->
<!--
Ensure each step in CONTRIBUTING.rst is complete by adding an "x" to
each box below.
Ensure each step in CONTRIBUTING.rst is complete, especially the following:
If only docs were changed, these aren't relevant and can be removed.
- Add tests that demonstrate the correct behavior of the change. Tests
should fail without the change.
- Add or update relevant docs, in the docs folder and in code.
- Add an entry in CHANGES.rst summarizing the change and linking to the issue.
- Add `.. versionchanged::` entries in any relevant code docs.
-->
Checklist:
- [ ] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [ ] Add or update relevant docs, in the docs folder and in code.
- [ ] Add an entry in `CHANGES.rst` summarizing the change and linking to the issue.
- [ ] Add `.. versionchanged::` entries in any relevant code docs.
- [ ] Run `pre-commit` hooks and fix any issues.
- [ ] Run `pytest` and `tox`, no tests failed.

View file

@ -1,15 +1,26 @@
name: 'Lock threads'
name: Lock inactive closed issues
# Lock closed issues that have not received any further activity for two weeks.
# This does not close open issues, only humans may do that. It is easier to
# respond to new issues with fresh examples rather than continuing discussions
# on old issues.
on:
schedule:
- cron: '0 0 * * *'
permissions: {}
concurrency:
group: lock
cancel-in-progress: true
jobs:
lock:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
discussions: write
steps:
- uses: dessant/lock-threads@v3
- uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7 # v6.0.0
with:
github-token: ${{ github.token }}
issue-inactive-days: 14
pr-inactive-days: 14
discussion-inactive-days: 14

29
.github/workflows/pre-commit.yaml vendored Normal file
View file

@ -0,0 +1,29 @@
name: pre-commit
on:
pull_request:
push:
branches: [main, stable]
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true
prune-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
id: setup-python
with:
python-version-file: pyproject.toml
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ~/.cache/pre-commit
key: pre-commit|${{ hashFiles('pyproject.toml', '.pre-commit-config.yaml') }}
- run: uv run --locked --no-default-groups --group pre-commit pre-commit run --show-diff-on-failure --color=always --all-files

62
.github/workflows/publish.yaml vendored Normal file
View file

@ -0,0 +1,62 @@
name: Publish
on:
push:
tags: ['*']
permissions: {}
concurrency:
group: publish-${{ github.event.push.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
outputs:
artifact-id: ${{ steps.upload-artifact.outputs.artifact-id }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: false
prune-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version-file: pyproject.toml
- run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV
- run: uv build
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
id: upload-artifact
with:
name: dist
path: dist/
if-no-files-found: error
create-release:
needs: [build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ needs.build.outputs.artifact-id }}
path: dist/
- name: create release
run: gh release create --draft --repo ${GITHUB_REPOSITORY} ${GITHUB_REF_NAME} dist/*
env:
GH_TOKEN: ${{ github.token }}
publish-pypi:
needs: [build]
environment:
name: publish
url: https://pypi.org/project/Flask/${{ github.ref_name }}
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
artifact-ids: ${{ needs.build.outputs.artifact-id }}
path: dist/
- uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with:
packages-dir: "dist/"

View file

@ -1,51 +1,63 @@
name: Tests
on:
push:
branches:
- main
- '*.x'
paths-ignore:
- 'docs/**'
- '*.md'
- '*.rst'
pull_request:
branches:
- main
- '*.x'
paths-ignore:
- 'docs/**'
- '*.md'
- '*.rst'
paths-ignore: ['docs/**', 'README.md']
push:
branches: [main, stable]
paths-ignore: ['docs/**', 'README.md']
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
tests:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
name: ${{ matrix.name || matrix.python }}
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
strategy:
fail-fast: false
matrix:
include:
- {name: Linux, python: '3.10', os: ubuntu-latest, tox: py310}
- {name: Windows, python: '3.10', os: windows-latest, tox: py310}
- {name: Mac, python: '3.10', os: macos-latest, tox: py310}
- {name: '3.11-dev', python: '3.11-dev', os: ubuntu-latest, tox: py311}
- {name: '3.9', python: '3.9', os: ubuntu-latest, tox: py39}
- {name: '3.8', python: '3.8', os: ubuntu-latest, tox: py38}
- {name: '3.7', python: '3.7', os: ubuntu-latest, tox: py37}
- {name: 'PyPy', python: 'pypy-3.7', os: ubuntu-latest, tox: pypy37}
- {name: 'Pallets Minimum Versions', python: '3.10', os: ubuntu-latest, tox: py-min}
- {name: 'Pallets Development Versions', python: '3.7', os: ubuntu-latest, tox: py-dev}
- {name: Typing, python: '3.10', os: ubuntu-latest, tox: typing}
- {python: '3.14'}
- {python: '3.14t'}
- {name: Windows, python: '3.14', os: windows-latest}
- {name: Mac, python: '3.14', os: macos-latest}
- {python: '3.13'}
- {python: '3.12'}
- {python: '3.11'}
- {python: '3.10'}
- {name: PyPy, python: 'pypy-3.11', tox: pypy3.11}
- {name: Minimum Versions, python: '3.14', tox: tests-min}
- {name: Development Versions, python: '3.10', tox: tests-dev}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v3
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true
prune-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ matrix.python }}
cache: 'pip'
cache-dependency-path: 'requirements/*.txt'
- name: update pip
run: |
pip install -U wheel
pip install -U setuptools
python -m pip install -U pip
- run: pip install tox
- run: tox -e ${{ matrix.tox }}
- run: uv run --locked --no-default-groups --group dev tox run
env:
TOX_ENV: ${{ matrix.tox || format('py{0}', matrix.python) }}
typing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
with:
enable-cache: true
prune-cache: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version-file: pyproject.toml
- name: cache mypy
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
with:
path: ./.mypy_cache
key: mypy|${{ hashFiles('pyproject.toml') }}
- run: uv run --locked --no-default-groups --group dev tox run -e typing

22
.github/workflows/zizmor.yaml vendored Normal file
View file

@ -0,0 +1,22 @@
name: GitHub Actions security analysis with zizmor
on:
pull_request:
paths: ["**/*.yaml?"]
push:
branches: [main, stable]
paths: ["**/*.yaml?"]
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
zizmor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
with:
advanced-security: false
annotations: true

29
.gitignore vendored
View file

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

View file

@ -1,38 +1,23 @@
ci:
autoupdate_branch: "2.1.x"
autoupdate_schedule: monthly
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v2.37.1
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: 5e2fb545eba1ea9dc051f6f962d52fe8f76a9794 # frozen: v0.15.13
hooks:
- id: pyupgrade
args: ["--py36-plus"]
- repo: https://github.com/asottile/reorder_python_imports
rev: v3.8.1
- id: ruff-check
- id: ruff-format
- repo: https://github.com/astral-sh/uv-pre-commit
rev: fa60a193803535a9e2accdb3ca4b1b584b1150cb # frozen: 0.11.15
hooks:
- id: reorder-python-imports
name: Reorder Python imports (src, tests)
files: "^(?!examples/)"
args: ["--application-directories", "src"]
additional_dependencies: ["setuptools>60.9"]
- repo: https://github.com/psf/black
rev: 22.6.0
- id: uv-lock
- repo: https://github.com/codespell-project/codespell
rev: 2ccb47ff45ad361a21071a7eedda4c37e6ae8c5a # frozen: v2.4.2
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
rev: 4.0.1
hooks:
- id: flake8
additional_dependencies:
- flake8-bugbear
- flake8-implicit-str-concat
- repo: https://github.com/peterdemin/pip-compile-multi
rev: v2.4.5
hooks:
- id: pip-compile-multi-verify
- id: codespell
args: ['--write-changes']
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: check-merge-conflict
- id: debug-statements
- id: fix-byte-order-marker
- id: trailing-whitespace
- id: end-of-file-fixer

View file

@ -1,13 +1,10 @@
version: 2
build:
os: ubuntu-20.04
os: ubuntu-24.04
tools:
python: "3.10"
python:
install:
- requirements: requirements/docs.txt
- method: pip
path: .
sphinx:
builder: dirhtml
fail_on_warning: true
python: '3.13'
commands:
- asdf plugin add uv
- asdf install uv latest
- asdf global uv latest
- uv run --group docs sphinx-build -W -b dirhtml docs $READTHEDOCS_OUTPUT/html

File diff suppressed because it is too large Load diff

View file

@ -1,76 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at report@palletsprojects.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View file

@ -1,227 +0,0 @@
How to contribute to Flask
==========================
Thank you for considering contributing to Flask!
Support questions
-----------------
Please don't use the issue tracker for this. The issue tracker is a tool
to address bugs and feature requests in Flask itself. Use one of the
following resources for questions about using Flask or issues with your
own code:
- The ``#questions`` channel on our Discord chat:
https://discord.gg/pallets
- Ask on `Stack Overflow`_. Search with Google first using:
``site:stackoverflow.com flask {search term, exception message, etc.}``
- Ask on our `GitHub Discussions`_ for long term discussion or larger
questions.
.. _Stack Overflow: https://stackoverflow.com/questions/tagged/flask?tab=Frequent
.. _GitHub Discussions: https://github.com/pallets/flask/discussions
Reporting issues
----------------
Include the following information in your post:
- Describe what you expected to happen.
- If possible, include a `minimal reproducible example`_ to help us
identify the issue. This also helps check that the issue is not with
your own code.
- Describe what actually happened. Include the full traceback if there
was an exception.
- List your Python and Flask versions. If possible, check if this
issue is already fixed in the latest releases or the latest code in
the repository.
.. _minimal reproducible example: https://stackoverflow.com/help/minimal-reproducible-example
Submitting patches
------------------
If there is not an open issue for what you want to submit, prefer
opening one for discussion before working on a PR. You can work on any
issue that doesn't have an open PR linked to it or a maintainer assigned
to it. These show up in the sidebar. No need to ask if you can work on
an issue that interests you.
Include the following in your patch:
- Use `Black`_ to format your code. This and other tools will run
automatically if you install `pre-commit`_ using the instructions
below.
- Include tests if your patch adds or changes code. Make sure the test
fails without your patch.
- Update any relevant docs pages and docstrings. Docs pages and
docstrings should be wrapped at 72 characters.
- Add an entry in ``CHANGES.rst``. Use the same style as other
entries. Also include ``.. versionchanged::`` inline changelogs in
relevant docstrings.
.. _Black: https://black.readthedocs.io
.. _pre-commit: https://pre-commit.com
First time setup
~~~~~~~~~~~~~~~~
- Download and install the `latest version of git`_.
- Configure git with your `username`_ and `email`_.
.. code-block:: text
$ git config --global user.name 'your name'
$ git config --global user.email 'your email'
- Make sure you have a `GitHub account`_.
- Fork Flask to your GitHub account by clicking the `Fork`_ button.
- `Clone`_ the main repository locally.
.. code-block:: text
$ git clone https://github.com/pallets/flask
$ cd flask
- Add your fork as a remote to push your work to. Replace
``{username}`` with your username. This names the remote "fork", the
default Pallets remote is "origin".
.. code-block:: text
$ git remote add fork https://github.com/{username}/flask
- Create a virtualenv.
- Linux/macOS
.. code-block:: text
$ python3 -m venv env
$ . env/bin/activate
- Windows
.. code-block:: text
> py -3 -m venv env
> env\Scripts\activate
- Upgrade pip and setuptools.
.. code-block:: text
$ python -m pip install --upgrade pip setuptools
- Install the development dependencies, then install Flask in editable
mode.
.. code-block:: text
$ pip install -r requirements/dev.txt && pip install -e .
- Install the pre-commit hooks.
.. code-block:: text
$ pre-commit install
.. _latest version of git: https://git-scm.com/downloads
.. _username: https://docs.github.com/en/github/using-git/setting-your-username-in-git
.. _email: https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/setting-your-commit-email-address
.. _GitHub account: https://github.com/join
.. _Fork: https://github.com/pallets/flask/fork
.. _Clone: https://docs.github.com/en/github/getting-started-with-github/fork-a-repo#step-2-create-a-local-clone-of-your-fork
Start coding
~~~~~~~~~~~~
- Create a branch to identify the issue you would like to work on. If
you're submitting a bug or documentation fix, branch off of the
latest ".x" branch.
.. code-block:: text
$ git fetch origin
$ git checkout -b your-branch-name origin/2.0.x
If you're submitting a feature addition or change, branch off of the
"main" branch.
.. code-block:: text
$ git fetch origin
$ git checkout -b your-branch-name origin/main
- Using your favorite editor, make your changes,
`committing as you go`_.
- Include tests that cover any code changes you make. Make sure the
test fails without your patch. Run the tests as described below.
- Push your commits to your fork on GitHub and
`create a pull request`_. Link to the issue being addressed with
``fixes #123`` in the pull request.
.. code-block:: text
$ git push --set-upstream fork your-branch-name
.. _committing as you go: https://dont-be-afraid-to-commit.readthedocs.io/en/latest/git/commandlinegit.html#commit-your-changes
.. _create a pull request: https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request
Running the tests
~~~~~~~~~~~~~~~~~
Run the basic test suite with pytest.
.. code-block:: text
$ pytest
This runs the tests for the current environment, which is usually
sufficient. CI will run the full suite when you submit your pull
request. You can run the full test suite with tox if you don't want to
wait.
.. code-block:: text
$ tox
Running test coverage
~~~~~~~~~~~~~~~~~~~~~
Generating a report of lines that do not have test coverage can indicate
where to start contributing. Run ``pytest`` using ``coverage`` and
generate a report.
.. code-block:: text
$ pip install coverage
$ coverage run -m pytest
$ coverage html
Open ``htmlcov/index.html`` in your browser to explore the report.
Read more about `coverage <https://coverage.readthedocs.io>`__.
Building the docs
~~~~~~~~~~~~~~~~~
Build the docs in the ``docs`` directory using Sphinx.
.. code-block:: text
$ cd docs
$ make html
Open ``_build/html/index.html`` in your browser to view the docs.
Read more about `Sphinx <https://www.sphinx-doc.org/en/stable/>`__.

View file

@ -1,11 +0,0 @@
include CHANGES.rst
include CONTRIBUTING.rst
include tox.ini
include requirements/*.txt
graft artwork
graft docs
prune docs/_build
graft examples
graft tests
include src/flask/py.typed
global-exclude *.pyc

53
README.md Normal file
View file

@ -0,0 +1,53 @@
<div align="center"><img src="https://raw.githubusercontent.com/pallets/flask/refs/heads/stable/docs/_static/flask-name.svg" alt="" height="150"></div>
# Flask
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. It began as a simple wrapper around [Werkzeug]
and [Jinja], and has become one of the most popular Python web
application frameworks.
Flask offers suggestions, but doesn't enforce any dependencies or
project layout. It is up to the developer to choose the tools and
libraries they want to use. There are many extensions provided by the
community that make adding new functionality easy.
[WSGI]: https://wsgi.readthedocs.io/
[Werkzeug]: https://werkzeug.palletsprojects.com/
[Jinja]: https://jinja.palletsprojects.com/
## A Simple Example
```python
# save this as app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
```
```
$ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
```
## Donate
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, [please
donate today].
[please donate today]: https://palletsprojects.com/donate
## Contributing
See our [detailed contributing documentation][contrib] for many ways to
contribute, including reporting issues, requesting features, asking or answering
questions, and making PRs.
[contrib]: https://palletsprojects.com/contributing/

View file

@ -1,82 +0,0 @@
Flask
=====
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. It began as a simple wrapper around `Werkzeug`_
and `Jinja`_ and has become one of the most popular Python web
application frameworks.
Flask offers suggestions, but doesn't enforce any dependencies or
project layout. It is up to the developer to choose the tools and
libraries they want to use. There are many extensions provided by the
community that make adding new functionality easy.
.. _WSGI: https://wsgi.readthedocs.io/
.. _Werkzeug: https://werkzeug.palletsprojects.com/
.. _Jinja: https://jinja.palletsprojects.com/
Installing
----------
Install and update using `pip`_:
.. code-block:: text
$ pip install -U Flask
.. _pip: https://pip.pypa.io/en/stable/getting-started/
A Simple Example
----------------
.. code-block:: python
# save this as app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
.. code-block:: text
$ flask run
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Contributing
------------
For guidance on setting up a development environment and how to make a
contribution to Flask, see the `contributing guidelines`_.
.. _contributing guidelines: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst
Donate
------
The Pallets organization develops and supports Flask and the libraries
it uses. In order to grow the community of contributors and users, and
allow the maintainers to devote more time to the projects, `please
donate today`_.
.. _please donate today: https://palletsprojects.com/donate
Links
-----
- Documentation: https://flask.palletsprojects.com/
- Changes: https://flask.palletsprojects.com/changes/
- PyPI Releases: https://pypi.org/project/Flask/
- Source Code: https://github.com/pallets/flask/
- Issue Tracker: https://github.com/pallets/flask/issues/
- Website: https://palletsprojects.com/p/flask/
- Twitter: https://twitter.com/PalletsTeam
- Chat: https://discord.gg/pallets

View file

@ -1,19 +0,0 @@
Copyright 2010 Pallets
This logo or a modified version may be used by anyone to refer to the
Flask project, but does not indicate endorsement by the project.
Redistribution and use in source (SVG) and binary (renders in PNG, etc.)
forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright
notice and this list of conditions.
2. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
We would appreciate that you make the image a link to
https://palletsprojects.com/p/flask/ if you use it in a medium that
supports links.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 77 KiB

View file

@ -1,165 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="211.15901"
height="190.52811"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="logo-lineart.svg">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective2824"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2840"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2878"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2894"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2910"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2926"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2976"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3020"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3036"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3052"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3866"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.1723341"
inkscape:cx="242.05817"
inkscape:cy="92.686293"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1676"
inkscape:window-height="1005"
inkscape:window-x="4"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="10"
fit-margin-left="10"
fit-margin-right="10"
fit-margin-bottom="10" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-29.820801,-20.186869)">
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="M 9.7525867,55.788422 C 40.421293,45.982204 33.821969,46.567748 69.327984,40.346648 c 8.493721,2.411576 22.910914,5.687215 22.240236,12.296506 -6.241933,2.320572 -15.351869,-6.455434 -20.254712,-1.539882 0.01014,18.421641 5.965221,38.200493 13.480678,55.747588 7.515457,17.5471 18.880714,32.86245 34.290034,42.35708 20.42595,12.66826 41.92048,14.9356 63.64846,15.65546 6.66858,0.23786 17.30912,-1.47838 20.01846,0 -4.9124,8.703 -19.28006,12.8118 -34.21844,14.71154 -14.93837,1.89974 -30.44747,1.59043 -37.64272,1.45723 -15.88921,-0.50065 -29.5942,-2.65111 -42.06658,-7.29048 C 56.640409,160.78176 38.428746,134.71246 24.668078,106.25832 16.765019,89.693325 11.290118,72.259923 9.7525867,55.788422 z"
id="path3826"
inkscape:connector-curvature="0"
transform="translate(29.820801,20.186869)"
sodipodi:nodetypes="ccccscccscccc" />
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 54.066806,32.351647 c -0.427165,0.87404 -0.384822,1.998232 -0.02834,2.90275 0.781834,1.983761 2.799883,3.252081 4.397491,4.681241 0.728446,0.651642 2.26934,0.803097 2.364296,1.769134 0.215279,2.190161 -2.700769,3.566537 -4.456242,4.921486 -1.316317,1.015991 -3.845581,0.776849 -4.451985,2.314219 -0.417515,1.058499 0.837317,2.10047 1.1679,3.188615 0.465799,1.533243 1.642442,3.150334 1.145997,4.674061 -0.597449,1.833868 -2.700081,2.84663 -4.420626,3.754433 -1.893115,0.998854 -4.450538,0.497797 -6.207667,1.715064 -1.674125,1.159765 -3.485979,2.907099 -3.554321,4.925579 -0.03097,0.915115 -0.384582,2.676814 -0.233936,3.114037 12.863193,-4.155671 20.195138,-6.507915 28.694286,-8.598094 8.499136,-2.090222 16.108852,-3.399531 29.579722,-5.689662 -0.06867,-0.457321 -1.197061,-1.855664 -1.647827,-2.652661 -0.994254,-1.75795 -3.408869,-2.469029 -5.429591,-2.722885 -2.120906,-0.26644 -4.15652,1.360749 -6.296964,1.350851 -1.945327,-0.009 -4.277958,0.06569 -5.655921,-1.283841 -1.144955,-1.121286 -0.849755,-3.099246 -1.145997,-4.674061 -0.210243,-1.117649 0.420309,-2.621884 -0.439473,-3.367212 -1.248754,-1.082519 -3.380554,0.299434 -5.017542,0.0075 -2.183125,-0.389274 -5.405114,-0.260713 -6.227327,-2.302063 -0.362663,-0.900401 0.93342,-1.747432 1.277831,-2.662119 0.75535,-2.006065 1.957858,-4.064009 1.733419,-6.184432 -0.102333,-0.966833 -0.5848,-1.983113 -1.367813,-2.56044 -1.68203,-1.191313 -4.366912,-1.323763 -7.531636,-0.525881 -3.164723,0.797885 -5.342193,2.137743 -6.247739,3.90434 z"
id="path3832"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssssscssscccssscssssssccc" />
<path
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 71.836704,50.617573 c 0,0 -24.55635,5.277975 -35.918352,8.551988 C 27.8621,61.491007 12.143824,67.37947 12.143824,67.37947"
id="path3847"
inkscape:connector-curvature="0"
transform="translate(29.820801,20.186869)"
sodipodi:nodetypes="csc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

15
docs/_static/flask-icon.svg vendored Normal file
View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<rect id="Icon" x="0" y="0" width="500" height="500" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="0" y="0" width="500" height="500"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g>
<path d="M224.446,59.975c-0.056,-4.151 -0.483,-5.543 -2.7,-6.823c-2.104,-1.393 -5.288,-1.421 -8.329,-0.085l-204.674,87.64c-3.042,1.336 -5.913,4.008 -7.448,6.908c-1.535,2.899 -1.705,5.97 -0.511,8.158l17.084,31.384l0.228,0.369c1.847,2.928 6.026,3.696 10.29,1.82l1.251,-0.54c5.344,22.4 14.1,50.429 25.783,70.413l178.294,-79.794c-2.559,-23.14 -9.552,-89.602 -9.268,-119.479l0,0.029Z" style="fill:#3babc3;fill-rule:nonzero;"/>
<path d="M238.603,205.776l-171.698,76.838c10.091,19.132 22.542,39.428 37.722,58.986c50.429,-25.698 100.887,-51.396 151.316,-77.094c-3.269,-8.471 -6.452,-17.653 -17.34,-58.73Z" style="fill:#3babc3;fill-rule:nonzero;"/>
<path d="M497.601,388.846l-12.139,-18.535c-1.819,-2.018 -4.633,-2.786 -7.106,-1.791l-15.578,5.999c-1.848,-2.047 -4.52,-2.815 -7.135,-1.791c-5.089,1.99 -10.206,4.008 -15.294,5.998c-1.649,0.625 -2.104,1.847 -1.791,3.439l0.995,4.861c-28.711,3.099 -77.236,1.564 -120.701,-32.577c-19.216,-15.066 -37.239,-36.386 -52.277,-66.206l-144.75,73.768c26.466,29.08 59.697,54.864 100.973,70.385c57.422,21.633 130.593,23.679 222.838,-13.475l0.512,2.616c0.455,2.928 3.98,6.026 8.755,4.15l15.323,-5.97c5.258,-1.99 5.287,-6.026 4.519,-8.641l19.729,-7.704c2.217,-0.853 9.096,-6.169 3.183,-14.526l-0.056,-0Z" style="fill:#3babc3;fill-rule:nonzero;"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

17
docs/_static/flask-logo.svg vendored Normal file
View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 500 500" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<rect id="Logo" x="0" y="0" width="500" height="500" style="fill:none;"/>
<g>
<path id="Box" d="M500,50l0,400c0,27.596 -22.404,50 -50,50l-400,0c-27.596,0 -50,-22.404 -50,-50l0,-400c0,-27.596 22.404,-50 50,-50l400,0c27.596,0 50,22.404 50,50Z" style="fill:url(#_Linear1);"/>
<path id="Shadow" d="M500,398.646l0,51.354c0,27.596 -22.404,50 -50,50l-94.111,0l-170.452,-170.451c13.541,12.279 29.511,22.845 48.242,29.888c34.453,12.98 78.356,14.208 133.703,-8.084l0.307,1.569c0.273,1.757 2.388,3.616 5.253,2.49l9.193,-3.582c3.156,-1.194 3.173,-3.616 2.712,-5.185l11.837,-4.622c1.331,-0.512 5.458,-3.701 1.91,-8.716l-0.034,0l-7.283,-11.12c-1.091,-1.211 -2.78,-1.672 -4.264,-1.075l-9.346,3.599c-1.109,-1.228 -2.712,-1.688 -4.281,-1.074c-3.054,1.194 -6.124,2.404 -9.177,3.598c-0.989,0.376 -1.262,1.109 -1.074,2.064l0.597,2.917c-17.227,1.859 -46.342,0.938 -72.421,-19.547c-11.53,-9.039 -22.343,-21.831 -31.366,-39.723l-83.923,42.769l-13.246,-10.755c30.258,-15.419 60.532,-30.837 90.79,-46.256c-1.961,-5.083 -3.872,-10.592 -10.404,-35.238l-98.082,43.893l-11.828,-11.828l106.976,-47.876c-1.534,-13.88 -5.728,-53.736 -5.56,-71.67l-0,-0.017c-0.027,-1.894 -0.184,-2.827 -0.85,-3.504l266.182,266.182Zm-388.562,-185.436c1.272,1.164 3.414,1.356 5.594,0.397l0.75,-0.324c0.645,2.703 1.373,5.543 2.181,8.452l-8.525,-8.525Z" style="fill:#3b808b;"/>
<g id="Icon">
<path d="M234.668,135.985c-0.034,-2.49 -0.29,-3.326 -1.62,-4.094c-1.263,-0.835 -3.173,-0.852 -4.998,-0.051l-122.804,52.584c-1.825,0.802 -3.548,2.405 -4.469,4.145c-0.921,1.74 -1.023,3.582 -0.307,4.895l10.251,18.83l0.136,0.222c1.109,1.757 3.616,2.217 6.175,1.091l0.75,-0.324c3.207,13.441 8.46,30.258 15.47,42.248l106.976,-47.876c-1.535,-13.884 -5.731,-53.761 -5.56,-71.687l-0,0.017Z" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M243.162,223.466l-103.019,46.103c6.055,11.478 13.525,23.656 22.633,35.391c30.258,-15.419 60.532,-30.837 90.79,-46.256c-1.961,-5.083 -3.872,-10.592 -10.404,-35.238Z" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M398.56,333.307l-7.283,-11.12c-1.091,-1.211 -2.78,-1.672 -4.264,-1.075l-9.346,3.599c-1.109,-1.228 -2.712,-1.688 -4.281,-1.074c-3.054,1.194 -6.124,2.404 -9.177,3.598c-0.989,0.376 -1.262,1.109 -1.074,2.064l0.597,2.917c-17.227,1.859 -46.342,0.938 -72.421,-19.547c-11.53,-9.039 -22.343,-21.831 -31.366,-39.723l-86.85,44.26c15.879,17.449 35.818,32.919 60.584,42.231c34.453,12.98 78.356,14.208 133.703,-8.084l0.307,1.569c0.273,1.757 2.388,3.616 5.253,2.49l9.193,-3.582c3.156,-1.194 3.173,-3.616 2.712,-5.185l11.837,-4.622c1.331,-0.512 5.458,-3.701 1.91,-8.716l-0.034,0Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(3.06162e-14,500,-500,3.06162e-14,267.59,0)"><stop offset="0" style="stop-color:#bdddeb;stop-opacity:1"/><stop offset="1" style="stop-color:#53a9d1;stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

23
docs/_static/flask-name.svg vendored Normal file
View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 706 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<path id="Name" d="M420.35,117.6l-37.65,-0c-4.4,-0 -7.475,0.85 -9.225,2.55c-1.75,1.7 -2.625,4.65 -2.625,8.85l-0,14.85l39.15,-0l-1.5,18.6l-37.65,-0l-0,43.35l-20.85,-0l-0,-85.05c-0,-7.9 1.725,-13.5 5.175,-16.8c3.45,-3.3 9.375,-4.95 17.775,-4.95l47.4,-0l0,18.6Z" style="fill-rule:nonzero;"/>
<path d="M455.75,205.8l-19.5,0.15l-0,-112.95l19.5,-0l-0,112.8Z" style="fill-rule:nonzero;"/>
<path d="M535.7,205.8l-13.05,-0l-6,-10.35l-20.85,11.25c-11.6,-0 -19.4,-4.2 -23.4,-12.6c-2,-4.1 -3.375,-8.525 -4.125,-13.275c-0.75,-4.75 -1.125,-9.7 -1.125,-14.85c-0,-5.15 0.05,-8.95 0.15,-11.4c0.1,-2.45 0.35,-5.3 0.75,-8.55c0.4,-3.25 0.975,-5.975 1.725,-8.175c0.75,-2.2 1.825,-4.475 3.225,-6.825c1.4,-2.35 3.1,-4.225 5.1,-5.625c4.5,-3.1 10.35,-4.65 17.55,-4.65l20.55,-0l19.5,-1.2l-0,86.25Zm-19.5,-27.3l-0,-40.2l-14.85,-0c-5.5,-0 -9.325,2.1 -11.475,6.3c-2.15,4.2 -3.225,10.475 -3.225,18.825c-0,8.35 1.025,14.225 3.075,17.625c2.05,3.4 5.925,5.1 11.625,5.1l14.85,-7.65Z" style="fill-rule:nonzero;"/>
<path d="M615.65,182.1l0,2.25c-0.6,7.5 -3.775,13.15 -9.525,16.95c-5.75,3.8 -12.925,5.7 -21.525,5.7c-12.7,-0 -21.6,-2.3 -26.7,-6.9c-4.7,-4.2 -7.05,-10.4 -7.05,-18.6l0,-1.8l17.7,0c0,4.6 1.2,7.75 3.6,9.45c2.4,1.7 6.55,2.55 12.45,2.55c8,0 12,-2.9 12,-8.7c0,-4.8 -1.4,-8 -4.2,-9.6c-1.3,-0.8 -2.95,-1.4 -4.95,-1.8l-15.15,-2.55c-13.2,-2.1 -19.8,-10.35 -19.8,-24.75c0,-8 2.925,-14.225 8.775,-18.675c5.85,-4.45 13.275,-6.675 22.275,-6.675c20.5,0 30.75,8.85 30.75,26.55l0,1.95l-16.95,0c-0.2,-4.7 -1.45,-7.9 -3.75,-9.6c-2.3,-1.7 -5.525,-2.55 -9.675,-2.55c-4.15,0 -7.275,0.825 -9.375,2.475c-2.1,1.65 -3.15,3.475 -3.15,5.475c0,5.7 2.3,8.95 6.9,9.75l18.15,3.3c12.8,2.4 19.2,11 19.2,25.8Z" style="fill-rule:nonzero;"/>
<path d="M705.65,205.8l-23.4,-0l-22.5,-30.3l-8.55,12.15l0,18.15l-19.5,-0l0,-112.8l19.5,-0l0,71.25l27.3,-40.65l22.05,-0l-28.05,38.4l33.15,43.8Z" style="fill-rule:nonzero;"/>
<g id="Logo">
<path id="Box" d="M300,30l0,240c0,16.557 -13.443,30 -30,30l-240,-0c-16.557,-0 -30,-13.443 -30,-30l0,-240c0,-16.557 13.443,-30 30,-30l240,0c16.557,0 30,13.443 30,30Z" style="fill:url(#_Linear1);"/>
<path id="Shadow" d="M300,239.188l0,30.812c0,16.557 -13.443,30 -30,30l-56.467,-0l-102.271,-102.271c8.125,7.368 17.707,13.707 28.945,17.933c20.672,7.788 47.014,8.525 80.222,-4.85l0.184,0.941c0.164,1.054 1.433,2.17 3.152,1.494l5.516,-2.149c1.893,-0.716 1.904,-2.169 1.627,-3.111l7.103,-2.773c0.798,-0.307 3.274,-2.221 1.146,-5.23l-0.021,0l-4.37,-6.672c-0.655,-0.727 -1.668,-1.003 -2.558,-0.645l-5.608,2.16c-0.665,-0.737 -1.627,-1.013 -2.569,-0.645c-1.832,0.716 -3.674,1.443 -5.505,2.159c-0.594,0.225 -0.758,0.665 -0.645,1.239l0.358,1.749c-10.336,1.116 -27.805,0.563 -43.452,-11.727c-6.918,-5.424 -13.406,-13.099 -18.82,-23.835l-50.354,25.662l-7.947,-6.453c18.154,-9.251 36.319,-18.502 54.474,-27.754c-1.177,-3.049 -2.323,-6.355 -6.243,-21.143l-58.849,26.336l-7.097,-7.096l64.186,-28.726c-0.921,-8.328 -3.437,-32.242 -3.336,-43.002l-0,-0.01c-0.016,-1.137 -0.111,-1.697 -0.51,-2.103l159.709,159.71Zm-233.137,-111.262c0.763,0.699 2.048,0.814 3.356,0.238l0.45,-0.194c0.387,1.622 0.824,3.325 1.309,5.071l-5.115,-5.115Z" style="fill:#3b808b;"/>
<g id="Icon">
<path d="M140.801,81.591c-0.021,-1.494 -0.174,-1.996 -0.972,-2.456c-0.758,-0.502 -1.904,-0.512 -2.999,-0.031l-73.683,31.551c-1.095,0.481 -2.128,1.443 -2.681,2.486c-0.552,1.044 -0.614,2.149 -0.184,2.937l6.151,11.298l0.081,0.133c0.666,1.055 2.17,1.331 3.705,0.655l0.45,-0.194c1.924,8.064 5.076,18.155 9.282,25.349l64.186,-28.726c-0.921,-8.33 -3.439,-32.257 -3.336,-43.012l-0,0.01Z" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M145.897,134.079l-61.811,27.662c3.633,6.887 8.115,14.194 13.58,21.235c18.154,-9.251 36.319,-18.502 54.474,-27.754c-1.177,-3.049 -2.323,-6.355 -6.243,-21.143Z" style="fill:#fff;fill-rule:nonzero;"/>
<path d="M239.136,199.984l-4.37,-6.672c-0.655,-0.727 -1.668,-1.003 -2.558,-0.645l-5.608,2.16c-0.665,-0.737 -1.627,-1.013 -2.569,-0.645c-1.832,0.716 -3.674,1.443 -5.505,2.159c-0.594,0.225 -0.758,0.665 -0.645,1.239l0.358,1.749c-10.336,1.116 -27.805,0.563 -43.452,-11.727c-6.918,-5.424 -13.406,-13.099 -18.82,-23.835l-52.11,26.557c9.528,10.469 21.491,19.751 36.35,25.338c20.672,7.788 47.014,8.525 80.222,-4.85l0.184,0.941c0.164,1.054 1.433,2.17 3.152,1.494l5.516,-2.149c1.893,-0.716 1.904,-2.169 1.627,-3.111l7.103,-2.773c0.798,-0.307 3.274,-2.221 1.146,-5.23l-0.021,0Z" style="fill:#fff;fill-rule:nonzero;"/>
</g>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.83697e-14,300,-300,1.83697e-14,160.554,0)"><stop offset="0" style="stop-color:#bdddeb;stop-opacity:1"/><stop offset="1" style="stop-color:#53a9d1;stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
docs/_static/no.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

BIN
docs/_static/pycharm-run-config.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/_static/yes.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

View file

@ -1,46 +0,0 @@
Foreword for Experienced Programmers
====================================
Thread-Locals in Flask
----------------------
One of the design decisions in Flask was that simple tasks should be simple;
they should not take a lot of code and yet they should not limit you. Because
of that, Flask has a few design choices that some people might find
surprising or unorthodox. For example, Flask uses thread-local objects
internally so that you dont have to pass objects around from
function to function within a request in order to stay threadsafe.
This approach is convenient, but requires a valid
request context for dependency injection or when attempting to reuse code which
uses a value pegged to the request. The Flask project is honest about
thread-locals, does not hide them, and calls out in the code and documentation
where they are used.
Develop for the Web with Caution
--------------------------------
Always keep security in mind when building web applications.
If you write a web application, you are probably allowing users to register
and leave their data on your server. The users are entrusting you with data.
And even if you are the only user that might leave data in your application,
you still want that data to be stored securely.
Unfortunately, there are many ways the security of a web application can be
compromised. Flask protects you against one of the most common security
problems of modern web applications: cross-site scripting (XSS). Unless you
deliberately mark insecure HTML as secure, Flask and the underlying Jinja2
template engine have you covered. But there are many more ways to cause
security problems.
The documentation will warn you about aspects of web development that require
attention to security. Some of these security concerns are far more complex
than one might think, and we all sometimes underestimate the likelihood that a
vulnerability will be exploited - until a clever attacker figures out a way to
exploit our applications. And don't think that your application is not
important enough to attract an attacker. Depending on the kind of attack,
chances are that automated bots are probing for ways to fill your database with
spam, links to malicious software, and the like.
Flask is no different from any other framework in that you the developer must
build with caution, watching for exploits when building to your requirements.

View file

@ -3,7 +3,7 @@ API
.. module:: flask
This part of the documentation covers all the interfaces of Flask. For
This part of the documentation covers all the interfaces of Flask. For
parts where Flask depends on external libraries, we document the most
important right here and provide links to the canonical documentation.
@ -31,17 +31,15 @@ Incoming Request Data
:inherited-members:
:exclude-members: json_module
.. attribute:: request
.. data:: request
To access incoming request data, you can use the global `request`
object. Flask parses incoming request data for you and gives you
access to it through that global object. Internally Flask makes
sure that you always get the correct data for the active thread if you
are in a multithreaded environment.
A proxy to the request data for the current request, an instance of
:class:`.Request`.
This is a proxy. See :ref:`notes-on-proxies` for more information.
This is only available when a :doc:`request context </appcontext>` is
active.
The request object is an instance of a :class:`~flask.Request`.
This is a proxy. See :ref:`context-visibility` for more information.
Response Objects
@ -62,40 +60,33 @@ does this is by using a signed cookie. The user can look at the session
contents, but can't modify it unless they know the secret key, so make sure to
set that to something complex and unguessable.
To access the current session you can use the :class:`session` object:
To access the current session you can use the :data:`.session` proxy.
.. class:: session
.. data:: session
The session object works pretty much like an ordinary dict, with the
difference that it keeps track of modifications.
A proxy to the session data for the current request, an instance of
:class:`.SessionMixin`.
This is a proxy. See :ref:`notes-on-proxies` for more information.
This is only available when a :doc:`request context </appcontext>` is
active.
The following attributes are interesting:
This is a proxy. See :ref:`context-visibility` for more information.
.. attribute:: new
The session object works like a dict but tracks assignment and access to its
keys. It cannot track modifications to mutable values, you need to set
:attr:`~.SessionMixin.modified` manually when modifying a list, dict, etc.
``True`` if the session is new, ``False`` otherwise.
.. code-block:: python
.. attribute:: modified
``True`` if the session object detected a modification. Be advised
that modifications on mutable structures are not picked up
automatically, in that situation you have to explicitly set the
attribute to ``True`` yourself. Here an example::
# this change is not picked up because a mutable object (here
# a list) is changed.
session['objects'].append(42)
# appending to a list is not detected
session["numbers"].append(42)
# so mark it as modified yourself
session.modified = True
.. attribute:: permanent
If set to ``True`` the session lives for
:attr:`~flask.Flask.permanent_session_lifetime` seconds. The
default is 31 days. If set to ``False`` (which is the default) the
session will be deleted when the user closes the browser.
The session is persisted across requests using a cookie. By default the
users's browser will clear the cookie when it is closed. Set
:attr:`~.SessionMixin.permanent` to ``True`` to persist the cookie for
:data:`PERMANENT_SESSION_LIFETIME`.
Session Interface
@ -125,10 +116,9 @@ implementation that Flask is using.
.. admonition:: Notice
The ``PERMANENT_SESSION_LIFETIME`` config key can also be an integer
starting with Flask 0.8. Either catch this down yourself or use
the :attr:`~flask.Flask.permanent_session_lifetime` attribute on the
app which converts the result to an integer automatically.
The :data:`PERMANENT_SESSION_LIFETIME` config can be an integer or ``timedelta``.
The :attr:`~flask.Flask.permanent_session_lifetime` attribute is always a
``timedelta``.
Test Client
@ -156,23 +146,24 @@ Application Globals
To share data that is valid for one request only from one function to
another, a global variable is not good enough because it would break in
threaded environments. Flask provides you with a special object that
threaded environments. Flask provides you with a special object that
ensures it is only valid for the active request and that will return
different values for each request. In a nutshell: it does the right
thing, like it does for :class:`request` and :class:`session`.
different values for each request. In a nutshell: it does the right
thing, like it does for :data:`.request` and :data:`.session`.
.. data:: g
A namespace object that can store data during an
:doc:`application context </appcontext>`. This is an instance of
:attr:`Flask.app_ctx_globals_class`, which defaults to
:class:`ctx._AppCtxGlobals`.
A proxy to a namespace object used to store data during a single request or
app context. An instance of :attr:`.Flask.app_ctx_globals_class`, which
defaults to :class:`._AppCtxGlobals`.
This is a good place to store resources during a request. For
example, a ``before_request`` function could load a user object from
a session id, then set ``g.user`` to be used in the view function.
This is a good place to store resources during a request. For example, a
:meth:`~.Flask.before_request` function could load a user object from a
session id, then set ``g.user`` to be used in the view function.
This is a proxy. See :ref:`notes-on-proxies` for more information.
This is only available when an :doc:`app context </appcontext>` is active.
This is a proxy. See :ref:`context-visibility` for more information.
.. versionchanged:: 0.10
Bound to the application context instead of the request context.
@ -186,17 +177,16 @@ Useful Functions and Classes
.. data:: current_app
A proxy to the application handling the current request. This is
useful to access the application without needing to import it, or if
it can't be imported, such as when using the application factory
pattern or in blueprints and extensions.
A proxy to the :class:`.Flask` application handling the current request or
other activity.
This is only available when an
:doc:`application context </appcontext>` is pushed. This happens
automatically during requests and CLI commands. It can be controlled
manually with :meth:`~flask.Flask.app_context`.
This is useful to access the application without needing to import it, or if
it can't be imported, such as when using the application factory pattern or
in blueprints and extensions.
This is a proxy. See :ref:`notes-on-proxies` for more information.
This is only available when an :doc:`app context </appcontext>` is active.
This is a proxy. See :ref:`context-visibility` for more information.
.. autofunction:: has_request_context
@ -218,10 +208,6 @@ Useful Functions and Classes
.. autofunction:: send_from_directory
.. autofunction:: escape
.. autoclass:: Markup
:members: escape, unescape, striptags
Message Flashing
----------------
@ -236,27 +222,20 @@ JSON Support
.. module:: flask.json
Flask uses the built-in :mod:`json` module for handling JSON. It will
use the current blueprint's or application's JSON encoder and decoder
for easier customization. By default it handles some extra data types:
Flask uses Python's built-in :mod:`json` module for handling JSON by
default. The JSON implementation can be changed by assigning a different
provider to :attr:`flask.Flask.json_provider_class` or
:attr:`flask.Flask.json`. The functions provided by ``flask.json`` will
use methods on ``app.json`` if an app context is active.
- :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.
Jinja's ``|tojson`` filter is configured to use Flask's :func:`dumps`
function. The filter marks the output with ``|safe`` automatically. Use
the filter to render data inside ``<script>`` tags.
Jinja's ``|tojson`` filter is configured to use the app's JSON provider.
The filter marks the output with ``|safe``. Use it to render data inside
HTML ``<script>`` tags.
.. sourcecode:: html+jinja
<script>
const names = {{ names|tosjon }};
const names = {{ names|tojson }};
renderChart(names, {{ axis_data|tojson }});
</script>
@ -270,11 +249,13 @@ the filter to render data inside ``<script>`` tags.
.. autofunction:: load
.. autoclass:: JSONEncoder
:members:
.. autoclass:: flask.json.provider.JSONProvider
:members:
:member-order: bysource
.. autoclass:: JSONDecoder
:members:
.. autoclass:: flask.json.provider.DefaultJSONProvider
:members:
:member-order: bysource
.. automodule:: flask.json.tag
@ -288,6 +269,10 @@ Template Rendering
.. autofunction:: render_template_string
.. autofunction:: stream_template
.. autofunction:: stream_template_string
.. autofunction:: get_template_attribute
Configuration
@ -305,59 +290,31 @@ Stream Helpers
Useful Internals
----------------
.. autoclass:: flask.ctx.RequestContext
:members:
.. data:: _request_ctx_stack
The internal :class:`~werkzeug.local.LocalStack` that holds
:class:`~flask.ctx.RequestContext` instances. Typically, the
:data:`request` and :data:`session` proxies should be accessed
instead of the stack. It may be useful to access the stack in
extension code.
The following attributes are always present on each layer of the
stack:
`app`
the active Flask application.
`url_adapter`
the URL adapter that was used to match the request.
`request`
the current request object.
`session`
the active session object.
`g`
an object with all the attributes of the :data:`flask.g` object.
`flashes`
an internal cache for the flashed messages.
Example usage::
from flask import _request_ctx_stack
def get_session():
ctx = _request_ctx_stack.top
if ctx is not None:
return ctx.session
.. autoclass:: flask.ctx.AppContext
:members:
.. data:: _app_ctx_stack
.. data:: flask.globals.app_ctx
The internal :class:`~werkzeug.local.LocalStack` that holds
:class:`~flask.ctx.AppContext` instances. Typically, the
:data:`current_app` and :data:`g` proxies should be accessed instead
of the stack. Extensions can access the contexts on the stack as a
namespace to store data.
A proxy to the active :class:`.AppContext`.
.. versionadded:: 0.9
This is an internal object that is essential to how Flask handles requests.
Accessing this should not be needed in most cases. Most likely you want
:data:`.current_app`, :data:`.g`, :data:`.request`, and :data:`.session` instead.
This is only available when a :doc:`request context </appcontext>` is
active.
This is a proxy. See :ref:`context-visibility` for more information.
.. class:: flask.ctx.RequestContext
.. deprecated:: 3.2
Merged with :class:`AppContext`. This alias will be removed in Flask 4.0.
.. data:: flask.globals.request_ctx
.. deprecated:: 3.2
Merged with :data:`.app_ctx`. This alias will be removed in Flask 4.0.
.. autoclass:: flask.blueprints.BlueprintSetupState
:members:
@ -367,18 +324,13 @@ Useful Internals
Signals
-------
.. versionadded:: 0.6
Signals are provided by the `Blinker`_ library. See :doc:`signals` for an introduction.
.. data:: signals.signals_available
``True`` if the signaling system is available. This is the case
when `blinker`_ is installed.
The following signals exist in Flask:
.. _blinker: https://blinker.readthedocs.io/
.. data:: template_rendered
This signal is sent when a template was successfully rendered. The
This signal is sent when a template was successfully rendered. The
signal is invoked with the instance of the template as `template`
and the context as dictionary (named `context`).
@ -412,7 +364,7 @@ The following signals exist in Flask:
.. data:: request_started
This signal is sent when the request context is set up, before
any request processing happens. Because the request context is already
any request processing happens. Because the request context is already
bound, the subscriber can access the request with the standard global
proxies such as :class:`~flask.request`.
@ -432,7 +384,7 @@ The following signals exist in Flask:
Example subscriber::
def log_response(sender, response, **extra):
sender.logger.debug('Request context is about to close down. '
sender.logger.debug('Request context is about to close down. '
'Response: %s', response)
from flask import request_finished
@ -469,8 +421,8 @@ The following signals exist in Flask:
.. data:: request_tearing_down
This signal is sent when the request is tearing down. This is always
called, even if an exception is caused. Currently functions listening
This signal is sent when the request is tearing down. This is always
called, even if an exception is caused. Currently functions listening
to this signal are called after the regular teardown handlers, but this
is not something you can rely on.
@ -488,8 +440,8 @@ The following signals exist in Flask:
.. data:: appcontext_tearing_down
This signal is sent when the app context is tearing down. This is always
called, even if an exception is caused. Currently functions listening
This signal is sent when the app context is tearing down. This is always
called, even if an exception is caused. Currently functions listening
to this signal are called after the regular teardown handlers, but this
is not something you can rely on.
@ -506,9 +458,9 @@ The following signals exist in Flask:
.. data:: appcontext_pushed
This signal is sent when an application context is pushed. The sender
is the application. This is usually useful for unittests in order to
temporarily hook in information. For instance it can be used to
This signal is sent when an application context is pushed. The sender
is the application. This is usually useful for unittests in order to
temporarily hook in information. For instance it can be used to
set a resource early onto the `g` object.
Example usage::
@ -535,16 +487,15 @@ The following signals exist in Flask:
.. data:: appcontext_popped
This signal is sent when an application context is popped. The sender
is the application. This usually falls in line with the
This signal is sent when an application context is popped. The sender
is the application. This usually falls in line with the
:data:`appcontext_tearing_down` signal.
.. versionadded:: 0.10
.. data:: message_flashed
This signal is sent when the application is flashing a message. The
This signal is sent when the application is flashing a message. The
messages is sent as `message` keyword argument and the category as
`category`.
@ -559,23 +510,6 @@ The following signals exist in Flask:
.. versionadded:: 0.10
.. class:: signals.Namespace
An alias for :class:`blinker.base.Namespace` if blinker is available,
otherwise a dummy class that creates fake signals. This class is
available for Flask extensions that want to provide the same fallback
system as Flask itself.
.. method:: signal(name, doc=None)
Creates a new signal for this namespace if blinker is available,
otherwise returns a fake signal that has a send method that will
do nothing but will fail with a :exc:`RuntimeError` for all other
operations, including connecting.
.. _blinker: https://pypi.org/project/blinker/
Class-Based Views
-----------------
@ -603,7 +537,7 @@ Generally there are three ways to define rules for the routing system:
which is exposed as :attr:`flask.Flask.url_map`.
Variable parts in the route can be specified with angular brackets
(``/user/<username>``). By default a variable part in the URL accepts any
(``/user/<username>``). By default a variable part in the URL accepts any
string without a slash however a different converter can be specified as
well by using ``<converter:name>``.
@ -637,7 +571,7 @@ Here are some examples::
pass
An important detail to keep in mind is how Flask deals with trailing
slashes. The idea is to keep each URL unique so the following rules
slashes. The idea is to keep each URL unique so the following rules
apply:
1. If a rule ends with a slash and is requested without a slash by the
@ -646,11 +580,11 @@ apply:
2. If a rule does not end with a trailing slash and the user requests the
page with a trailing slash, a 404 not found is raised.
This is consistent with how web servers deal with static files. This
This is consistent with how web servers deal with static files. This
also makes it possible to use relative link targets safely.
You can also define multiple rules for the same function. They have to be
unique however. Defaults can also be specified. Here for example is a
You can also define multiple rules for the same function. They have to be
unique however. Defaults can also be specified. Here for example is a
definition for a URL that accepts an optional page::
@app.route('/users/', defaults={'page': 1})
@ -662,7 +596,7 @@ This specifies that ``/users/`` will be the URL for page one and
``/users/page/N`` will be the URL for page ``N``.
If a URL contains a default value, it will be redirected to its simpler
form with a 301 redirect. In the above example, ``/users/page/1`` will
form with a 308 redirect. In the above example, ``/users/page/1`` will
be redirected to ``/users/``. If your route handles ``GET`` and ``POST``
requests, make sure the default route only handles ``GET``, as redirects
can't preserve form data. ::
@ -673,33 +607,33 @@ can't preserve form data. ::
pass
Here are the parameters that :meth:`~flask.Flask.route` and
:meth:`~flask.Flask.add_url_rule` accept. The only difference is that
:meth:`~flask.Flask.add_url_rule` accept. The only difference is that
with the route parameter the view function is defined with the decorator
instead of the `view_func` parameter.
=============== ==========================================================
`rule` the URL rule as string
`endpoint` the endpoint for the registered URL rule. Flask itself
`endpoint` the endpoint for the registered URL rule. Flask itself
assumes that the name of the view function is the name
of the endpoint if not explicitly stated.
`view_func` the function to call when serving a request to the
provided endpoint. If this is not provided one can
provided endpoint. If this is not provided one can
specify the function later by storing it in the
:attr:`~flask.Flask.view_functions` dictionary with the
endpoint as key.
`defaults` A dictionary with defaults for this rule. See the
`defaults` A dictionary with defaults for this rule. See the
example above for how defaults work.
`subdomain` specifies the rule for the subdomain in case subdomain
matching is in use. If not specified the default
matching is in use. If not specified the default
subdomain is assumed.
`**options` the options to be forwarded to the underlying
:class:`~werkzeug.routing.Rule` object. A change to
Werkzeug is handling of method options. methods is a list
:class:`~werkzeug.routing.Rule` object. A change to
Werkzeug is handling of method options. methods is a list
of methods this rule should be limited to (``GET``, ``POST``
etc.). By default a rule just listens for ``GET`` (and
implicitly ``HEAD``). Starting with Flask 0.6, ``OPTIONS`` is
etc.). By default a rule just listens for ``GET`` (and
implicitly ``HEAD``). Starting with Flask 0.6, ``OPTIONS`` is
implicitly added and handled by the standard request
handling. They have to be specified as keyword arguments.
handling. They have to be specified as keyword arguments.
=============== ==========================================================
@ -711,19 +645,19 @@ customize behavior the view function would normally not have control over.
The following attributes can be provided optionally to either override
some defaults to :meth:`~flask.Flask.add_url_rule` or general behavior:
- `__name__`: The name of a function is by default used as endpoint. If
endpoint is provided explicitly this value is used. Additionally this
- `__name__`: The name of a function is by default used as endpoint. If
endpoint is provided explicitly this value is used. Additionally this
will be prefixed with the name of the blueprint by default which
cannot be customized from the function itself.
- `methods`: If methods are not provided when the URL rule is added,
Flask will look on the view function object itself if a `methods`
attribute exists. If it does, it will pull the information for the
attribute exists. If it does, it will pull the information for the
methods from there.
- `provide_automatic_options`: if this attribute is set Flask will
either force enable or disable the automatic implementation of the
HTTP ``OPTIONS`` response. This can be useful when working with
HTTP ``OPTIONS`` response. This can be useful when working with
decorators that want to customize the ``OPTIONS`` response on a per-view
basis.

View file

@ -1,74 +1,63 @@
.. currentmodule:: flask
The App and Request Context
===========================
The Application Context
=======================
The context keeps track of data and objects during a request, CLI command, or
other activity. Rather than passing this data around to every function, the
:data:`.current_app`, :data:`.g`, :data:`.request`, and :data:`.session` proxies
are accessed instead.
The application context keeps track of the application-level data during
a request, CLI command, or other activity. Rather than passing the
application around to each function, the :data:`current_app` and
:data:`g` proxies are accessed instead.
When handling a request, the context is referred to as the "request context"
because it contains request data in addition to application data. Otherwise,
such as during a CLI command, it is referred to as the "app context". During an
app context, :data:`.current_app` and :data:`.g` are available, while during a
request context :data:`.request` and :data:`.session` are also available.
This is similar to :doc:`/reqcontext`, which keeps track of
request-level data during a request. A corresponding application context
is pushed when a request context is pushed.
Purpose of the Context
----------------------
The :class:`Flask` application object has attributes, such as
:attr:`~Flask.config`, that are useful to access within views and
:doc:`CLI commands </cli>`. However, importing the ``app`` instance
within the modules in your project is prone to circular import issues.
When using the :doc:`app factory pattern </patterns/appfactories>` or
writing reusable :doc:`blueprints </blueprints>` or
:doc:`extensions </extensions>` there won't be an ``app`` instance to
import at all.
The context and proxies help solve two development issues: circular imports, and
passing around global data during a request.
Flask solves this issue with the *application context*. Rather than
referring to an ``app`` directly, you use the :data:`current_app`
proxy, which points to the application handling the current activity.
The :class:`.Flask` application object has attributes, such as
:attr:`~.Flask.config`, that are useful to access within views and other
functions. However, importing the ``app`` instance within the modules in your
project is prone to circular import issues. When using the
:doc:`app factory pattern </patterns/appfactories>` or writing reusable
:doc:`blueprints </blueprints>` or :doc:`extensions </extensions>` there won't
be an ``app`` instance to import at all.
Flask automatically *pushes* an application context when handling a
request. View functions, error handlers, and other functions that run
during a request will have access to :data:`current_app`.
When the application handles a request, it creates a :class:`.Request` object.
Because a *worker* handles only one request at a time, the request data can be
considered global to that worker during that request. Passing it as an argument
through every function during the request becomes verbose and redundant.
Flask will also automatically push an app context when running CLI
commands registered with :attr:`Flask.cli` using ``@app.cli.command()``.
Flask solves these issues with the *active context* pattern. Rather than
importing an ``app`` directly, or having to pass it and the request through to
every single function, you import and access the proxies, which point to the
currently active application and request data. This is sometimes referred to
as "context local" data.
Lifetime of the Context
-----------------------
Context During Setup
--------------------
The application context is created and destroyed as necessary. When a
Flask application begins handling a request, it pushes an application
context and a :doc:`request context </reqcontext>`. When the request
ends it pops the request context then the application context.
Typically, an application context will have the same lifetime as a
request.
See :doc:`/reqcontext` for more information about how the contexts work
and the full life cycle of a request.
Manually Push a Context
-----------------------
If you try to access :data:`current_app`, or anything that uses it,
outside an application context, you'll get this error message:
If you try to access :data:`.current_app`, :data:`.g`, or anything that uses it,
outside an app context, you'll get this error message:
.. code-block:: pytb
RuntimeError: Working outside of application context.
This typically means that you attempted to use functionality that
needed to interface with the current application object in some way.
To solve this, set up an application context with app.app_context().
Attempted to use functionality that expected a current application to be
set. To solve this, set up an app context using 'with app.app_context()'.
See the documentation on app context for more information.
If you see that error while configuring your application, such as when
initializing an extension, you can push a context manually since you
have direct access to the ``app``. Use :meth:`~Flask.app_context` in a
``with`` block, and everything that runs in the block will have access
to :data:`current_app`. ::
initializing an extension, you can push a context manually since you have direct
access to the ``app``. Use :meth:`.Flask.app_context` in a ``with`` block.
.. code-block:: python
def create_app():
app = Flask(__name__)
@ -78,80 +67,121 @@ to :data:`current_app`. ::
return app
If you see that error somewhere else in your code not related to
configuring the application, it most likely indicates that you should
move that code into a view function or CLI command.
If you see that error somewhere else in your code not related to setting up the
application, it most likely indicates that you should move that code into a view
function or CLI command.
Storing Data
------------
Context During Testing
----------------------
The application context is a good place to store common data during a
request or CLI command. Flask provides the :data:`g object <g>` for this
purpose. It is a simple namespace object that has the same lifetime as
an application context.
See :doc:`/testing` for detailed information about managing the context during
tests.
.. note::
The ``g`` name stands for "global", but that is referring to the
data being global *within a context*. The data on ``g`` is lost
after the context ends, and it is not an appropriate place to store
data between requests. Use the :data:`session` or a database to
store data across requests.
If you try to access :data:`.request`, :data:`.session`, or anything that uses
it, outside a request context, you'll get this error message:
A common use for :data:`g` is to manage resources during a request.
.. code-block:: pytb
1. ``get_X()`` creates resource ``X`` if it does not exist, caching it
as ``g.X``.
2. ``teardown_X()`` closes or otherwise deallocates the resource if it
exists. It is registered as a :meth:`~Flask.teardown_appcontext`
handler.
RuntimeError: Working outside of request context.
For example, you can manage a database connection using this pattern::
Attempted to use functionality that expected an active HTTP request. See the
documentation on request context for more information.
from flask import g
This will probably only happen during tests. If you see that error somewhere
else in your code not related to testing, it most likely indicates that you
should move that code into a view function.
def get_db():
if 'db' not in g:
g.db = connect_to_database()
The primary way to solve this is to use :meth:`.Flask.test_client` to simulate
a full request.
return g.db
If you only want to unit test one function, rather than a full request, use
:meth:`.Flask.test_request_context` in a ``with`` block.
@app.teardown_appcontext
def teardown_db(exception):
db = g.pop('db', None)
.. code-block:: python
if db is not None:
db.close()
def generate_report(year):
format = request.args.get("format")
...
During a request, every call to ``get_db()`` will return the same
connection, and it will be closed automatically at the end of the
request.
You can use :class:`~werkzeug.local.LocalProxy` to make a new context
local from ``get_db()``::
from werkzeug.local import LocalProxy
db = LocalProxy(get_db)
Accessing ``db`` will call ``get_db`` internally, in the same way that
:data:`current_app` works.
----
If you're writing an extension, :data:`g` should be reserved for user
code. You may store internal data on the context itself, but be sure to
use a sufficiently unique name. The current context is accessed with
:data:`_app_ctx_stack.top <_app_ctx_stack>`. For more information see
:doc:`/extensiondev`.
with app.test_request_context(
"/make_report/2017", query_string={"format": "short"}
):
generate_report()
Events and Signals
------------------
.. _context-visibility:
The application will call functions registered with
:meth:`~Flask.teardown_appcontext` when the application context is
popped.
Visibility of the Context
-------------------------
If :data:`~signals.signals_available` is true, the following signals are
sent: :data:`appcontext_pushed`, :data:`appcontext_tearing_down`, and
:data:`appcontext_popped`.
The context will have the same lifetime as an activity, such as a request, CLI
command, or ``with`` block. Various callbacks and signals registered with the
app will be run during the context.
When a Flask application handles a request, it pushes a request context
to set the active application and request data. When it handles a CLI command,
it pushes an app context to set the active application. When the activity ends,
it pops that context. Proxy objects like :data:`.request`, :data:`.session`,
:data:`.g`, and :data:`.current_app`, are accessible while the context is pushed
and active, and are not accessible after the context is popped.
The context is unique to each thread (or other worker type). The proxies cannot
be passed to another worker, which has a different context space and will not
know about the active context in the parent's space.
Besides being scoped to each worker, the proxy object has a separate type and
identity than the proxied real object. In some cases you'll need access to the
real object, rather than the proxy. Use the
:meth:`~.LocalProxy._get_current_object` method in those cases.
.. code-block:: python
app = current_app._get_current_object()
my_signal.send(app)
Lifecycle of the Context
------------------------
Flask dispatches a request in multiple stages which can affect the request,
response, and how errors are handled. See :doc:`/lifecycle` for a list of all
the steps, callbacks, and signals during each request. The following are the
steps directly related to the context.
- The app context is pushed, the proxies are available.
- The :data:`.appcontext_pushed` signal is sent.
- The request is dispatched.
- Any :meth:`.Flask.teardown_request` decorated functions are called.
- The :data:`.request_tearing_down` signal is sent.
- Any :meth:`.Flask.teardown_appcontext` decorated functions are called.
- The :data:`.appcontext_tearing_down` signal is sent.
- The app context is popped, the proxies are no longer available.
- The :data:`.appcontext_popped` signal is sent.
The teardown callbacks are called by the context when it is popped. They are
called even if there is an unhandled exception during dispatch. They may be
called multiple times in some test scenarios. This means there is no guarantee
that any other parts of the request dispatch have run. Be sure to write these
functions in a way that does not depend on other callbacks. All callbacks are
called even if any raise an error.
How the Context Works
---------------------
Context locals are implemented using Python's :mod:`contextvars` and Werkzeug's
:class:`~werkzeug.local.LocalProxy`. Python's contextvars are a low level
structure to manage data local to a thread or coroutine. ``LocalProxy`` wraps
the contextvar so that access to any attributes and methods is forwarded to the
object stored in the contextvar.
The context is tracked like a stack, with the active context at the top of the
stack. Flask manages pushing and popping contexts during requests, CLI commands,
testing, ``with`` blocks, etc. The proxies access attributes on the active
context.
Because it is a stack, other contexts may be pushed to change the proxies during
an already active context. This is not a common pattern, but can be used in
advanced use cases. For example, a Flask application can be used as WSGI
middleware, calling another wrapped Flask app from a view.

View file

@ -23,18 +23,6 @@ method in views that inherit from the :class:`flask.views.View` class, as
well as all the HTTP method handlers in views that inherit from the
:class:`flask.views.MethodView` class.
.. admonition:: Using ``async`` on Windows on Python 3.8
Python 3.8 has a bug related to asyncio on Windows. If you encounter
something like ``ValueError: set_wakeup_fd only works in main thread``,
please upgrade to Python 3.9.
.. admonition:: Using ``async`` with greenlet
When using gevent or eventlet to serve an application or patch the
runtime, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
required.
Performance
-----------
@ -84,15 +72,15 @@ Flask based on the `ASGI`_ standard instead of WSGI. This allows it to
handle many concurrent requests, long running requests, and websockets
without requiring multiple worker processes or threads.
It has also already been possible to run Flask with Gevent or Eventlet
to get many of the benefits of async request handling. These libraries
patch low-level Python functions to accomplish this, whereas ``async``/
``await`` and ASGI use standard, modern Python capabilities. Deciding
whether you should use Flask, Quart, or something else is ultimately up
to understanding the specific needs of your project.
It has also already been possible to :doc:`run Flask with Gevent </gevent>` to
get many of the benefits of async request handling. Gevent patches low-level
Python functions to accomplish this, whereas ``async``/``await`` and ASGI use
standard, modern Python capabilities. Deciding whether you should use gevent
with Flask, or Quart, or something else is ultimately up to understanding the
specific needs of your project.
.. _Quart: https://github.com/pallets/quart
.. _ASGI: https://asgi.readthedocs.io/en/latest/
.. _Quart: https://quart.palletsprojects.com
.. _ASGI: https://asgi.readthedocs.io
Extensions
@ -126,6 +114,6 @@ implemented async support, or make a feature request or PR to them.
Other event loops
-----------------
At the moment Flask only supports :mod:`asyncio`. It's possible to
override :meth:`flask.Flask.ensure_sync` to change how async functions
are wrapped to use a different library.
At the moment Flask only supports :mod:`asyncio`. It's possible to override
:meth:`flask.Flask.ensure_sync` to change how async functions are wrapped to use
a different library. See :ref:`gevent-asyncio` for an example.

View file

@ -140,6 +140,19 @@ name, and child URLs will be prefixed with the parent's URL prefix.
url_for('parent.child.create')
/parent/child/create
In addition a child blueprint's will gain their parent's subdomain,
with their subdomain as prefix if present i.e.
.. code-block:: python
parent = Blueprint('parent', __name__, subdomain='parent')
child = Blueprint('child', __name__, subdomain='child')
parent.register_blueprint(child)
app.register_blueprint(parent)
url_for('parent.child.create', _external=True)
"child.parent.domain.tld"
Blueprint-specific before request functions, etc. registered with the
parent will trigger for the child. If a child does not have an error
handler that can handle a given exception, the parent's will be tried.

View file

@ -15,40 +15,10 @@ Application Discovery
---------------------
The ``flask`` command is installed by Flask, not your application; it must be
told where to find your application in order to use it. The ``FLASK_APP``
environment variable is used to specify how to load the application.
told where to find your application in order to use it. The ``--app``
option is used to specify how to load the application.
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=hello
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP hello
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=hello
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "hello"
> flask run
While ``FLASK_APP`` supports a variety of options for specifying your
While ``--app`` supports a variety of options for specifying your
application, most use cases should be simple. Here are the typical values:
(nothing)
@ -56,32 +26,32 @@ application, most use cases should be simple. Here are the typical values:
automatically detecting an app (``app`` or ``application``) or
factory (``create_app`` or ``make_app``).
``FLASK_APP=hello``
``--app hello``
The given name is imported, automatically detecting an app (``app``
or ``application``) or factory (``create_app`` or ``make_app``).
----
``FLASK_APP`` has three parts: an optional path that sets the current working
``--app`` has three parts: an optional path that sets the current working
directory, a Python file or dotted import path, and an optional variable
name of the instance or factory. If the name is a factory, it can optionally
be followed by arguments in parentheses. The following values demonstrate these
parts:
``FLASK_APP=src/hello``
``--app src/hello``
Sets the current working directory to ``src`` then imports ``hello``.
``FLASK_APP=hello.web``
``--app hello.web``
Imports the path ``hello.web``.
``FLASK_APP=hello:app2``
``--app hello:app2``
Uses the ``app2`` Flask instance in ``hello``.
``FLASK_APP="hello:create_app('dev')"``
``--app 'hello:create_app("dev")'``
The ``create_app`` factory in ``hello`` is called with the string ``'dev'``
as the argument.
If ``FLASK_APP`` is not set, the command will try to import "app" or
If ``--app`` is not set, the command will try to import "app" or
"wsgi" (as a ".py" file, or package) and try to detect an application
instance or factory.
@ -101,7 +71,7 @@ Run the Development Server
The :func:`run <cli.run_command>` command will start the development server. It
replaces the :meth:`Flask.run` method in most cases. ::
$ flask run
$ flask --app hello run
* Serving Flask app "hello"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
@ -116,6 +86,50 @@ server tries to start. See :ref:`address-already-in-use` for how to
handle that.
Debug Mode
~~~~~~~~~~
In debug mode, the ``flask run`` command will enable the interactive debugger and the
reloader by default, and make errors easier to see and debug. To enable debug mode, use
the ``--debug`` option.
.. code-block:: console
$ flask --app hello run --debug
* Serving Flask app "hello"
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When using debug mode, the reloader will trigger whenever your Python code or imported
modules change. The reloader can watch additional files with the ``--extra-files``
option. Multiple paths are separated with ``:``, or ``;`` on Windows.
.. code-block:: text
$ flask run --extra-files file1:dirA/file2:dirB/
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
The reloader can also ignore files using :mod:`fnmatch` patterns with the
``--exclude-patterns`` option. Multiple patterns are separated with ``:``, or ``;`` on
Windows.
Open a Shell
------------
@ -132,166 +146,26 @@ context will be active, and the app instance will be imported. ::
Use :meth:`~Flask.shell_context_processor` to add other automatic imports.
Environments
------------
.. versionadded:: 1.0
The environment in which the Flask app runs is set by the
:envvar:`FLASK_ENV` environment variable. If not set it defaults to
``production``. The other recognized environment is ``development``.
Flask and extensions may choose to enable behaviors based on the
environment.
If the env is set to ``development``, the ``flask`` command will enable
debug mode and ``flask run`` will enable the interactive debugger and
reloader.
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
$ flask run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run
* Serving Flask app "hello"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with inotify reloader
* Debugger is active!
* Debugger PIN: 223-456-919
Watch Extra Files with the Reloader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When using development mode, the reloader will trigger whenever your
Python code or imported modules change. The reloader can watch
additional files with the ``--extra-files`` option, or the
``FLASK_RUN_EXTRA_FILES`` environment variable. Multiple paths are
separated with ``:``, or ``;`` on Windows.
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ flask run --extra-files file1:dirA/file2:dirB/
# or
$ export FLASK_RUN_EXTRA_FILES=file1:dirA/file2:dirB/
$ flask run
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
.. group-tab:: Fish
.. code-block:: text
$ flask run --extra-files file1:dirA/file2:dirB/
# or
$ set -x FLASK_RUN_EXTRA_FILES file1 dirA/file2 dirB/
$ flask run
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
.. group-tab:: CMD
.. code-block:: text
> flask run --extra-files file1:dirA/file2:dirB/
# or
> set FLASK_RUN_EXTRA_FILES=file1:dirA/file2:dirB/
> flask run
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
.. group-tab:: Powershell
.. code-block:: text
> flask run --extra-files file1:dirA/file2:dirB/
# or
> $env:FLASK_RUN_EXTRA_FILES = "file1:dirA/file2:dirB/"
> flask run
* Running on http://127.0.0.1:8000/
* Detected change in '/path/to/file1', reloading
Ignore files with the Reloader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The reloader can also ignore files using :mod:`fnmatch` patterns with
the ``--exclude-patterns`` option, or the ``FLASK_RUN_EXCLUDE_PATTERNS``
environment variable. Multiple patterns are separated with ``:``, or
``;`` on Windows.
Debug Mode
----------
Debug mode will be enabled when :envvar:`FLASK_ENV` is ``development``,
as described above. If you want to control debug mode separately, use
:envvar:`FLASK_DEBUG`. The value ``1`` enables it, ``0`` disables it.
.. _dotenv:
Environment Variables From dotenv
---------------------------------
Rather than setting ``FLASK_APP`` each time you open a new terminal, you can
use Flask's dotenv support to set environment variables automatically.
The ``flask`` command supports setting any option for any command with
environment variables. The variables are named like ``FLASK_OPTION`` or
``FLASK_COMMAND_OPTION``, for example ``FLASK_APP`` or
``FLASK_RUN_PORT``.
Rather than passing options every time you run a command, or environment
variables every time you open a new terminal, you can use Flask's dotenv
support to set environment variables automatically.
If `python-dotenv`_ is installed, running the ``flask`` command will set
environment variables defined in the files :file:`.env` and :file:`.flaskenv`.
This can be used to avoid having to set ``FLASK_APP`` manually every time you
open a new terminal, and to set configuration using environment variables
similar to how some deployment services work.
environment variables defined in the files ``.env`` and ``.flaskenv``.
You can also specify an extra file to load with the ``--env-file``
option. Dotenv files can be used to avoid having to set ``--app`` or
``FLASK_APP`` manually, and to set configuration using environment
variables similar to how some deployment services work.
Variables set on the command line are used over those set in :file:`.env`,
which are used over those set in :file:`.flaskenv`. :file:`.flaskenv` should be
@ -414,25 +288,25 @@ script. Activating the virtualenv will set the variables.
.. group-tab:: Bash
Unix Bash, :file:`venv/bin/activate`::
Unix Bash, :file:`.venv/bin/activate`::
$ export FLASK_APP=hello
.. group-tab:: Fish
Fish, :file:`venv/bin/activate.fish`::
Fish, :file:`.venv/bin/activate.fish`::
$ set -x FLASK_APP hello
.. group-tab:: CMD
Windows CMD, :file:`venv\\Scripts\\activate.bat`::
Windows CMD, :file:`.venv\\Scripts\\activate.bat`::
> set FLASK_APP=hello
.. group-tab:: Powershell
Windows Powershell, :file:`venv\\Scripts\\activate.ps1`::
Windows Powershell, :file:`.venv\\Scripts\\activate.ps1`::
> $env:FLASK_APP = "hello"
@ -547,12 +421,14 @@ commands directly to the application's level:
Application Context
~~~~~~~~~~~~~~~~~~~
Commands added using the Flask app's :attr:`~Flask.cli`
:meth:`~cli.AppGroup.command` decorator will be executed with an application
context pushed, so your command and extensions have access to the app and its
configuration. If you create a command using the Click :func:`~click.command`
decorator instead of the Flask decorator, you can use
:func:`~cli.with_appcontext` to get the same behavior. ::
Commands added using the Flask app's :attr:`~Flask.cli` or
:class:`~flask.cli.FlaskGroup` :meth:`~cli.AppGroup.command` decorator
will be executed with an application context pushed, so your custom
commands and parameters have access to the app and its configuration. The
:func:`~cli.with_appcontext` decorator can be used to get the same
behavior, but is not needed in most cases.
.. code-block:: python
import click
from flask.cli import with_appcontext
@ -564,36 +440,22 @@ decorator instead of the Flask decorator, you can use
app.cli.add_command(do_work)
If you're sure a command doesn't need the context, you can disable it::
@app.cli.command(with_appcontext=False)
def do_work():
...
Plugins
-------
Flask will automatically load commands specified in the ``flask.commands``
`entry point`_. This is useful for extensions that want to add commands when
they are installed. Entry points are specified in :file:`setup.py` ::
they are installed. Entry points are specified in :file:`pyproject.toml`:
from setuptools import setup
setup(
name='flask-my-extension',
...,
entry_points={
'flask.commands': [
'my-command=flask_my_extension.commands:cli'
],
},
)
.. code-block:: toml
[project.entry-points."flask.commands"]
my-command = "my_extension.commands:cli"
.. _entry point: https://packaging.python.org/tutorials/packaging-projects/#entry-points
Inside :file:`flask_my_extension/commands.py` you can then export a Click
Inside :file:`my_extension/commands.py` you can then export a Click
object::
import click
@ -612,7 +474,7 @@ Custom Scripts
--------------
When you are using the app factory pattern, it may be more convenient to define
your own Click script. Instead of using ``FLASK_APP`` and letting Flask load
your own Click script. Instead of using ``--app`` and letting Flask load
your application, you can create your own Click object and export it as a
`console script`_ entry point.
@ -631,22 +493,15 @@ Create an instance of :class:`~cli.FlaskGroup` and pass it the factory::
def cli():
"""Management script for the Wiki application."""
Define the entry point in :file:`setup.py`::
Define the entry point in :file:`pyproject.toml`:
from setuptools import setup
.. code-block:: toml
setup(
name='flask-my-extension',
...,
entry_points={
'console_scripts': [
'wiki=wiki:cli'
],
},
)
[project.scripts]
wiki = "wiki:cli"
Install the application in the virtualenv in editable mode and the custom
script is available. Note that you don't need to set ``FLASK_APP``. ::
script is available. Note that you don't need to set ``--app``. ::
$ pip install -e .
$ wiki run
@ -666,53 +521,36 @@ script is available. Note that you don't need to set ``FLASK_APP``. ::
PyCharm Integration
-------------------
PyCharm Professional provides a special Flask run configuration. For
the Community Edition, we need to configure it to call the ``flask run``
CLI command with the correct environment variables. These instructions
should be similar for any other IDE you might want to use.
PyCharm Professional provides a special Flask run configuration to run the development
server. For the Community Edition, and for other commands besides ``run``, you need to
create a custom run configuration. These instructions should be similar for any other
IDE you use.
In PyCharm, with your project open, click on *Run* from the menu bar and
go to *Edit Configurations*. You'll be greeted by a screen similar to
this:
In PyCharm, with your project open, click on *Run* from the menu bar and go to *Edit
Configurations*. You'll see a screen similar to this:
.. image:: _static/pycharm-runconfig.png
.. image:: _static/pycharm-run-config.png
:align: center
:class: screenshot
:alt: Screenshot of PyCharms's run configuration settings.
:alt: Screenshot of PyCharm run configuration.
There's quite a few options to change, but once we've done it for one
command, we can easily copy the entire configuration and make a single
tweak to give us access to other commands, including any custom ones you
may implement yourself.
Once you create a configuration for the ``flask run``, you can copy and change it to
call any other command.
Click the + (*Add New Configuration*) button and select *Python*. Give
the configuration a name such as "flask run". For the ``flask run``
command, check "Single instance only" since you can't run the server
more than once at the same time.
Click the *+ (Add New Configuration)* button and select *Python*. Give the configuration
a name such as "flask run".
Select *Module name* from the dropdown (**A**) then input ``flask``.
Click the *Script path* dropdown and change it to *Module name*, then input ``flask``.
The *Parameters* field (**B**) is set to the CLI command to execute
(with any arguments). In this example we use ``run``, which will run
the development server.
The *Parameters* field is set to the CLI command to execute along with any arguments.
This example uses ``--app hello run --debug``, which will run the development server in
debug mode. ``--app hello`` should be the import or file with your Flask app.
You can skip this next step if you're using :ref:`dotenv`. We need to
add an environment variable (**C**) to identify our application. Click
on the browse button and add an entry with ``FLASK_APP`` on the left and
the Python import or file on the right (``hello`` for example). Add an
entry with ``FLASK_ENV`` and set it to ``development``.
If you installed your project as a package in your virtualenv, you may uncheck the
*PYTHONPATH* options. This will more accurately match how you deploy later.
Next we need to set the working directory (**D**) to be the folder where
our application resides.
Click *OK* to save and close the configuration. Select the configuration in the main
PyCharm window and click the play button next to it to run the server.
If you have installed your project as a package in your virtualenv, you
may untick the *PYTHONPATH* options (**E**). This will more accurately
match how you deploy the app later.
Click *Apply* to save the configuration, or *OK* to save and close the
window. Select the configuration in the main PyCharm window and click
the play button next to it to run the server.
Now that we have a configuration which runs ``flask run`` from within
PyCharm, we can copy that configuration and alter the *Script* argument
to run a different CLI command, e.g. ``flask shell``.
Now that you have a configuration for ``flask run``, you can copy that configuration and
change the *Parameters* argument to run a different CLI command.

View file

@ -11,16 +11,23 @@ release, version = get_version("Flask")
# General --------------------------------------------------------------
master_doc = "index"
default_role = "code"
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinxcontrib.log_cabinet",
"pallets_sphinx_themes",
"sphinx_issues",
"sphinx_tabs.tabs",
"pallets_sphinx_themes",
]
autodoc_member_order = "bysource"
autodoc_typehints = "description"
autodoc_preserve_defaults = True
extlinks = {
"issue": ("https://github.com/pallets/flask/issues/%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 = {
"python": ("https://docs.python.org/3/", None),
"werkzeug": ("https://werkzeug.palletsprojects.com/", None),
@ -29,9 +36,8 @@ intersphinx_mapping = {
"itsdangerous": ("https://itsdangerous.palletsprojects.com/", None),
"sqlalchemy": ("https://docs.sqlalchemy.org/", None),
"wtforms": ("https://wtforms.readthedocs.io/", None),
"blinker": ("https://pythonhosted.org/blinker/", None),
"blinker": ("https://blinker.readthedocs.io/", None),
}
issues_github_path = "pallets/flask"
# HTML -----------------------------------------------------------------
@ -43,8 +49,6 @@ html_context = {
ProjectLink("PyPI Releases", "https://pypi.org/project/Flask/"),
ProjectLink("Source Code", "https://github.com/pallets/flask/"),
ProjectLink("Issue Tracker", "https://github.com/pallets/flask/issues/"),
ProjectLink("Website", "https://palletsprojects.com/p/flask/"),
ProjectLink("Twitter", "https://twitter.com/PalletsTeam"),
ProjectLink("Chat", "https://discord.gg/pallets"),
]
}
@ -54,14 +58,13 @@ html_sidebars = {
}
singlehtml_sidebars = {"index": ["project.html", "localtoc.html", "ethicalads.html"]}
html_static_path = ["_static"]
html_favicon = "_static/flask-icon.png"
html_logo = "_static/flask-icon.png"
html_favicon = "_static/flask-icon.svg"
html_logo = "_static/flask-logo.svg"
html_title = f"Flask Documentation ({version})"
html_show_sourcelink = False
# LaTeX ----------------------------------------------------------------
latex_documents = [(master_doc, f"Flask-{version}.tex", html_title, author, "manual")]
gettext_uuid = True
gettext_compact = False
# Local Extensions -----------------------------------------------------

View file

@ -42,66 +42,22 @@ method::
)
Environment and Debug Features
------------------------------
Debug Mode
----------
The :data:`ENV` and :data:`DEBUG` config values are special because they
may behave inconsistently if changed after the app has begun setting up.
In order to set the environment and debug mode reliably, Flask uses
environment variables.
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
``--debug`` option on the ``flask`` or ``flask run`` command. ``flask run`` will use the
interactive debugger and reloader by default in debug mode.
The environment is used to indicate to Flask, extensions, and other
programs, like Sentry, what context Flask is running in. It is
controlled with the :envvar:`FLASK_ENV` environment variable and
defaults to ``production``.
.. code-block:: text
Setting :envvar:`FLASK_ENV` to ``development`` will enable debug mode.
``flask run`` will use the interactive debugger and reloader by default
in debug mode. To control this separately from the environment, use the
:envvar:`FLASK_DEBUG` flag.
$ flask --app hello run --debug
.. versionchanged:: 1.0
Added :envvar:`FLASK_ENV` to control the environment separately
from debug mode. The development environment enables debug mode.
To switch Flask to the development environment and enable debug mode,
set :envvar:`FLASK_ENV`:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run
Using the environment variables as described above is recommended. While
it is possible to set :data:`ENV` and :data:`DEBUG` in your config or
code, this is strongly discouraged. They can't be read early by the
``flask`` command, and some systems or extensions may have already
configured themselves based on a previous value.
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`` command, and some systems or extensions may have already configured
themselves based on a previous value.
Builtin Configuration Values
@ -109,38 +65,21 @@ Builtin Configuration Values
The following configuration values are used internally by Flask:
.. py:data:: ENV
What environment the app is running in. Flask and extensions may
enable behaviors based on the environment, such as enabling debug
mode. The :attr:`~flask.Flask.env` attribute maps to this config
key. This is set by the :envvar:`FLASK_ENV` environment variable and
may not behave as expected if set in code.
**Do not enable development when deploying in production.**
Default: ``'production'``
.. versionadded:: 1.0
.. py:data:: DEBUG
Whether debug mode is enabled. When using ``flask run`` to start the
development server, an interactive debugger will be shown for
unhandled exceptions, and the server will be reloaded when code
changes. The :attr:`~flask.Flask.debug` attribute maps to this
config key. This is enabled when :data:`ENV` is ``'development'``
and is overridden by the ``FLASK_DEBUG`` environment variable. It
may not behave as expected if set in code.
Whether debug mode is enabled. When using ``flask run`` to start the development
server, an interactive debugger will be shown for unhandled exceptions, and the
server will be reloaded when code changes. The :attr:`~flask.Flask.debug` attribute
maps to this config key. This is set with the ``FLASK_DEBUG`` environment variable.
It may not behave as expected if set in code.
**Do not enable debug mode when deploying in production.**
Default: ``True`` if :data:`ENV` is ``'development'``, or ``False``
otherwise.
Default: ``False``
.. py:data:: TESTING
Enable testing mode. Exceptions are propagated rather than handled by the
Enable testing mode. Exceptions are propagated rather than handled by
the app's error handlers. Extensions may also change their behavior to
facilitate easier testing. You should enable this in your own tests.
@ -154,14 +93,6 @@ The following configuration values are used internally by Flask:
Default: ``None``
.. py:data:: PRESERVE_CONTEXT_ON_EXCEPTION
Don't pop the request context when an exception occurs. If not set, this
is true if ``DEBUG`` is true. This allows debuggers to introspect the
request data on errors, and should normally not need to be set directly.
Default: ``None``
.. py:data:: TRAP_HTTP_EXCEPTIONS
If there is no handler for an ``HTTPException``-type exception, re-raise it
@ -194,6 +125,25 @@ The following configuration values are used internally by Flask:
Default: ``None``
.. py:data:: SECRET_KEY_FALLBACKS
A list of old secret keys that can still be used for unsigning. This allows
a project to implement key rotation without invalidating active sessions or
other recently-signed secrets.
Keys should be removed after an appropriate period of time, as checking each
additional key adds some overhead.
Order should not matter, but the default implementation will test the last
key in the list first, so it might make sense to order oldest to newest.
Flask's built-in secure cookie session supports this. Extensions that use
:data:`SECRET_KEY` may not support this yet.
Default: ``None``
.. versionadded:: 3.1
.. py:data:: SESSION_COOKIE_NAME
The name of the session cookie. Can be changed in case you already have a
@ -203,12 +153,23 @@ The following configuration values are used internally by Flask:
.. py:data:: SESSION_COOKIE_DOMAIN
The domain match rule that the session cookie will be valid for. If not
set, the cookie will be valid for all subdomains of :data:`SERVER_NAME`.
If ``False``, the cookie's domain will not be set.
The value of the ``Domain`` parameter on the session cookie. If not set, browsers
will only send the cookie to the exact domain it was set from. Otherwise, they
will send it to any subdomain of the given value as well.
Not setting this value is more restricted and secure than setting it.
Default: ``None``
.. warning::
If this is changed after the browser created a cookie is created with
one setting, it may result in another being created. Browsers may send
send both in an undefined order. In that case, you may want to change
:data:`SESSION_COOKIE_NAME` as well or otherwise invalidate old sessions.
.. versionchanged:: 2.3
Not set by default, does not fall back to ``SERVER_NAME``.
.. py:data:: SESSION_COOKIE_PATH
The path that the session cookie will be valid for. If not set, the cookie
@ -231,6 +192,23 @@ The following configuration values are used internally by Flask:
Default: ``False``
.. py:data:: SESSION_COOKIE_PARTITIONED
Browsers will send cookies based on the top-level document's domain, rather
than only the domain of the document setting the cookie. This prevents third
party cookies set in iframes from "leaking" between separate sites.
Browsers are beginning to disallow non-partitioned third party cookies, so
you need to mark your cookies partitioned if you expect them to work in such
embedded situations.
Enabling this implicitly enables :data:`SESSION_COOKIE_SECURE` as well, as
it is only valid when served over HTTPS.
Default: ``False``
.. versionadded:: 3.1
.. py:data:: SESSION_COOKIE_SAMESITE
Restrict how cookies are sent with requests from external sites. Can
@ -283,24 +261,43 @@ The following configuration values are used internally by Flask:
Default: ``None``
.. py:data:: SERVER_NAME
.. py:data:: TRUSTED_HOSTS
Inform the application what host and port it is bound to. Required
for subdomain route matching support.
Validate :attr:`.Request.host` and other attributes that use it against
these trusted values. Raise a :exc:`~werkzeug.exceptions.SecurityError` if
the host is invalid, which results in a 400 error. If it is ``None``, all
hosts are valid. Each value is either an exact match, or can start with
a dot ``.`` to match any subdomain.
If set, will be used for the session cookie domain if
:data:`SESSION_COOKIE_DOMAIN` is not set. Modern web browsers will
not allow setting cookies for domains without a dot. To use a domain
locally, add any names that should route to the app to your
``hosts`` file. ::
127.0.0.1 localhost.dev
If set, ``url_for`` can generate external URLs with only an application
context instead of a request context.
Validation is done during routing against this value. ``before_request`` and
``after_request`` callbacks will still be called.
Default: ``None``
.. versionadded:: 3.1
.. py:data:: SERVER_NAME
Inform the application what host and port it is bound to.
Must be set if ``subdomain_matching`` is enabled, to be able to extract the
subdomain from the request.
Must be set for ``url_for`` to generate external URLs outside of a
request context.
Default: ``None``
.. versionchanged:: 3.1
Does not restrict requests to only this domain, for both
``subdomain_matching`` and ``host_matching``.
.. versionchanged:: 1.0
Does not implicitly enable ``subdomain_matching``.
.. versionchanged:: 2.3
Does not affect ``SESSION_COOKIE_DOMAIN``.
.. py:data:: APPLICATION_ROOT
Inform the application what path it is mounted under by the application /
@ -322,42 +319,53 @@ The following configuration values are used internally by Flask:
.. py:data:: MAX_CONTENT_LENGTH
Don't read more than this many bytes from the incoming request data. If not
set and the request does not specify a ``CONTENT_LENGTH``, no data will be
read for security.
The maximum number of bytes that will be read during this request. If
this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge`
error is raised. If it is set to ``None``, no limit is enforced at the
Flask application level. However, if it is ``None`` and the request has no
``Content-Length`` header and the WSGI server does not indicate that it
terminates the stream, then no data is read to avoid an infinite stream.
Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_content_length` to apply the limit to that specific
view. This should be set appropriately based on an application's or view's
specific needs.
Default: ``None``
.. py:data:: JSON_AS_ASCII
.. versionadded:: 0.6
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.
.. py:data:: MAX_FORM_MEMORY_SIZE
Default: ``True``
The maximum size in bytes any non-file form field may be in a
``multipart/form-data`` body. If this limit is exceeded, a 413
:exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it is
set to ``None``, no limit is enforced at the Flask application level.
.. py:data:: JSON_SORT_KEYS
Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_form_memory_parts` to apply the limit to that specific
view. This should be set appropriately based on an application's or view's
specific needs.
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: ``500_000``
Default: ``True``
.. versionadded:: 3.1
.. py:data:: JSONIFY_PRETTYPRINT_REGULAR
.. py:data:: MAX_FORM_PARTS
``jsonify`` responses will be output with newlines, spaces, and indentation
for easier reading by humans. Always enabled in debug mode.
The maximum number of fields that may be present in a
``multipart/form-data`` body. If this limit is exceeded, a 413
:exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it
is set to ``None``, no limit is enforced at the Flask application level.
Default: ``False``
Each request defaults to this config. It can be set on a specific
:attr:`.Request.max_form_parts` to apply the limit to that specific view.
This should be set appropriately based on an application's or view's
specific needs.
.. py:data:: JSONIFY_MIMETYPE
Default: ``1_000``
The mimetype of ``jsonify`` responses.
Default: ``'application/json'``
.. versionadded:: 3.1
.. py:data:: TEMPLATES_AUTO_RELOAD
@ -380,6 +388,12 @@ The following configuration values are used internally by Flask:
``4093``. Larger cookies may be silently ignored by browsers. Set to
``0`` to disable the warning.
.. py:data:: PROVIDE_AUTOMATIC_OPTIONS
Set to ``False`` to disable the automatic addition of OPTIONS
responses. This can be overridden per route by altering the
``provide_automatic_options`` attribute.
.. versionadded:: 0.4
``LOGGER_NAME``
@ -420,17 +434,30 @@ The following configuration values are used internally by Flask:
Added :data:`MAX_COOKIE_SIZE` to control a warning from Werkzeug.
.. versionchanged:: 2.2
Removed ``PRESERVE_CONTEXT_ON_EXCEPTION``.
.. versionchanged:: 2.3
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_MIMETYPE``, and
``JSONIFY_PRETTYPRINT_REGULAR`` were removed. The default ``app.json`` provider has
equivalent attributes instead.
.. versionchanged:: 2.3
``ENV`` was removed.
.. versionadded:: 3.1
Added :data:`PROVIDE_AUTOMATIC_OPTIONS` to control the default
addition of autogenerated OPTIONS responses.
Configuring from Python Files
-----------------------------
Configuration becomes more useful if you can store it in a separate file,
ideally located outside the actual application package. This makes
packaging and distributing your application possible via various package
handling tools (:doc:`/patterns/distribute`) and finally modifying the
configuration file afterwards.
Configuration becomes more useful if you can store it in a separate file, ideally
located outside the actual application package. You can deploy your application, then
separately configure it for the specific deployment.
So a common pattern is this::
A common pattern is this::
app = Flask(__name__)
app.config.from_object('yourapplication.default_settings')
@ -501,8 +528,8 @@ from a TOML file:
.. code-block:: python
import toml
app.config.from_file("config.toml", load=toml.load)
import tomllib
app.config.from_file("config.toml", load=tomllib.load, text=False)
Or from a JSON file:
@ -722,10 +749,8 @@ your configuration files. However here a list of good recommendations:
code at all. If you are working often on different projects you can
even create your own script for sourcing that activates a virtualenv
and exports the development configuration for you.
- Use a tool like `fabric`_ in production to push code and
configurations separately to the production server(s). For some
details about how to do that, head over to the
:doc:`/patterns/fabric` pattern.
- Use a tool like `fabric`_ to push code and configuration separately
to the production server(s).
.. _fabric: https://www.fabfile.org/

View file

@ -1 +1,8 @@
.. include:: ../CONTRIBUTING.rst
Contributing
============
See the Pallets `detailed contributing documentation <contrib_>`_ for many ways
to contribute, including reporting issues, requesting features, asking or
answering questions, and making PRs.
.. _contrib: https://palletsprojects.com/contributing/

View file

@ -39,54 +39,22 @@ during a request. This debugger should only be used during development.
security risk. Do not run the development server or debugger in a
production environment.
To enable the debugger, run the development server with the
``FLASK_ENV`` environment variable set to ``development``. This puts
Flask in debug mode, which changes how it handles some errors, and
enables the debugger and reloader.
The debugger is enabled by default when the development server is run in debug mode.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
$ flask --app hello run --debug
.. code-block:: text
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run
``FLASK_ENV`` can only be set as an environment variable. When running
from Python code, passing ``debug=True`` enables debug mode, which is
mostly equivalent. Debug mode can be controlled separately from
``FLASK_ENV`` with the ``FLASK_DEBUG`` environment variable as well.
When running from Python code, passing ``debug=True`` enables debug mode, which is
mostly equivalent.
.. code-block:: python
app.run(debug=True)
:doc:`/server` and :doc:`/cli` have more information about running the
debugger, debug mode, and development mode. More information about the
debugger can be found in the `Werkzeug documentation
<https://werkzeug.palletsprojects.com/debug/>`__.
:doc:`/server` and :doc:`/cli` have more information about running the debugger and
debug mode. More information about the debugger can be found in the `Werkzeug
documentation <https://werkzeug.palletsprojects.com/debug/>`__.
External Debuggers
@ -98,41 +66,13 @@ be used to step through code during a request before an error is raised,
or if no error is raised. Some even have a remote mode so you can debug
code running on another machine.
When using an external debugger, the app should still be in debug mode,
but it can be useful to disable the built-in debugger and reloader,
which can interfere.
When using an external debugger, the app should still be in debug mode, otherwise Flask
turns unhandled errors into generic 500 error pages. However, the built-in debugger and
reloader should be disabled so they don't interfere with the external debugger.
When running from the command line:
.. code-block:: text
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
$ flask run --no-debugger --no-reload
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run --no-debugger --no-reload
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run --no-debugger --no-reload
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run --no-debugger --no-reload
$ flask --app hello run --debug --no-debugger --no-reload
When running from Python:
@ -140,8 +80,20 @@ When running from Python:
app.run(debug=True, use_debugger=False, use_reloader=False)
Disabling these isn't required, an external debugger will continue to
work with the following caveats. If the built-in debugger is not
disabled, it will catch unhandled exceptions before the external
debugger can. If the reloader is not disabled, it could cause an
unexpected reload if code changes during debugging.
Disabling these isn't required, an external debugger will continue to work with the
following caveats.
- If the built-in debugger is not disabled, it will catch unhandled exceptions before
the external debugger can.
- If the reloader is not disabled, it could cause an unexpected reload if code changes
during a breakpoint.
- The development server will still catch unhandled exceptions if the built-in
debugger is disabled, otherwise it would crash on any error. If you want that (and
usually you don't) pass ``passthrough_errors=True`` to ``app.run``.
.. code-block:: python
app.run(
debug=True, passthrough_errors=True,
use_debugger=False, use_reloader=False
)

View file

@ -20,7 +20,7 @@ wrapping the Flask app,
asgi_app = WsgiToAsgi(app)
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

View file

@ -1,80 +1,8 @@
:orphan:
eventlet
========
Prefer using :doc:`gunicorn` with eventlet workers rather than using
`eventlet`_ directly. Gunicorn provides a much more configurable and
production-tested server.
`Eventlet is no longer maintained.`__ Use :doc:`/deploying/gevent` instead.
`eventlet`_ allows writing asynchronous, coroutine-based code that looks
like standard synchronous Python. It uses `greenlet`_ to enable task
switching without writing ``async/await`` or using ``asyncio``.
:doc:`gevent` is another library that does the same thing. Certain
dependencies you have, or other considerations, may affect which of the
two you choose to use.
eventlet provides a WSGI server that can handle many connections at once
instead of one per worker process. You must actually use eventlet in
your own code to see any benefit to using the server.
.. _eventlet: https://eventlet.net/
.. _greenlet: https://greenlet.readthedocs.io/en/latest/
Installing
----------
When using eventlet, greenlet>=1.0 is required, otherwise context locals
such as ``request`` will not work as expected. When using PyPy,
PyPy>=7.3.7 is required.
Create a virtualenv, install your application, then install
``eventlet``.
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ pip install . # install your application
$ pip install eventlet
Running
-------
To use eventlet to serve your application, write a script that imports
its ``wsgi.server``, as well as your app or app factory.
.. code-block:: python
:caption: ``wsgi.py``
import eventlet
from eventlet import wsgi
from hello import create_app
app = create_app()
wsgi.server(eventlet.listen(("127.0.0.1", 8000), app)
.. code-block:: text
$ python wsgi.py
(x) wsgi starting up on http://127.0.0.1:8000
Binding Externally
------------------
eventlet should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
in front of eventlet.
You can bind to all external IPs on a non-privileged port by using
``0.0.0.0`` in the server arguments shown in the previous section.
Don't do this when using a reverse proxy setup, otherwise it will be
possible to bypass the proxy.
``0.0.0.0`` is not a valid address to navigate to, you'd use a specific
IP address in your browser.
__ https://eventlet.readthedocs.io

View file

@ -7,15 +7,12 @@ configurable and production-tested servers.
`gevent`_ allows writing asynchronous, coroutine-based code that looks
like standard synchronous Python. It uses `greenlet`_ to enable task
switching without writing ``async/await`` or using ``asyncio``.
:doc:`eventlet` is another library that does the same thing. Certain
dependencies you have, or other considerations, may affect which of the
two you choose to use.
switching without writing ``async/await`` or using ``asyncio``. This is
not the same as Python's ``async/await``, or the ASGI server spec.
gevent provides a WSGI server that can handle many connections at once
instead of one per worker process. You must actually use gevent in your
own code to see any benefit to using the server.
instead of one per worker process. See :doc:`/gevent` for more
information about enabling it in your application.
.. _gevent: https://www.gevent.org/
.. _greenlet: https://greenlet.readthedocs.io/en/latest/
@ -24,8 +21,7 @@ own code to see any benefit to using the server.
Installing
----------
When using gevent, greenlet>=1.0 is required, otherwise context locals
such as ``request`` will not work as expected. When using PyPy,
When using gevent, greenlet>=1.0 is required. When using PyPy,
PyPy>=7.3.7 is required.
Create a virtualenv, install your application, then install ``gevent``.
@ -33,8 +29,8 @@ Create a virtualenv, install your application, then install ``gevent``.
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install gevent

View file

@ -8,7 +8,7 @@ multiple worker implementations for performance tuning.
* It does not support Windows (but does run on WSL).
* It is easy to install as it does not require additional dependencies
or compilation.
* It has built-in async worker support using gevent or eventlet.
* It has built-in async worker support using gevent.
This page outlines the basics of running Gunicorn. Be sure to read its
`documentation`_ and use ``gunicorn --help`` to understand what features
@ -30,8 +30,8 @@ Create a virtualenv, install your application, then install
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install gunicorn
@ -93,20 +93,19 @@ otherwise it will be possible to bypass the proxy.
IP address in your browser.
Async with gevent or eventlet
-----------------------------
Async with gevent
-----------------
The default sync worker is appropriate for many use cases. If you need
asynchronous support, Gunicorn provides workers using either `gevent`_
or `eventlet`_. This is not the same as Python's ``async/await``, or the
ASGI server spec. You must actually use gevent/eventlet in your own code
to see any benefit to using the workers.
The default sync worker is appropriate for most use cases. If you need numerous,
long running, concurrent connections, Gunicorn provides an asynchronous worker
using `gevent`_. This is not the same as Python's ``async/await``, or the ASGI
server spec. See :doc:`/gevent` for more information about enabling it in your
application.
When using either gevent or eventlet, greenlet>=1.0 is required,
otherwise context locals such as ``request`` will not work as expected.
When using PyPy, PyPy>=7.3.7 is required.
.. _gevent: https://www.gevent.org/
To use gevent:
When using gevent, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
required.
.. code-block:: text
@ -115,16 +114,3 @@ To use gevent:
Listening at: http://127.0.0.1:8000 (x)
Using worker: gevent
Booting worker with pid: x
To use eventlet:
.. code-block:: text
$ gunicorn -k eventlet 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: eventlet
Booting worker with pid: x
.. _gevent: https://www.gevent.org/
.. _eventlet: https://eventlet.net/

View file

@ -36,7 +36,6 @@ discusses platforms that can manage this for you.
mod_wsgi
uwsgi
gevent
eventlet
asgi
WSGI servers have HTTP servers built-in. However, a dedicated HTTP
@ -66,7 +65,6 @@ interface. The links below are for some of the most common platforms,
which have instructions for Flask, WSGI, or Python.
- `PythonAnywhere <https://help.pythonanywhere.com/pages/Flask/>`_
- `Heroku <https://devcenter.heroku.com/articles/getting-started-with-python>`_
- `Google App Engine <https://cloud.google.com/appengine/docs/standard/python3/building-app>`_
- `Google Cloud Run <https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-python-service>`_
- `AWS Elastic Beanstalk <https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create-deploy-python-flask.html>`_

View file

@ -33,8 +33,8 @@ Create a virtualenv, install your application, then install
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install mod_wsgi
@ -89,6 +89,6 @@ mod_wsgi to drop to that user after starting.
.. code-block:: text
$ sudo /home/hello/venv/bin/mod_wsgi-express start-server \
$ sudo /home/hello/.venv/bin/mod_wsgi-express start-server \
/home/hello/wsgi.py \
--user hello --group hello --port 80 --processes 4

View file

@ -29,8 +29,8 @@ Create a virtualenv, install your application, then install ``pyuwsgi``.
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install pyuwsgi
@ -119,15 +119,16 @@ IP address in your browser.
Async with gevent
-----------------
The default sync worker is appropriate for many use cases. If you need
asynchronous support, uWSGI provides a `gevent`_ worker. This is not the
same as Python's ``async/await``, or the ASGI server spec. You must
actually use gevent in your own code to see any benefit to using the
worker.
The default sync worker is appropriate for most use cases. If you need numerous,
long running, concurrent connections, uWSGI provides an asynchronous worker
using `gevent`_. This is not the same as Python's ``async/await``, or the ASGI
server spec. See :doc:`/gevent` for more information about enabling it in your
application.
When using gevent, greenlet>=1.0 is required, otherwise context locals
such as ``request`` will not work as expected. When using PyPy,
PyPy>=7.3.7 is required.
.. _gevent: https://www.gevent.org/
When using gevent, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
required.
.. code-block:: text
@ -140,6 +141,3 @@ PyPy>=7.3.7 is required.
spawned uWSGI worker 1 (pid: x, cores: 100)
spawned uWSGI http 1 (pid: x)
*** running gevent loop engine [addr:x] ***
.. _gevent: https://www.gevent.org/

View file

@ -27,8 +27,8 @@ Create a virtualenv, install your application, then install
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ python -m venv .venv
$ . .venv/bin/activate
$ pip install . # install your application
$ pip install waitress
@ -45,10 +45,10 @@ pattern, use ``--call {module}:{factory}`` instead.
.. code-block:: text
# equivalent to 'from hello import app'
$ waitress-serve hello:app --host 127.0.0.1
$ waitress-serve --host 127.0.0.1 hello:app
# equivalent to 'from hello import create_app; create_app()'
$ waitress-serve --call hello:create_app --host 127.0.0.1
$ waitress-serve --host 127.0.0.1 --call hello:create_app
Serving on http://127.0.0.1:8080
@ -68,7 +68,7 @@ reverse proxy such as :doc:`nginx` or :doc:`apache-httpd` should be used
in front of Waitress.
You can bind to all external IPs on a non-privileged port by not
specifying the ``--host`` option. Don't do this when using a revers
specifying the ``--host`` option. Don't do this when using a reverse
proxy setup, otherwise it will be possible to bypass the proxy.
``0.0.0.0`` is not a valid address to navigate to, you'd use a specific

View file

@ -96,10 +96,10 @@ is ambiguous.
One Template Engine
-------------------
Flask decides on one template engine: Jinja2. Why doesn't Flask have a
Flask decides on one template engine: Jinja. Why doesn't Flask have a
pluggable template engine interface? You can obviously use a different
template engine, but Flask will still configure Jinja2 for you. While
that limitation that Jinja2 is *always* configured will probably go away,
template engine, but Flask will still configure Jinja for you. While
that limitation that Jinja is *always* configured will probably go away,
the decision to bundle one template engine and use that will not.
Template engines are like programming languages and each of those engines
@ -107,7 +107,7 @@ has a certain understanding about how things work. On the surface they
all work the same: you tell the engine to evaluate a template with a set
of variables and take the return value as string.
But that's about where similarities end. Jinja2 for example has an
But that's about where similarities end. Jinja for example has an
extensive filter system, a certain way to do template inheritance,
support for reusable blocks (macros) that can be used from inside
templates and also from Python code, supports iterative template
@ -118,8 +118,8 @@ other hand treats templates similar to Python modules.
When it comes to connecting a template engine with an application or
framework there is more than just rendering templates. For instance,
Flask uses Jinja2's extensive autoescaping support. Also it provides
ways to access macros from Jinja2 templates.
Flask uses Jinja's extensive autoescaping support. Also it provides
ways to access macros from Jinja templates.
A template abstraction layer that would not take the unique features of
the template engines away is a science on its own and a too large
@ -130,11 +130,27 @@ being present. You can easily use your own templating language, but an
extension could still depend on Jinja itself.
Micro with Dependencies
What does "micro" mean?
-----------------------
“Micro” does not mean that your whole web application has to fit into a single
Python file (although it certainly can), nor does it mean that Flask is lacking
in functionality. The "micro" in microframework means Flask aims to keep the
core simple but extensible. Flask won't make many decisions for you, such as
what database to use. Those decisions that it does make, such as what
templating engine to use, are easy to change. Everything else is up to you, so
that Flask can be everything you need and nothing you don't.
By default, Flask does not include a database abstraction layer, form
validation or anything else where different libraries already exist that can
handle that. Instead, Flask supports extensions to add such functionality to
your application as if it was implemented in Flask itself. Numerous extensions
provide database integration, form validation, upload handling, various open
authentication technologies, and more. Flask may be "micro", but it's ready for
production use on a variety of needs.
Why does Flask call itself a microframework and yet it depends on two
libraries (namely Werkzeug and Jinja2). Why shouldn't it? If we look
libraries (namely Werkzeug and Jinja). Why shouldn't it? If we look
over to the Ruby side of web development there we have a protocol very
similar to WSGI. Just that it's called Rack there, but besides that it
looks very much like a WSGI rendition for Ruby. But nearly all
@ -153,19 +169,20 @@ infrastructure, packages with dependencies are no longer an issue and
there are very few reasons against having libraries that depend on others.
Thread Locals
-------------
Context Locals
--------------
Flask uses thread local objects (context local objects in fact, they
support greenlet contexts as well) for request, session and an extra
object you can put your own things on (:data:`~flask.g`). Why is that and
isn't that a bad idea?
Flask uses special context locals and proxies to provide access to the
current app and request data to any code running during a request, CLI command,
etc. Context locals are specific to the worker handling the activity, such as a
thread, process, coroutine, or greenlet.
Yes it is usually not such a bright idea to use thread locals. They cause
troubles for servers that are not based on the concept of threads and make
large applications harder to maintain. However Flask is just not designed
for large applications or asynchronous servers. Flask wants to make it
quick and easy to write a traditional web application.
The context and proxies help solve two development issues: circular imports, and
passing around global data. :data:`.current_app` can be used to access the
application object without needing to import the app object directly, avoiding
circular import issues. :data:`.request`, :data:`.session`, and :data:`.g` can
be imported to access the current data for the request, rather than needing to
pass them as arguments through every single function in your project.
Async/await and ASGI support
@ -192,7 +209,7 @@ What Flask is, What Flask is Not
Flask will never have a database layer. It will not have a form library
or anything else in that direction. Flask itself just bridges to Werkzeug
to implement a proper WSGI application and to Jinja2 to handle templating.
to implement a proper WSGI application and to Jinja to handle templating.
It also binds to a few common standard library packages such as logging.
Everything else is up for extensions.
@ -201,5 +218,12 @@ requirements and Flask could not meet those if it would force any of this
into the core. The majority of web applications will need a template
engine in some sort. However not every application needs a SQL database.
As your codebase grows, you are free to make the design decisions appropriate
for your project. Flask will continue to provide a very simple glue layer to
the best that Python has to offer. You can implement advanced patterns in
SQLAlchemy or another database tool, introduce non-relational data persistence
as appropriate, and take advantage of framework-agnostic tools built for WSGI,
the Python web interface.
The idea of Flask is to build a good foundation for all applications.
Everything else is up to you or extensions.

View file

@ -69,7 +69,6 @@ See also:
- Sentry also supports catching errors from a worker queue
(RQ, Celery, etc.) in a similar fashion. See the `Python SDK docs
<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/>`__
@ -232,7 +231,7 @@ responses, you could also pass them through directly.
Error handlers still respect the exception class hierarchy. If you
register handlers for both ``HTTPException`` and ``Exception``, the
``Exception`` handler will not handle ``HTTPException`` subclasses
because it the ``HTTPException`` handler is more specific.
because the ``HTTPException`` handler is more specific.
Unhandled Exceptions

View file

@ -67,7 +67,7 @@ application instance.
It is important that the app is not stored on the extension, don't do
``self.app = app``. The only time the extension should have direct
access to an app is during ``init_app``, otherwise it should use
:data:`current_app`.
:data:`.current_app`.
This allows the extension to support the application factory pattern,
avoids circular import issues when importing the extension instance
@ -105,7 +105,7 @@ during an extension's ``init_app`` method.
A common pattern is to use :meth:`~Flask.before_request` to initialize
some data or a connection at the beginning of each request, then
:meth:`~Flask.teardown_request` to clean it up at the end. This can be
stored on :data:`g`, discussed more below.
stored on :data:`.g`, discussed more below.
A more lazy approach is to provide a method that initializes and caches
the data or connection. For example, a ``ext.get_db`` method could
@ -179,19 +179,12 @@ name as a prefix, or as a namespace.
g._hello = SimpleNamespace()
g._hello.user_id = 2
The data in ``g`` lasts for an application context. An application
context is active when a request context is, or when a CLI command is
run. If you're storing something that should be closed, use
:meth:`~flask.Flask.teardown_appcontext` to ensure that it gets closed
when the application context ends. If it should only be valid during a
request, or would not be used in the CLI outside a reqeust, use
:meth:`~flask.Flask.teardown_request`.
An older technique for storing context data was to store it on
``_app_ctx_stack.top`` or ``_request_ctx_stack.top``. However, this just
moves the same namespace collision problem elsewhere (although less
likely) and modifies objects that are very internal to Flask's
operations. Prefer storing data under a unique name in ``g``.
The data in ``g`` lasts for an application context. An application context is
active during a request, CLI command, or ``with app.app_context()`` block. If
you're storing something that should be closed, use
:meth:`~flask.Flask.teardown_appcontext` to ensure that it gets closed when the
app context ends. If it should only be valid during a request, or would not be
used in the CLI outside a request, use :meth:`~flask.Flask.teardown_request`.
Views and Models
@ -218,7 +211,7 @@ class's :meth:`~views.View.as_view` method.
def __init__(self, model):
self.model = model
def get(id):
def get(self, id):
post = self.model.query.get(id)
return jsonify(post.to_json())
@ -299,12 +292,14 @@ ecosystem remain consistent and compatible.
any particular version scheme, but should use lower bounds to
indicate minimum compatibility support. For example,
``sqlalchemy>=1.4``.
9. Indicate the versions of Python supported using
``python_requires=">=version"``. Flask itself supports Python >=3.7
as of December 2021, but this will update over time.
9. Indicate the versions of Python supported using ``python_requires=">=version"``.
Flask and Pallets policy is to support all Python versions that are not
within six months of end of life (EOL). See Python's `EOL calendar`_ for
timing.
.. _PyPI: https://pypi.org/search/?c=Framework+%3A%3A+Flask
.. _Discord Chat: https://discord.gg/pallets
.. _GitHub Discussions: https://github.com/pallets/flask/discussions
.. _Official Pallets Themes: https://pypi.org/project/Pallets-Sphinx-Themes/
.. _Pallets-Eco: https://github.com/pallets-eco
.. _EOL calendar: https://devguide.python.org/versions/

View file

@ -1,53 +0,0 @@
Foreword
========
Read this before you get started with Flask. This hopefully answers some
questions about the purpose and goals of the project, and when you
should or should not be using it.
What does "micro" mean?
-----------------------
“Micro” does not mean that your whole web application has to fit into a single
Python file (although it certainly can), nor does it mean that Flask is lacking
in functionality. The "micro" in microframework means Flask aims to keep the
core simple but extensible. Flask won't make many decisions for you, such as
what database to use. Those decisions that it does make, such as what
templating engine to use, are easy to change. Everything else is up to you, so
that Flask can be everything you need and nothing you don't.
By default, Flask does not include a database abstraction layer, form
validation or anything else where different libraries already exist that can
handle that. Instead, Flask supports extensions to add such functionality to
your application as if it was implemented in Flask itself. Numerous extensions
provide database integration, form validation, upload handling, various open
authentication technologies, and more. Flask may be "micro", but it's ready for
production use on a variety of needs.
Configuration and Conventions
-----------------------------
Flask has many configuration values, with sensible defaults, and a few
conventions when getting started. By convention, templates and static
files are stored in subdirectories within the application's Python
source tree, with the names :file:`templates` and :file:`static`
respectively. While this can be changed, you usually don't have to,
especially when getting started.
Growing with Flask
------------------
Once you have Flask up and running, you'll find a variety of extensions
available in the community to integrate your project for production.
As your codebase grows, you are free to make the design decisions appropriate
for your project. Flask will continue to provide a very simple glue layer to
the best that Python has to offer. You can implement advanced patterns in
SQLAlchemy or another database tool, introduce non-relational data persistence
as appropriate, and take advantage of framework-agnostic tools built for WSGI,
the Python web interface.
Flask includes many hooks to customize its behavior. Should you need
more customization, the Flask class is built for subclassing. If you are
curious about the Flask design principles, head over to the section
about :doc:`design`.

125
docs/gevent.rst Normal file
View file

@ -0,0 +1,125 @@
Async with Gevent
=================
`Gevent`_ patches Python's standard library to run within special async workers
called `greenlets`_. Gevent has existed since long before Python's native
asyncio was available, and Flask has always worked with it.
.. _gevent: https://www.gevent.org
.. _greenlets: https://greenlet.readthedocs.io
Gevent is a reliable way to handle numerous, long lived, concurrent connections,
and to achieve similar capabilities to ASGI and asyncio. This works without
needing to write ``async def`` or ``await`` anywhere, but relies on gevent and
greenlet's low level manipulation of the Python interpreter.
Deciding whether you should use gevent with Flask, or `Quart`_, or something
else, is ultimately up to understanding the specific needs of your project.
.. _quart: https://quart.palletsprojects.com
Enabling gevent
---------------
You need to apply gevent's patching as early as possible in your code. This
enables gevent's underlying event loop and converts many Python internals to run
inside it. Add the following at the top of your project's module or top
``__init__.py``:
.. code-block:: python
import gevent.monkey
gevent.monkey.patch_all()
When deploying in production, use :doc:`/deploying/gunicorn` or
:doc:`/deploying/uwsgi` with a gevent worker, as described on those pages.
To run concurrent tasks within your own code, such as views, use
|gevent.spawn|_:
.. |gevent.spawn| replace:: ``gevent.spawn()``
.. _gevent.spawn: https://www.gevent.org/api/gevent.html#gevent.spawn
.. code-block:: python
@app.post("/send")
def send_email():
gevent.spawn(email.send, to="example@example.example", text="example")
return "Email is being sent."
If you need to access :data:`request` or other Flask context globals within the
spawned function, decorate the function with :func:`.stream_with_context` or
:func:`.copy_current_request_context`. Prefer passing the exact data you need
when spawning the function, rather than using the decorators.
.. note::
When using gevent, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7
is required.
.. _gevent-asyncio:
Combining with ``async``/``await``
----------------------------------
Gevent's patching does not interact well with Flask's built-in asyncio support.
If you want to use Gevent and asyncio in the same app, you'll need to override
:meth:`flask.Flask.async_to_sync` to run async functions inside gevent.
.. code-block:: python
import gevent.monkey
gevent.monkey.patch_all()
import asyncio
from flask import Flask, request
loop = asyncio.EventLoop()
gevent.spawn(loop.run_forever)
class GeventFlask(Flask):
def async_to_sync(self, func):
def run(*args, **kwargs):
coro = func(*args, **kwargs)
future = asyncio.run_coroutine_threadsafe(coro, loop)
return future.result()
return run
app = GeventFlask(__name__)
@app.get("/")
async def greet():
await asyncio.sleep(1)
return f"Hello, {request.args.get("name", "World")}!"
This starts an asyncio event loop in a gevent worker. Async functions are
scheduled on that event loop. This may still have limitations, and may need to
be modified further when using other asyncio implementations.
libuv
~~~~~
`libuv`_ is another event loop implementation that `gevent supports`_. There's
also a project called `uvloop`_ that enables libuv in asyncio. If you want to
use libuv, use gevent's support, not uvloop. It may be possible to further
modify the ``async_to_sync`` code from the previous section to work with uvloop,
but that's not currently known.
.. _libuv: https://libuv.org/
.. _gevent supports: https://www.gevent.org/loop_impls.html
.. _uvloop: https://uvloop.readthedocs.io/
To enable gevent's libuv support, add the following at the *very* top of your
code, before ``gevent.monkey.patch_all()``:
.. code-block:: python
import gevent
gevent.config.loop = "libuv"
import gevent.monkey
gevent.monkey.patch_all()

View file

@ -1,206 +0,0 @@
HTML/XHTML FAQ
==============
The Flask documentation and example applications are using HTML5. You
may notice that in many situations, when end tags are optional they are
not used, so that the HTML is cleaner and faster to load. Because there
is much confusion about HTML and XHTML among developers, this document tries
to answer some of the major questions.
History of XHTML
----------------
For a while, it appeared that HTML was about to be replaced by XHTML.
However, barely any websites on the Internet are actual XHTML (which is
HTML processed using XML rules). There are a couple of major reasons
why this is the case. One of them is Internet Explorer's lack of proper
XHTML support. The XHTML spec states that XHTML must be served with the MIME
type :mimetype:`application/xhtml+xml`, but Internet Explorer refuses
to read files with that MIME type.
While it is relatively easy to configure Web servers to serve XHTML properly,
few people do. This is likely because properly using XHTML can be quite
painful.
One of the most important causes of pain is XML's draconian (strict and
ruthless) error handling. When an XML parsing error is encountered,
the browser is supposed to show the user an ugly error message, instead
of attempting to recover from the error and display what it can. Most of
the (X)HTML generation on the web is based on non-XML template engines
(such as Jinja, the one used in Flask) which do not protect you from
accidentally creating invalid XHTML. There are XML based template engines,
such as Kid and the popular Genshi, but they often come with a larger
runtime overhead and are not as straightforward to use because they have
to obey XML rules.
The majority of users, however, assumed they were properly using XHTML.
They wrote an XHTML doctype at the top of the document and self-closed all
the necessary tags (``<br>`` becomes ``<br/>`` or ``<br></br>`` in XHTML).
However, even if the document properly validates as XHTML, what really
determines XHTML/HTML processing in browsers is the MIME type, which as
said before is often not set properly. So the valid XHTML was being treated
as invalid HTML.
XHTML also changed the way JavaScript is used. To properly work with XHTML,
programmers have to use the namespaced DOM interface with the XHTML
namespace to query for HTML elements.
History of HTML5
----------------
Development of the HTML5 specification was started in 2004 under the name
"Web Applications 1.0" by the Web Hypertext Application Technology Working
Group, or WHATWG (which was formed by the major browser vendors Apple,
Mozilla, and Opera) with the goal of writing a new and improved HTML
specification, based on existing browser behavior instead of unrealistic
and backwards-incompatible specifications.
For example, in HTML4 ``<title/Hello/`` theoretically parses exactly the
same as ``<title>Hello</title>``. However, since people were using
XHTML-like tags along the lines of ``<link />``, browser vendors implemented
the XHTML syntax over the syntax defined by the specification.
In 2007, the specification was adopted as the basis of a new HTML
specification under the umbrella of the W3C, known as HTML5. Currently,
it appears that XHTML is losing traction, as the XHTML 2 working group has
been disbanded and HTML5 is being implemented by all major browser vendors.
HTML versus XHTML
-----------------
The following table gives you a quick overview of features available in
HTML 4.01, XHTML 1.1 and HTML5. (XHTML 1.0 is not included, as it was
superseded by XHTML 1.1 and the barely-used XHTML5.)
.. tabularcolumns:: |p{9cm}|p{2cm}|p{2cm}|p{2cm}|
+-----------------------------------------+----------+----------+----------+
| | HTML4.01 | XHTML1.1 | HTML5 |
+=========================================+==========+==========+==========+
| ``<tag/value/`` == ``<tag>value</tag>`` | |Y| [1]_ | |N| | |N| |
+-----------------------------------------+----------+----------+----------+
| ``<br/>`` supported | |N| | |Y| | |Y| [2]_ |
+-----------------------------------------+----------+----------+----------+
| ``<script/>`` supported | |N| | |Y| | |N| |
+-----------------------------------------+----------+----------+----------+
| should be served as `text/html` | |Y| | |N| [3]_ | |Y| |
+-----------------------------------------+----------+----------+----------+
| should be served as | |N| | |Y| | |N| |
| `application/xhtml+xml` | | | |
+-----------------------------------------+----------+----------+----------+
| strict error handling | |N| | |Y| | |N| |
+-----------------------------------------+----------+----------+----------+
| inline SVG | |N| | |Y| | |Y| |
+-----------------------------------------+----------+----------+----------+
| inline MathML | |N| | |Y| | |Y| |
+-----------------------------------------+----------+----------+----------+
| ``<video>`` tag | |N| | |N| | |Y| |
+-----------------------------------------+----------+----------+----------+
| ``<audio>`` tag | |N| | |N| | |Y| |
+-----------------------------------------+----------+----------+----------+
| New semantic tags like ``<article>`` | |N| | |N| | |Y| |
+-----------------------------------------+----------+----------+----------+
.. [1] This is an obscure feature inherited from SGML. It is usually not
supported by browsers, for reasons detailed above.
.. [2] This is for compatibility with server code that generates XHTML for
tags such as ``<br>``. It should not be used in new code.
.. [3] XHTML 1.0 is the last XHTML standard that allows to be served
as `text/html` for backwards compatibility reasons.
.. |Y| image:: _static/yes.png
:alt: Yes
.. |N| image:: _static/no.png
:alt: No
What does "strict" mean?
------------------------
HTML5 has strictly defined parsing rules, but it also specifies exactly
how a browser should react to parsing errors - unlike XHTML, which simply
states parsing should abort. Some people are confused by apparently
invalid syntax that still generates the expected results (for example,
missing end tags or unquoted attribute values).
Some of these work because of the lenient error handling most browsers use
when they encounter a markup error, others are actually specified. The
following constructs are optional in HTML5 by standard, but have to be
supported by browsers:
- Wrapping the document in an ``<html>`` tag
- Wrapping header elements in ``<head>`` or the body elements in
``<body>``
- Closing the ``<p>``, ``<li>``, ``<dt>``, ``<dd>``, ``<tr>``,
``<td>``, ``<th>``, ``<tbody>``, ``<thead>``, or ``<tfoot>`` tags.
- Quoting attributes, so long as they contain no whitespace or
special characters (like ``<``, ``>``, ``'``, or ``"``).
- Requiring boolean attributes to have a value.
This means the following page in HTML5 is perfectly valid:
.. sourcecode:: html
<!doctype html>
<title>Hello HTML5</title>
<div class=header>
<h1>Hello HTML5</h1>
<p class=tagline>HTML5 is awesome
</div>
<ul class=nav>
<li><a href=/index>Index</a>
<li><a href=/downloads>Downloads</a>
<li><a href=/about>About</a>
</ul>
<div class=body>
<h2>HTML5 is probably the future</h2>
<p>
There might be some other things around but in terms of
browser vendor support, HTML5 is hard to beat.
<dl>
<dt>Key 1
<dd>Value 1
<dt>Key 2
<dd>Value 2
</dl>
</div>
New technologies in HTML5
-------------------------
HTML5 adds many new features that make Web applications easier to write
and to use.
- The ``<audio>`` and ``<video>`` tags provide a way to embed audio and
video without complicated add-ons like QuickTime or Flash.
- Semantic elements like ``<article>``, ``<header>``, ``<nav>``, and
``<time>`` that make content easier to understand.
- The ``<canvas>`` tag, which supports a powerful drawing API, reducing
the need for server-generated images to present data graphically.
- New form control types like ``<input type="date">`` that allow user
agents to make entering and validating values easier.
- Advanced JavaScript APIs like Web Storage, Web Workers, Web Sockets,
geolocation, and offline applications.
Many other features have been added, as well. A good guide to new features
in HTML5 is Mark Pilgrim's book, `Dive Into HTML5`_.
Not all of them are supported in browsers yet, however, so use caution.
.. _Dive Into HTML5: https://diveintohtml5.info/
What should be used?
--------------------
Currently, the answer is HTML5. There are very few reasons to use XHTML
considering the latest developments in Web browsers. To summarize the
reasons given above:
- Internet Explorer has poor support for XHTML.
- Many JavaScript libraries also do not support XHTML, due to the more
complicated namespacing API it requires.
- HTML5 adds several new features, including semantic tags and the
long-awaited ``<audio>`` and ``<video>`` tags.
- It has the support of most browser vendors behind it.
- It is much easier to write, and more compact.
For most applications, it is undoubtedly better to use HTML5 than XHTML.

View file

@ -3,12 +3,15 @@
Welcome to Flask
================
.. image:: _static/flask-logo.png
:alt: Flask: web development, one drop at a time
.. image:: _static/flask-name.svg
:align: center
:target: https://palletsprojects.com/p/flask/
:height: 200px
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
more detailed :doc:`tutorial/index` that shows how to create a small but
complete application with Flask. Common patterns are described in the
@ -16,28 +19,26 @@ complete application with Flask. Common patterns are described in the
component of Flask in detail, with a full reference in the :doc:`api`
section.
Flask depends on the `Jinja`_ template engine and the `Werkzeug`_ WSGI
toolkit. The documentation for these libraries can be found at:
Flask depends on the `Werkzeug`_ WSGI toolkit, the `Jinja`_ template engine, and the
`Click`_ CLI toolkit. Be sure to check their documentation as well as Flask's when
looking for information.
- `Jinja documentation <https://jinja.palletsprojects.com/>`_
- `Werkzeug documentation <https://werkzeug.palletsprojects.com/>`_
.. _Jinja: https://www.palletsprojects.com/p/jinja/
.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/
.. _Werkzeug: https://werkzeug.palletsprojects.com
.. _Jinja: https://jinja.palletsprojects.com
.. _Click: https://click.palletsprojects.com
User's Guide
------------
This part of the documentation, which is mostly prose, begins with some
background information about Flask, then focuses on step-by-step
instructions for web development with Flask.
Flask provides configuration and conventions, with sensible defaults, to get started.
This section of the documentation explains the different parts of the Flask framework
and how they can be used, customized, and extended. Beyond Flask itself, look for
community-maintained extensions to add even more functionality.
.. toctree::
:maxdepth: 2
foreword
advanced_foreword
installation
quickstart
tutorial/index
@ -49,15 +50,17 @@ instructions for web development with Flask.
config
signals
views
lifecycle
appcontext
reqcontext
blueprints
extensions
cli
server
shell
patterns/index
web-security
deploying/index
gevent
async-await
@ -76,14 +79,10 @@ method, this part of the documentation is for you.
Additional Notes
----------------
Design notes, legal information and changelog are here for the interested.
.. toctree::
:maxdepth: 2
design
htmlfaq
security
extensiondev
contributing
license

View file

@ -5,8 +5,7 @@ Installation
Python Version
--------------
We recommend using the latest version of Python. Flask supports Python
3.7 and newer.
We recommend using the latest version of Python. Flask supports Python 3.10 and newer.
Dependencies
@ -24,12 +23,14 @@ These distributions will be installed automatically when installing Flask.
to protect Flask's session cookie.
* `Click`_ is a framework for writing command line applications. It provides
the ``flask`` command and allows adding custom management commands.
* `Blinker`_ provides support for :doc:`signals`.
.. _Werkzeug: https://palletsprojects.com/p/werkzeug/
.. _Jinja: https://palletsprojects.com/p/jinja/
.. _MarkupSafe: https://palletsprojects.com/p/markupsafe/
.. _ItsDangerous: https://palletsprojects.com/p/itsdangerous/
.. _Click: https://palletsprojects.com/p/click/
.. _Blinker: https://blinker.readthedocs.io/
Optional dependencies
@ -38,13 +39,11 @@ Optional dependencies
These distributions will not be installed automatically. Flask will detect and
use them if you install them.
* `Blinker`_ provides support for :doc:`signals`.
* `python-dotenv`_ enables support for :ref:`dotenv` when running ``flask``
commands.
* `Watchdog`_ provides a faster, more efficient reloader for the development
server.
.. _Blinker: https://pythonhosted.org/blinker/
.. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
.. _watchdog: https://pythonhosted.org/watchdog/
@ -52,9 +51,8 @@ use them if you install them.
greenlet
~~~~~~~~
You may choose to use gevent or eventlet with your application. In this
case, greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is
required.
You may choose to use :doc:`/gevent` with your application. In this case,
greenlet>=1.0 is required. When using PyPy, PyPy>=7.3.7 is required.
These are not minimum supported versions, they only indicate the first
versions that added necessary features. You should use the latest
@ -85,7 +83,7 @@ environments.
Create an environment
~~~~~~~~~~~~~~~~~~~~~
Create a project folder and a :file:`venv` folder within:
Create a project folder and a :file:`.venv` folder within:
.. tabs::
@ -95,7 +93,7 @@ Create a project folder and a :file:`venv` folder within:
$ mkdir myproject
$ cd myproject
$ python3 -m venv venv
$ python3 -m venv .venv
.. group-tab:: Windows
@ -103,7 +101,7 @@ Create a project folder and a :file:`venv` folder within:
> mkdir myproject
> cd myproject
> py -3 -m venv venv
> py -3 -m venv .venv
.. _install-activate-env:
@ -119,13 +117,13 @@ Before you work on your project, activate the corresponding environment:
.. code-block:: text
$ . venv/bin/activate
$ . .venv/bin/activate
.. group-tab:: Windows
.. code-block:: text
> venv\Scripts\activate
> .venv\Scripts\activate
Your shell prompt will change to show the name of the activated
environment.

View file

@ -1,19 +1,5 @@
License
=======
BSD-3-Clause License
====================
BSD-3-Clause Source License
---------------------------
The BSD-3-Clause license applies to all files in the Flask repository
and source distribution. This includes Flask's source code, the
examples, and tests, as well as the documentation.
.. include:: ../LICENSE.rst
Artwork License
---------------
This license applies to Flask's logo.
.. include:: ../artwork/LICENSE.rst
.. literalinclude:: ../LICENSE.txt
:language: text

171
docs/lifecycle.rst Normal file
View file

@ -0,0 +1,171 @@
Application Structure and Lifecycle
===================================
Flask makes it pretty easy to write a web application. But there are quite a few
different parts to an application and to each request it handles. Knowing what happens
during application setup, serving, and handling requests will help you know what's
possible in Flask and how to structure your application.
Application Setup
-----------------
The first step in creating a Flask application is creating the application object. Each
Flask application is an instance of the :class:`.Flask` class, which collects all
configuration, extensions, and views.
.. code-block:: python
from flask import Flask
app = Flask(__name__)
app.config.from_mapping(
SECRET_KEY="dev",
)
app.config.from_prefixed_env()
@app.route("/")
def index():
return "Hello, World!"
This is known as the "application setup phase", it's the code you write that's outside
any view functions or other handlers. It can be split up between different modules and
sub-packages, but all code that you want to be part of your application must be imported
in order for it to be registered.
All application setup must be completed before you start serving your application and
handling requests. This is because WSGI servers divide work between multiple workers, or
can be distributed across multiple machines. If the configuration changed in one worker,
there's no way for Flask to ensure consistency between other workers.
Flask tries to help developers catch some of these setup ordering issues by showing an
error if setup-related methods are called after requests are handled. In that case
you'll see this error:
The setup method 'route' can no longer be called on the application. It has already
handled its first request, any changes will not be applied consistently.
Make sure all imports, decorators, functions, etc. needed to set up the application
are done before running it.
However, it is not possible for Flask to detect all cases of out-of-order setup. In
general, don't do anything to modify the ``Flask`` app object and ``Blueprint`` objects
from within view functions that run during requests. This includes:
- Adding routes, view functions, and other request handlers with ``@app.route``,
``@app.errorhandler``, ``@app.before_request``, etc.
- Registering blueprints.
- Loading configuration with ``app.config``.
- Setting up the Jinja template environment with ``app.jinja_env``.
- Setting a session interface, instead of the default itsdangerous cookie.
- Setting a JSON provider with ``app.json``, instead of the default provider.
- Creating and initializing Flask extensions.
Serving the Application
-----------------------
Flask is a WSGI application framework. The other half of WSGI is the WSGI server. During
development, Flask, through Werkzeug, provides a development WSGI server with the
``flask run`` CLI command. When you are done with development, use a production server
to serve your application, see :doc:`deploying/index`.
Regardless of what server you're using, it will follow the :pep:`3333` WSGI spec. The
WSGI server will be told how to access your Flask application object, which is the WSGI
application. Then it will start listening for HTTP requests, translate the request data
into a WSGI environ, and call the WSGI application with that data. The WSGI application
will return data that is translated into an HTTP response.
#. Browser or other client makes HTTP request.
#. WSGI server receives request.
#. WSGI server converts HTTP data to WSGI ``environ`` dict.
#. WSGI server calls WSGI application with the ``environ``.
#. Flask, the WSGI application, does all its internal processing to route the request
to a view function, handle errors, etc.
#. Flask translates View function return into WSGI response data, passes it to WSGI
server.
#. WSGI server creates and send an HTTP response.
#. Client receives the HTTP response.
Middleware
~~~~~~~~~~
The WSGI application above is a callable that behaves in a certain way. Middleware
is a WSGI application that wraps another WSGI application. It's a similar concept to
Python decorators. The outermost middleware will be called by the server. It can modify
the data passed to it, then call the WSGI application (or further middleware) that it
wraps, and so on. And it can take the return value of that call and modify it further.
From the WSGI server's perspective, there is one WSGI application, the one it calls
directly. Typically, Flask is the "real" application at the end of the chain of
middleware. But even Flask can call further WSGI applications, although that's an
advanced, uncommon use case.
A common middleware you'll see used with Flask is Werkzeug's
:class:`~werkzeug.middleware.proxy_fix.ProxyFix`, which modifies the request to look
like it came directly from a client even if it passed through HTTP proxies on the way.
There are other middleware that can handle serving static files, authentication, etc.
How a Request is Handled
------------------------
For us, the interesting part of the steps above is when Flask gets called by the WSGI
server (or middleware). At that point, it will do quite a lot to handle the request and
generate the response. At the most basic, it will match the URL to a view function, call
the view function, and pass the return value back to the server. But there are many more
parts that you can use to customize its behavior.
#. WSGI server calls the Flask object, which calls :meth:`.Flask.wsgi_app`.
#. An :class:`.AppContext` object is created. This converts the WSGI ``environ``
dict into a :class:`.Request` object.
#. The :doc:`app context <appcontext>` is pushed, which makes
:data:`.current_app`, :data:`.g`, :data:`.request`, and :data:`.session`
available.
#. The :data:`.appcontext_pushed` signal is sent.
#. The URL is matched against the URL rules registered with the :meth:`~.Flask.route`
decorator during application setup. If there is no match, the error - usually a 404,
405, or redirect - is stored to be handled later.
#. The :data:`.request_started` signal is sent.
#. Any :meth:`~.Flask.url_value_preprocessor` decorated functions are called.
#. Any :meth:`~.Flask.before_request` decorated functions are called. If any of
these function returns a value it is treated as the response immediately.
#. If the URL didn't match a route a few steps ago, that error is raised now.
#. The :meth:`~.Flask.route` decorated view function associated with the matched URL
is called and returns a value to be used as the response.
#. If any step so far raised an exception, and there is an :meth:`~.Flask.errorhandler`
decorated function that matches the exception class or HTTP error code, it is
called to handle the error and return a response.
#. Whatever returned a response value - a before request function, the view, or an
error handler, that value is converted to a :class:`.Response` object.
#. Any :func:`~.after_this_request` decorated functions are called, which can modify
the response object. They are then cleared.
#. Any :meth:`~.Flask.after_request` decorated functions are called, which can modify
the response object.
#. The session is saved, persisting any modified session data using the app's
:attr:`~.Flask.session_interface`.
#. The :data:`.request_finished` signal is sent.
#. If any step so far raised an exception, and it was not handled by an error handler
function, it is handled now. HTTP exceptions are treated as responses with their
corresponding status code, other exceptions are converted to a generic 500 response.
The :data:`.got_request_exception` signal is sent.
#. The response object's status, headers, and body are returned to the WSGI server.
#. Any :meth:`~.Flask.teardown_request` decorated functions are called.
#. The :data:`.request_tearing_down` signal is sent.
#. Any :meth:`~.Flask.teardown_appcontext` decorated functions are called.
#. The :data:`.appcontext_tearing_down` signal is sent.
#. The app context is popped, :data:`.current_app`, :data:`.g`, :data:`.request`,
and :data:`.session` are no longer available.
#. The :data:`.appcontext_popped` signal is sent.
When executing a CLI command or plain app context without request data, the same
order of steps is followed, omitting the steps that refer to the request.
A :class:`Blueprint` can add handlers for these events that are specific to the
blueprint. The handlers for a blueprint will run if the blueprint
owns the route that matches the request.
There are even more decorators and customization points than this, but that aren't part
of every request lifecycle. They're more specific to certain things you might use during
a request, such as templates, building URLs, or handling JSON data. See the rest of this
documentation, as well as the :doc:`api` to explore further.

View file

@ -159,7 +159,7 @@ Depending on your project, it may be more useful to configure each logger you
care about separately, instead of configuring only the root logger. ::
for logger in (
app.logger,
logging.getLogger(app.name),
logging.getLogger('sqlalchemy'),
logging.getLogger('other_package'),
):

View file

@ -18,34 +18,20 @@ Working with this Document
--------------------------
Each of the techniques and examples below results in an ``application``
object that can be run with any WSGI server. For production, see
:doc:`/deploying/index`. For development, Werkzeug provides a server
through :func:`werkzeug.serving.run_simple`::
object that can be run with any WSGI server. For development, use the
``flask run`` command to start a development server. For production, see
:doc:`/deploying/index`.
from werkzeug.serving import run_simple
run_simple('localhost', 5000, application, use_reloader=True)
Note that :func:`run_simple <werkzeug.serving.run_simple>` is not intended for
use in production. Use a production WSGI server. See :doc:`/deploying/index`.
In order to use the interactive debugger, debugging must be enabled both on
the application and the simple server. Here is the "hello world" example with
debugging and :func:`run_simple <werkzeug.serving.run_simple>`::
.. code-block:: python
from flask import Flask
from werkzeug.serving import run_simple
app = Flask(__name__)
app.debug = True
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
run_simple('localhost', 5000, app,
use_reloader=True, use_debugger=True, use_evalex=True)
Combining Applications
----------------------
@ -58,7 +44,9 @@ are combined by the dispatcher middleware into a larger one that is
dispatched based on prefix.
For example you could have your main application run on ``/`` and your
backend interface on ``/backend``::
backend interface on ``/backend``.
.. code-block:: python
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from frontend_app import application as frontend
@ -89,11 +77,13 @@ the dynamic application creation.
The perfect level for abstraction in that regard is the WSGI layer. You
write your own WSGI application that looks at the request that comes and
delegates it to your Flask application. If that application does not
exist yet, it is dynamically created and remembered::
exist yet, it is dynamically created and remembered.
.. code-block:: python
from threading import Lock
class SubdomainDispatcher(object):
class SubdomainDispatcher:
def __init__(self, domain, create_app):
self.domain = domain
@ -117,7 +107,9 @@ exist yet, it is dynamically created and remembered::
return app(environ, start_response)
This dispatcher can then be used like this::
This dispatcher can then be used like this:
.. code-block:: python
from myapplication import create_app, get_user_for_subdomain
from werkzeug.exceptions import NotFound
@ -143,12 +135,14 @@ Dispatch by Path
Dispatching by a path on the URL is very similar. Instead of looking at
the ``Host`` header to figure out the subdomain one simply looks at the
request path up to the first slash::
request path up to the first slash.
.. code-block:: python
from threading import Lock
from werkzeug.wsgi import pop_path_info, peek_path_info
from wsgiref.util import shift_path_info
class PathDispatcher(object):
class PathDispatcher:
def __init__(self, default_app, create_app):
self.default_app = default_app
@ -166,15 +160,24 @@ request path up to the first slash::
return app
def __call__(self, environ, start_response):
app = self.get_application(peek_path_info(environ))
app = self.get_application(_peek_path_info(environ))
if app is not None:
pop_path_info(environ)
shift_path_info(environ)
else:
app = self.default_app
return app(environ, start_response)
def _peek_path_info(environ):
segments = environ.get("PATH_INFO", "").lstrip("/").split("/", 1)
if segments:
return segments[0]
return None
The big difference between this and the subdomain one is that this one
falls back to another application if the creator function returns ``None``::
falls back to another application if the creator function returns ``None``.
.. code-block:: python
from myapplication import create_app, default_app, get_user_for_prefix

View file

@ -89,71 +89,20 @@ Using Applications
To run such an application, you can use the :command:`flask` command:
.. tabs::
.. code-block:: text
.. group-tab:: Bash
$ flask --app hello run
.. code-block:: text
Flask will automatically detect the factory if it is named
``create_app`` or ``make_app`` in ``hello``. You can also pass arguments
to the factory like this:
$ export FLASK_APP=myapp
$ flask run
.. code-block:: text
.. group-tab:: Fish
$ flask --app 'hello:create_app(local_auth=True)' run
.. code-block:: text
$ set -x FLASK_APP myapp
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=myapp
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "myapp"
> flask run
Flask will automatically detect the factory (``create_app`` or ``make_app``)
in ``myapp``. You can also pass arguments to the factory like this:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP="myapp:create_app('dev')"
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP "myapp:create_app('dev')"
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP="myapp:create_app('dev')"
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "myapp:create_app('dev')"
> flask run
Then the ``create_app`` factory in ``myapp`` is called with the string
``'dev'`` as the argument. See :doc:`/cli` for more detail.
Then the ``create_app`` factory in ``hello`` is called with the keyword
argument ``local_auth=True``. See :doc:`/cli` for more detail.
Factory Improvements
--------------------

View file

@ -1,105 +1,242 @@
Celery Background Tasks
=======================
Background Tasks with Celery
============================
If your application has a long running task, such as processing some uploaded
data or sending email, you don't want to wait for it to finish during a
request. Instead, use a task queue to send the necessary data to another
process that will run the task in the background while the request returns
immediately.
If your application has a long running task, such as processing some uploaded data or
sending email, you don't want to wait for it to finish during a request. Instead, use a
task queue to send the necessary data to another process that will run the task in the
background while the request returns immediately.
`Celery`_ is a powerful task queue that can be used for simple background tasks as well
as complex multi-stage programs and schedules. This guide will show you how to configure
Celery using Flask. Read Celery's `First Steps with Celery`_ guide to learn how to use
Celery itself.
.. _Celery: https://celery.readthedocs.io
.. _First Steps with Celery: https://celery.readthedocs.io/en/latest/getting-started/first-steps-with-celery.html
The Flask repository contains `an example <https://github.com/pallets/flask/tree/main/examples/celery>`_
based on the information on this page, which also shows how to use JavaScript to submit
tasks and poll for progress and results.
Celery is a powerful task queue that can be used for simple background tasks
as well as complex multi-stage programs and schedules. This guide will show you
how to configure Celery using Flask, but assumes you've already read the
`First Steps with Celery <https://celery.readthedocs.io/en/latest/getting-started/first-steps-with-celery.html>`_
guide in the Celery documentation.
Install
-------
Celery is a separate Python package. Install it from PyPI using pip::
Install Celery from PyPI, for example using pip:
.. code-block:: text
$ pip install celery
Configure
---------
The first thing you need is a Celery instance, this is called the celery
application. It serves the same purpose as the :class:`~flask.Flask`
object in Flask, just for Celery. Since this instance is used as the
entry-point for everything you want to do in Celery, like creating tasks
and managing workers, it must be possible for other modules to import it.
Integrate Celery with Flask
---------------------------
For instance you can place this in a ``tasks`` module. While you can use
Celery without any reconfiguration with Flask, it becomes a bit nicer by
subclassing tasks and adding support for Flask's application contexts and
hooking it up with the Flask configuration.
You can use Celery without any integration with Flask, but it's convenient to configure
it through Flask's config, and to let tasks access the Flask application.
This is all that is necessary to integrate Celery with Flask:
Celery uses similar ideas to Flask, with a ``Celery`` app object that has configuration
and registers tasks. While creating a Flask app, use the following code to create and
configure a Celery app as well.
.. code-block:: python
from celery import Celery
from celery import Celery, Task
def make_celery(app):
celery = Celery(app.import_name)
celery.conf.update(app.config["CELERY_CONFIG"])
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
def celery_init_app(app: Flask) -> Celery:
class FlaskTask(Task):
def __call__(self, *args: object, **kwargs: object) -> object:
with app.app_context():
return self.run(*args, **kwargs)
celery.Task = ContextTask
return celery
celery_app = Celery(app.name, task_cls=FlaskTask)
celery_app.config_from_object(app.config["CELERY"])
celery_app.set_default()
app.extensions["celery"] = celery_app
return celery_app
The function creates a new Celery object, configures it with the broker
from the application config, updates the rest of the Celery config from
the Flask config and then creates a subclass of the task that wraps the
task execution in an application context.
This creates and returns a ``Celery`` app object. Celery `configuration`_ is taken from
the ``CELERY`` key in the Flask configuration. The Celery app is set as the default, so
that it is seen during each request. The ``Task`` subclass automatically runs task
functions with a Flask app context active, so that services like your database
connections are available.
.. note::
Celery 5.x deprecated uppercase configuration keys, and 6.x will
remove them. See their official `migration guide`_.
.. _configuration: https://celery.readthedocs.io/en/stable/userguide/configuration.html
.. _migration guide: https://docs.celeryproject.org/en/stable/userguide/configuration.html#conf-old-settings-map.
Here's a basic ``example.py`` that configures Celery to use Redis for communication. We
enable a result backend, but ignore results by default. This allows us to store results
only for tasks where we care about the result.
An example task
---------------
Let's write a task that adds two numbers together and returns the result. We
configure Celery's broker and backend to use Redis, create a ``celery``
application using the factory from above, and then use it to define the task. ::
.. code-block:: python
from flask import Flask
flask_app = Flask(__name__)
flask_app.config.update(CELERY_CONFIG={
'broker_url': 'redis://localhost:6379',
'result_backend': 'redis://localhost:6379',
})
celery = make_celery(flask_app)
app = Flask(__name__)
app.config.from_mapping(
CELERY=dict(
broker_url="redis://localhost",
result_backend="redis://localhost",
task_ignore_result=True,
),
)
celery_app = celery_init_app(app)
@celery.task()
def add_together(a, b):
Point the ``celery worker`` command at this and it will find the ``celery_app`` object.
.. code-block:: text
$ celery -A example worker --loglevel INFO
You can also run the ``celery beat`` command to run tasks on a schedule. See Celery's
docs for more information about defining schedules.
.. code-block:: text
$ celery -A example beat --loglevel INFO
Application Factory
-------------------
When using the Flask application factory pattern, call the ``celery_init_app`` function
inside the factory. It sets ``app.extensions["celery"]`` to the Celery app object, which
can be used to get the Celery app from the Flask app returned by the factory.
.. code-block:: python
def create_app() -> Flask:
app = Flask(__name__)
app.config.from_mapping(
CELERY=dict(
broker_url="redis://localhost",
result_backend="redis://localhost",
task_ignore_result=True,
),
)
app.config.from_prefixed_env()
celery_init_app(app)
return app
To use ``celery`` commands, Celery needs an app object, but that's no longer directly
available. Create a ``make_celery.py`` file that calls the Flask app factory and gets
the Celery app from the returned Flask app.
.. code-block:: python
from example import create_app
flask_app = create_app()
celery_app = flask_app.extensions["celery"]
Point the ``celery`` command to this file.
.. code-block:: text
$ celery -A make_celery worker --loglevel INFO
$ celery -A make_celery beat --loglevel INFO
Defining Tasks
--------------
Using ``@celery_app.task`` to decorate task functions requires access to the
``celery_app`` object, which won't be available when using the factory pattern. It also
means that the decorated tasks are tied to the specific Flask and Celery app instances,
which could be an issue during testing if you change configuration for a test.
Instead, use Celery's ``@shared_task`` decorator. This creates task objects that will
access whatever the "current app" is, which is a similar concept to Flask's blueprints
and app context. This is why we called ``celery_app.set_default()`` above.
Here's an example task that adds two numbers together and returns the result.
.. code-block:: python
from celery import shared_task
@shared_task(ignore_result=False)
def add_together(a: int, b: int) -> int:
return a + b
This task can now be called in the background::
Earlier, we configured Celery to ignore task results by default. Since we want to know
the return value of this task, we set ``ignore_result=False``. On the other hand, a task
that didn't need a result, such as sending an email, wouldn't set this.
result = add_together.delay(23, 42)
result.wait() # 65
Run a worker
------------
Calling Tasks
-------------
If you jumped in and already executed the above code you will be
disappointed to learn that ``.wait()`` will never actually return.
That's because you also need to run a Celery worker to receive and execute the
task. ::
The decorated function becomes a task object with methods to call it in the background.
The simplest way is to use the ``delay(*args, **kwargs)`` method. See Celery's docs for
more methods.
$ celery -A your_application.celery worker
A Celery worker must be running to run the task. Starting a worker is shown in the
previous sections.
The ``your_application`` string has to point to your application's package
or module that creates the ``celery`` object.
.. code-block:: python
Now that the worker is running, ``wait`` will return the result once the task
is finished.
from flask import request
@app.post("/add")
def start_add() -> dict[str, object]:
a = request.form.get("a", type=int)
b = request.form.get("b", type=int)
result = add_together.delay(a, b)
return {"result_id": result.id}
The route doesn't get the task's result immediately. That would defeat the purpose by
blocking the response. Instead, we return the running task's result id, which we can use
later to get the result.
Getting Results
---------------
To fetch the result of the task we started above, we'll add another route that takes the
result id we returned before. We return whether the task is finished (ready), whether it
finished successfully, and what the return value (or error) was if it is finished.
.. code-block:: python
from celery.result import AsyncResult
@app.get("/result/<id>")
def task_result(id: str) -> dict[str, object]:
result = AsyncResult(id)
return {
"ready": result.ready(),
"successful": result.successful(),
"value": result.result if result.ready() else None,
}
Now you can start the task using the first route, then poll for the result using the
second route. This keeps the Flask request workers from being blocked waiting for tasks
to finish.
The Flask repository contains `an example <https://github.com/pallets/flask/tree/main/examples/celery>`_
using JavaScript to submit tasks and poll for progress and results.
Passing Data to Tasks
---------------------
The "add" task above took two integers as arguments. To pass arguments to tasks, Celery
has to serialize them to a format that it can pass to other processes. Therefore,
passing complex objects is not recommended. For example, it would be impossible to pass
a SQLAlchemy model object, since that object is probably not serializable and is tied to
the session that queried it.
Pass the minimal amount of data necessary to fetch or recreate any complex data within
the task. Consider a task that will run when the logged in user asks for an archive of
their data. The Flask request knows the logged in user, and has the user object queried
from the database. It got that by querying the database for a given id, so the task can
do the same thing. Pass the user's id rather than the user object.
.. code-block:: python
@shared_task
def generate_user_archive(user_id: str) -> None:
user = db.session.get(User, user_id)
...
generate_user_archive.delay(current_user.id)

View file

@ -1,170 +0,0 @@
Deploying with Setuptools
=========================
`Setuptools`_, is an extension library that is commonly used to
distribute Python libraries and extensions. It extends distutils, a basic
module installation system shipped with Python to also support various more
complex constructs that make larger applications easier to distribute:
- **support for dependencies**: a library or application can declare a
list of other libraries it depends on which will be installed
automatically for you.
- **package registry**: setuptools registers your package with your
Python installation. This makes it possible to query information
provided by one package from another package. The best known feature of
this system is the entry point support which allows one package to
declare an "entry point" that another package can hook into to extend the
other package.
- **installation manager**: :command:`pip` can install other libraries for you.
Flask itself, and all the libraries you can find on PyPI are distributed with
either setuptools or distutils.
In this case we assume your application is called
:file:`yourapplication.py` and you are not using a module, but a
package. If you have not yet converted your application into a package,
head over to :doc:`packages` to see how this can be done.
A working deployment with setuptools is the first step into more complex
and more automated deployment scenarios. If you want to fully automate
the process, also read the :doc:`fabric` chapter.
Basic Setup Script
------------------
Because you have Flask installed, you have setuptools available on your system.
Flask already depends upon setuptools.
Standard disclaimer applies: :ref:`use a virtualenv
<install-create-env>`.
Your setup code always goes into a file named :file:`setup.py` next to your
application. The name of the file is only convention, but because
everybody will look for a file with that name, you better not change it.
A basic :file:`setup.py` file for a Flask application looks like this::
from setuptools import setup
setup(
name='Your Application',
version='1.0',
long_description=__doc__,
packages=['yourapplication'],
include_package_data=True,
zip_safe=False,
install_requires=['Flask']
)
Please keep in mind that you have to list subpackages explicitly. If you
want setuptools to lookup the packages for you automatically, you can use
the ``find_packages`` function::
from setuptools import setup, find_packages
setup(
...
packages=find_packages()
)
Most parameters to the ``setup`` function should be self explanatory,
``include_package_data`` and ``zip_safe`` might not be.
``include_package_data`` tells setuptools to look for a :file:`MANIFEST.in` file
and install all the entries that match as package data. We will use this
to distribute the static files and templates along with the Python module
(see :ref:`distributing-resources`). The ``zip_safe`` flag can be used to
force or prevent zip Archive creation. In general you probably don't want
your packages to be installed as zip files because some tools do not
support them and they make debugging a lot harder.
Tagging Builds
--------------
It is useful to distinguish between release and development builds. Add a
:file:`setup.cfg` file to configure these options. ::
[egg_info]
tag_build = .dev
tag_date = 1
[aliases]
release = egg_info -Db ''
Running ``python setup.py sdist`` will create a development package
with ".dev" and the current date appended: ``flaskr-1.0.dev20160314.tar.gz``.
Running ``python setup.py release sdist`` will create a release package
with only the version: ``flaskr-1.0.tar.gz``.
.. _distributing-resources:
Distributing Resources
----------------------
If you try to install the package you just created, you will notice that
folders like :file:`static` or :file:`templates` are not installed for you. The
reason for this is that setuptools does not know which files to add for
you. What you should do, is to create a :file:`MANIFEST.in` file next to your
:file:`setup.py` file. This file lists all the files that should be added to
your tarball::
recursive-include yourapplication/templates *
recursive-include yourapplication/static *
Don't forget that even if you enlist them in your :file:`MANIFEST.in` file, they
won't be installed for you unless you set the `include_package_data`
parameter of the ``setup`` function to ``True``!
Declaring Dependencies
----------------------
Dependencies are declared in the ``install_requires`` parameter as a list.
Each item in that list is the name of a package that should be pulled from
PyPI on installation. By default it will always use the most recent
version, but you can also provide minimum and maximum version
requirements. Here some examples::
install_requires=[
'Flask>=0.2',
'SQLAlchemy>=0.6',
'BrokenPackage>=0.7,<=1.0'
]
As mentioned earlier, dependencies are pulled from PyPI. What if you
want to depend on a package that cannot be found on PyPI and won't be
because it is an internal package you don't want to share with anyone?
Just do it as if there was a PyPI entry and provide a list of
alternative locations where setuptools should look for tarballs::
dependency_links=['http://example.com/yourfiles']
Make sure that page has a directory listing and the links on the page are
pointing to the actual tarballs with their correct filenames as this is
how setuptools will find the files. If you have an internal company
server that contains the packages, provide the URL to that server.
Installing / Developing
-----------------------
To install your application (ideally into a virtualenv) just run the
:file:`setup.py` script with the ``install`` parameter. It will install your
application into the virtualenv's site-packages folder and also download
and install all dependencies::
$ python setup.py install
If you are developing on the package and also want the requirements to be
installed, you can use the ``develop`` command instead::
$ python setup.py develop
This has the advantage of just installing a link to the site-packages
folder instead of copying the data over. You can then continue to work on
the code without having to run ``install`` again after each change.
.. _pip: https://pypi.org/project/pip/
.. _Setuptools: https://pypi.org/project/setuptools/

View file

@ -1,184 +0,0 @@
Deploying with Fabric
=====================
`Fabric`_ is a tool for Python similar to Makefiles but with the ability
to execute commands on a remote server. In combination with a properly
set up Python package (:doc:`packages`) and a good concept for
configurations (:doc:`/config`) it is very easy to deploy Flask
applications to external servers.
Before we get started, here a quick checklist of things we have to ensure
upfront:
- Fabric 1.0 has to be installed locally. This tutorial assumes the
latest version of Fabric.
- The application already has to be a package and requires a working
:file:`setup.py` file (:doc:`distribute`).
- In the following example we are using `mod_wsgi` for the remote
servers. You can of course use your own favourite server there, but
for this example we chose Apache + `mod_wsgi` because it's very easy
to setup and has a simple way to reload applications without root
access.
Creating the first Fabfile
--------------------------
A fabfile is what controls what Fabric executes. It is named :file:`fabfile.py`
and executed by the `fab` command. All the functions defined in that file
will show up as `fab` subcommands. They are executed on one or more
hosts. These hosts can be defined either in the fabfile or on the command
line. In this case we will add them to the fabfile.
This is a basic first example that has the ability to upload the current
source code to the server and install it into a pre-existing
virtual environment::
from fabric.api import *
# the user to use for the remote commands
env.user = 'appuser'
# the servers where the commands are executed
env.hosts = ['server1.example.com', 'server2.example.com']
def pack():
# build the package
local('python setup.py sdist --formats=gztar', capture=False)
def deploy():
# figure out the package name and version
dist = local('python setup.py --fullname', capture=True).strip()
filename = f'{dist}.tar.gz'
# upload the package to the temporary folder on the server
put(f'dist/{filename}', f'/tmp/{filename}')
# install the package in the application's virtualenv with pip
run(f'/var/www/yourapplication/env/bin/pip install /tmp/{filename}')
# remove the uploaded package
run(f'rm -r /tmp/{filename}')
# touch the .wsgi file to trigger a reload in mod_wsgi
run('touch /var/www/yourapplication.wsgi')
Running Fabfiles
----------------
Now how do you execute that fabfile? You use the `fab` command. To
deploy the current version of the code on the remote server you would use
this command::
$ fab pack deploy
However this requires that our server already has the
:file:`/var/www/yourapplication` folder created and
:file:`/var/www/yourapplication/env` to be a virtual environment. Furthermore
are we not creating the configuration or ``.wsgi`` file on the server. So
how do we bootstrap a new server into our infrastructure?
This now depends on the number of servers we want to set up. If we just
have one application server (which the majority of applications will
have), creating a command in the fabfile for this is overkill. But
obviously you can do that. In that case you would probably call it
`setup` or `bootstrap` and then pass the servername explicitly on the
command line::
$ fab -H newserver.example.com bootstrap
To setup a new server you would roughly do these steps:
1. Create the directory structure in :file:`/var/www`::
$ mkdir /var/www/yourapplication
$ cd /var/www/yourapplication
$ virtualenv --distribute env
2. Upload a new :file:`application.wsgi` file to the server and the
configuration file for the application (eg: :file:`application.cfg`)
3. Create a new Apache config for ``yourapplication`` and activate it.
Make sure to activate watching for changes of the ``.wsgi`` file so
that we can automatically reload the application by touching it.
See :doc:`/deploying/mod_wsgi`.
So now the question is, where do the :file:`application.wsgi` and
:file:`application.cfg` files come from?
The WSGI File
-------------
The WSGI file has to import the application and also to set an environment
variable so that the application knows where to look for the config. This
is a short example that does exactly that::
import os
os.environ['YOURAPPLICATION_CONFIG'] = '/var/www/yourapplication/application.cfg'
from yourapplication import app
The application itself then has to initialize itself like this to look for
the config at that environment variable::
app = Flask(__name__)
app.config.from_object('yourapplication.default_config')
app.config.from_envvar('YOURAPPLICATION_CONFIG')
This approach is explained in detail in the :doc:`/config` section of the
documentation.
The Configuration File
----------------------
Now as mentioned above, the application will find the correct
configuration file by looking up the ``YOURAPPLICATION_CONFIG`` environment
variable. So we have to put the configuration in a place where the
application will able to find it. Configuration files have the unfriendly
quality of being different on all computers, so you do not version them
usually.
A popular approach is to store configuration files for different servers
in a separate version control repository and check them out on all
servers. Then symlink the file that is active for the server into the
location where it's expected (eg: :file:`/var/www/yourapplication`).
Either way, in our case here we only expect one or two servers and we can
upload them ahead of time by hand.
First Deployment
----------------
Now we can do our first deployment. We have set up the servers so that
they have their virtual environments and activated apache configs. Now we
can pack up the application and deploy it::
$ fab pack deploy
Fabric will now connect to all servers and run the commands as written
down in the fabfile. First it will execute pack so that we have our
tarball ready and then it will execute deploy and upload the source code
to all servers and install it there. Thanks to the :file:`setup.py` file we
will automatically pull in the required libraries into our virtual
environment.
Next Steps
----------
From that point onwards there is so much that can be done to make
deployment actually fun:
- Create a `bootstrap` command that initializes new servers. It could
initialize a new virtual environment, setup apache appropriately etc.
- Put configuration files into a separate version control repository
and symlink the active configs into place.
- You could also put your application code into a repository and check
out the latest version on the server and then install. That way you
can also easily go back to older versions.
- hook in testing functionality so that you can deploy to an external
server and run the test suite.
Working with Fabric is fun and you will notice that it's quite magical to
type ``fab deploy`` and see your application being deployed automatically
to one or more remote servers.
.. _Fabric: https://www.fabfile.org/

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
however your application is the root you can simply route a redirect::
app.add_url_rule('/favicon.ico',
redirect_to=url_for('static', filename='favicon.ico'))
app.add_url_rule(
"/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
using :func:`~flask.send_from_directory`::

View file

@ -19,8 +19,6 @@ collected in the following pages.
appfactories
appdispatch
urlprocessors
distribute
fabric
sqlite3
sqlalchemy
fileuploads

View file

@ -28,7 +28,7 @@ It is important to understand the difference between templates and
JavaScript. Templates are rendered on the server, before the response is
sent to the user's browser. JavaScript runs in the user's browser, after
the template is rendered and sent. Therefore, it is impossible to use
JavaScript to affect how the Jinja template is rendered, but is is
JavaScript to affect how the Jinja template is rendered, but it is
possible to render data into the JavaScript that will run.
To provide data to JavaScript when rendering the template, use the
@ -125,8 +125,8 @@ in a Flask view.
.. code-block:: javascript
let data = new FormData()
data.append("name": "Flask Room")
data.append("description": "Talk about Flask here.")
data.append("name", "Flask Room")
data.append("description", "Talk about Flask here.")
fetch(room_url, {
"method": "POST",
"body": data,
@ -136,7 +136,8 @@ In general, prefer sending request data as form data, as would be used
when submitting an HTML form. JSON can represent more complex data, but
unless you need that it's better to stick with the simpler format. When
sending JSON data, the ``Content-Type: application/json`` header must be
sent as well, otherwise Flask will return a 400 error.
sent as well, otherwise Flask will return a 415 Unsupported Media Type
error.
.. code-block:: javascript
@ -197,7 +198,7 @@ in the previous section. The following example shows how to replace a
const geology_div = getElementById("geology-fact")
fetch(geology_url)
.then(response => response.text)
.then(text => geology_div.innerHtml = text)
.then(text => geology_div.innerHTML = text)
</script>
@ -244,8 +245,9 @@ Receiving JSON in Views
Use the :attr:`~flask.Request.json` property of the
:data:`~flask.request` object to decode the request's body as JSON. If
the body is not valid JSON, or the ``Content-Type`` header is not set to
``application/json``, a 400 Bad Request error will be raised.
the body is not valid JSON, a 400 Bad Request error will be raised. If
the ``Content-Type`` header is not set to ``application/json``, a 415
Unsupported Media Type error will be raised.
.. code-block:: python

View file

@ -10,8 +10,7 @@ A running MongoDB server and `Flask-MongoEngine`_ are required. ::
pip install flask-mongoengine
.. _MongoEngine: http://mongoengine.org
.. _Flask-MongoEngine: https://flask-mongoengine.readthedocs.io
.. _Flask-MongoEngine: https://docs.mongoengine.org/projects/flask-mongoengine/en/latest/
Configuration
-------------
@ -80,7 +79,7 @@ Queries
Use the class ``objects`` attribute to make queries. A keyword argument
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
using a double-underscore. ``objects``, and queries returned by

View file

@ -42,84 +42,34 @@ You should then end up with something like that::
But how do you run your application now? The naive ``python
yourapplication/__init__.py`` will not work. Let's just say that Python
does not want modules in packages to be the startup file. But that is not
a big problem, just add a new file called :file:`setup.py` next to the inner
:file:`yourapplication` folder with the following contents::
a big problem, just add a new file called :file:`pyproject.toml` next to the inner
:file:`yourapplication` folder with the following contents:
from setuptools import setup
.. code-block:: toml
setup(
name='yourapplication',
packages=['yourapplication'],
include_package_data=True,
install_requires=[
'flask',
],
)
[project]
name = "yourapplication"
dependencies = [
"flask",
]
In order to run the application you need to export an environment variable
that tells Flask where to find the application instance:
[build-system]
requires = ["flit_core<4"]
build-backend = "flit_core.buildapi"
.. tabs::
Install your application so it is importable:
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=yourapplication
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP yourapplication
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=yourapplication
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "yourapplication"
If you are outside of the project directory make sure to provide the exact
path to your application directory. Similarly you can turn on the
development features like this:
.. tabs::
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
In order to install and run the application you need to issue the following
commands::
.. code-block:: text
$ pip install -e .
$ flask run
To use the ``flask`` command and run your application you need to set
the ``--app`` option that tells Flask where to find the application
instance:
.. code-block:: text
$ flask --app yourapplication run
What did we gain from this? Now we can restructure the application a bit
into multiple modules. The only thing you have to remember is the
@ -151,7 +101,7 @@ And this is what :file:`views.py` would look like::
You should then end up with something like that::
/yourapplication
setup.py
pyproject.toml
/yourapplication
__init__.py
views.py

View file

@ -34,8 +34,7 @@ official documentation on the `declarative`_ extension.
Here's the example :file:`database.py` module for your application::
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker, declarative_base
engine = create_engine('sqlite:////tmp/test.db')
db_session = scoped_session(sessionmaker(autocommit=False,
@ -132,9 +131,8 @@ Here is an example :file:`database.py` module for your application::
def init_db():
metadata.create_all(bind=engine)
As in the declarative approach, you need to close the session after
each request or application context shutdown. Put this into your
application module::
As in the declarative approach, you need to close the session after each app
context. Put this into your application module::
from yourapplication.database import db_session

View file

@ -1,9 +1,9 @@
Using SQLite 3 with Flask
=========================
In Flask you can easily implement the opening of database connections on
demand and closing them when the context dies (usually at the end of the
request).
You can implement a few functions to work with a SQLite connection during a
request context. The connection is created the first time it's accessed,
reused on subsequent access, until it is closed when the request context ends.
Here is a simple example of how you can use SQLite 3 with Flask::
@ -30,10 +30,6 @@ or create an application context itself. At that point the ``get_db``
function can be used to get the current database connection. Whenever the
context is destroyed the database connection will be terminated.
Note: if you use Flask 0.9 or older you need to use
``flask._app_ctx_stack.top`` instead of ``g`` as the :data:`flask.g`
object was bound to the request and not application context.
Example::
@app.route('/')

View file

@ -8,6 +8,21 @@ roundtrip to the filesystem?
The answer is by using generators and direct responses.
HTTP Response Behavior
----------------------
**Headers cannot be changed after the streaming response starts.**
When using streaming, it's important to be aware of the order than an HTTP
response is sent. All headers must be sent first, then the body. More headers
cannot be sent after the body has begun. Therefore, you must make sure all
headers are set before starting the response, outside the generator.
In particular, if the generator will access ``session``, be sure to do so in the
view as well so that the ``Vary: cookie`` header will be set. Do not modify the
session in the generator, as the ``Set-Cookie`` header will already be sent.
Basic Usage
-----------
@ -20,7 +35,7 @@ data and to then invoke that function and pass it to a response object::
def generate():
for row in iter_all_rows():
yield f"{','.join(row)}\n"
return app.response_class(generate(), mimetype='text/csv')
return generate(), {"Content-Type": "text/csv"}
Each ``yield`` expression is directly sent to the browser. Note though
that some WSGI middlewares might break streaming, so be careful there in
@ -29,52 +44,57 @@ debug environments with profilers and other things you might have enabled.
Streaming from Templates
------------------------
The Jinja2 template engine also supports rendering templates piece by
piece. This functionality is not directly exposed by Flask because it is
quite uncommon, but you can easily do it yourself::
The Jinja template engine supports rendering a template piece by
piece, returning an iterator of strings. Flask provides the
:func:`~flask.stream_template` and :func:`~flask.stream_template_string`
functions to make this easier to use.
def stream_template(template_name, **context):
app.update_template_context(context)
t = app.jinja_env.get_template(template_name)
rv = t.stream(context)
rv.enable_buffering(5)
return rv
.. code-block:: python
@app.route('/my-large-page.html')
def render_large_template():
rows = iter_all_rows()
return app.response_class(stream_template('the_template.html', rows=rows))
from flask import stream_template
@app.get("/timeline")
def timeline():
return stream_template("timeline.html")
The parts yielded by the render stream tend to match statement blocks in
the template.
The trick here is to get the template object from the Jinja2 environment
on the application and to call :meth:`~jinja2.Template.stream` instead of
:meth:`~jinja2.Template.render` which returns a stream object instead of a
string. Since we're bypassing the Flask template render functions and
using the template object itself we have to make sure to update the render
context ourselves by calling :meth:`~flask.Flask.update_template_context`.
The template is then evaluated as the stream is iterated over. Since each
time you do a yield the server will flush the content to the client you
might want to buffer up a few items in the template which you can do with
``rv.enable_buffering(size)``. ``5`` is a sane default.
Streaming with Context
----------------------
.. versionadded:: 0.9
The :data:`.request` proxy will not be active while the generator is
running, because the app has already returned control to the WSGI server at that
point. If you try to access ``request``, you'll get a ``RuntimeError``.
Note that when you stream data, the request context is already gone the
moment the function executes. Flask 0.9 provides you with a helper that
can keep the request context around during the execution of the
generator::
If your generator function relies on data in ``request``, use the
:func:`.stream_with_context` wrapper. This will keep the request context active
during the generator.
.. code-block:: python
from flask import stream_with_context, request
from markupsafe import escape
@app.route('/stream')
def streamed_response():
def generate():
yield 'Hello '
yield request.args['name']
yield '!'
return app.response_class(stream_with_context(generate()))
yield '<p>Hello '
yield escape(request.args['name'])
yield '!</p>'
return stream_with_context(generate())
Without the :func:`~flask.stream_with_context` function you would get a
:class:`RuntimeError` at that point.
It can also be used as a decorator.
.. code-block:: python
@stream_with_context
def generate():
...
return generate()
The :func:`~flask.stream_template` and
:func:`~flask.stream_template_string` functions automatically
use :func:`~flask.stream_with_context` if a request is active.

View file

@ -99,7 +99,7 @@ WTForm's field function, which renders the field for us. The keyword
arguments will be inserted as HTML attributes. So, for example, you can
call ``render_field(form.username, class='username')`` to add a class to
the input element. Note that WTForms returns standard Python strings,
so we have to tell Jinja2 that this data is already HTML-escaped with
so we have to tell Jinja that this data is already HTML-escaped with
the ``|safe`` filter.
Here is the :file:`register.html` template for the function we used above, which

View file

@ -39,50 +39,20 @@ Save it as :file:`hello.py` or something similar. Make sure to not call
your application :file:`flask.py` because this would conflict with Flask
itself.
To run the application, use the :command:`flask` command or
:command:`python -m flask`. Before you can do that you need
to tell your terminal the application to work with by exporting the
``FLASK_APP`` environment variable:
To run the application, use the ``flask`` command or
``python -m flask``. You need to tell the Flask where your application
is with the ``--app`` option.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=hello
$ flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP hello
$ flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=hello
> flask run
* Running on http://127.0.0.1:5000/
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "hello"
> flask run
* Running on http://127.0.0.1:5000/
$ flask --app hello run
* Serving Flask app 'hello'
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
.. admonition:: Application Discovery Behavior
As a shortcut, if the file is named ``app.py`` or ``wsgi.py``, you
don't have to set the ``FLASK_APP`` environment variable. See
:doc:`/cli` for more details.
don't have to use ``--app``. See :doc:`/cli` for more details.
This launches a very simple builtin server, which is good enough for
testing but probably not what you want to use in production. For
@ -114,34 +84,6 @@ handle that.
This tells your operating system to listen on all public IPs.
What to do if the Server does not Start
---------------------------------------
In case the :command:`python -m flask` fails or :command:`flask`
does not exist, there are multiple reasons this might be the case.
First of all you need to look at the error message.
Old Version of Flask
````````````````````
Versions of Flask older than 0.11 used to have different ways to start the
application. In short, the :command:`flask` command did not exist, and
neither did :command:`python -m flask`. In that case you have two options:
either upgrade to newer Flask versions or have a look at :doc:`/server`
to see the alternative method for running a server.
Invalid Import Name
```````````````````
The ``FLASK_APP`` environment variable is the name of the module to import at
:command:`flask run`. In case that module is incorrectly named you will get an
import error upon start (or if debug is enabled when you navigate to the
application). It will tell you what it tried to import and why it failed.
The most common reason is a typo or because you did not actually create an
``app`` object.
Debug Mode
----------
@ -162,43 +104,21 @@ error occurs during a request.
security risk. Do not run the development server or debugger in a
production environment.
To enable all development features, set the ``FLASK_ENV`` environment
variable to ``development`` before calling ``flask run``.
To enable debug mode, use the ``--debug`` option.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_ENV development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_ENV = "development"
> flask run
$ flask --app hello run --debug
* Serving Flask app 'hello'
* Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: nnn-nnn-nnn
See also:
- :doc:`/server` and :doc:`/cli` for information about running in
development mode.
- :doc:`/server` and :doc:`/cli` for information about running in debug mode.
- :doc:`/debugging` for information about using the built-in debugger
and other debuggers.
- :doc:`/logging` and :doc:`/errorhandling` to log errors and display
@ -219,18 +139,16 @@ how you're using untrusted data.
.. code-block:: python
from flask import request
from markupsafe import escape
@app.route("/<name>")
def hello(name):
@app.route("/hello")
def hello():
name = request.args.get("name", "Flask")
return f"Hello, {escape(name)}!"
If a user managed to submit the name ``<script>alert("bad")</script>``,
escaping causes it to be rendered as text, rather than running the
script in the user's browser.
``<name>`` in the route captures a value from the URL and passes it to
the view function. These variable rules are explained below.
If a user submits ``/hello?name=<script>alert("bad")</script>``, escaping causes
it to be rendered as text, rather than running the script in the user's browser.
Routing
@ -340,7 +258,7 @@ Why would you want to build URLs using the URL reversing function
For example, here we use the :meth:`~flask.Flask.test_request_context` method
to try out :func:`~flask.url_for`. :meth:`~flask.Flask.test_request_context`
tells Flask to behave as though it's handling a request even while we use a
Python shell. See :ref:`context-locals`.
Python shell. See :doc:`/appcontext`.
.. code-block:: python
@ -434,9 +352,17 @@ Rendering Templates
Generating HTML from within Python is not fun, and actually pretty
cumbersome because you have to do the HTML escaping on your own to keep
the application secure. Because of that Flask configures the `Jinja2
the application secure. Because of that Flask configures the `Jinja
<https://palletsprojects.com/p/jinja/>`_ template engine for you automatically.
Templates can be used to generate any type of text file. For web applications, you'll
primarily be generating HTML pages, but you can also generate markdown, plain text for
emails, and anything else.
For a reference to HTML, CSS, and other web APIs, use the `MDN Web Docs`_.
.. _MDN Web Docs: https://developer.mozilla.org/
To render a template you can use the :func:`~flask.render_template`
method. All you have to do is provide the name of the template and the
variables you want to pass to the template engine as keyword arguments.
@ -447,7 +373,7 @@ Here's a simple example of how to render a template::
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)
return render_template('hello.html', person=name)
Flask will look for templates in the :file:`templates` folder. So if your
application is a module, this folder is next to that module, if it's a
@ -466,8 +392,8 @@ package it's actually inside your package:
/templates
/hello.html
For templates you can use the full power of Jinja2 templates. Head over
to the official `Jinja2 Template Documentation
For templates you can use the full power of Jinja templates. Head over
to the official `Jinja Template Documentation
<https://jinja.palletsprojects.com/templates/>`_ for more information.
Here is an example template:
@ -476,8 +402,8 @@ Here is an example template:
<!doctype html>
<title>Hello from Flask</title>
{% if name %}
<h1>Hello {{ name }}!</h1>
{% if person %}
<h1>Hello {{ person }}!</h1>
{% else %}
<h1>Hello, World!</h1>
{% endif %}
@ -491,7 +417,7 @@ know how that works, see :doc:`patterns/templateinheritance`. Basically
template inheritance makes it possible to keep certain elements on each
page (like header, navigation and footer).
Automatic escaping is enabled, so if ``name`` contains HTML it will be escaped
Automatic escaping is enabled, so if ``person`` contains HTML it will be escaped
automatically. If you can trust a variable and you know that it will be
safe HTML (for example because it came from a module that converts wiki
markup to HTML) you can mark it as safe by using the
@ -523,105 +449,58 @@ Here is a basic introduction to how the :class:`~markupsafe.Markup` class works:
Accessing Request Data
----------------------
For web applications it's crucial to react to the data a client sends to
the server. In Flask this information is provided by the global
:class:`~flask.request` object. If you have some experience with Python
you might be wondering how that object can be global and how Flask
manages to still be threadsafe. The answer is context locals:
For web applications it's crucial to react to the data a client sends to the
server. In Flask this information is provided by the global :data:`.request`
object, which is an instance of :class:`.Request`. This object has many
attributes and methods to work with the incoming request data, but here is a
broad overview. First it needs to be imported.
.. _context-locals:
Context Locals
``````````````
.. admonition:: Insider Information
If you want to understand how that works and how you can implement
tests with context locals, read this section, otherwise just skip it.
Certain objects in Flask are global objects, but not of the usual kind.
These objects are actually proxies to objects that are local to a specific
context. What a mouthful. But that is actually quite easy to understand.
Imagine the context being the handling thread. A request comes in and the
web server decides to spawn a new thread (or something else, the
underlying object is capable of dealing with concurrency systems other
than threads). When Flask starts its internal request handling it
figures out that the current thread is the active context and binds the
current application and the WSGI environments to that context (thread).
It does that in an intelligent way so that one application can invoke another
application without breaking.
So what does this mean to you? Basically you can completely ignore that
this is the case unless you are doing something like unit testing. You
will notice that code which depends on a request object will suddenly break
because there is no request object. The solution is creating a request
object yourself and binding it to the context. The easiest solution for
unit testing is to use the :meth:`~flask.Flask.test_request_context`
context manager. In combination with the ``with`` statement it will bind a
test request so that you can interact with it. Here is an example::
.. code-block:: python
from flask import request
with app.test_request_context('/hello', method='POST'):
# now you can do something with the request until the
# end of the with block, such as basic assertions:
assert request.path == '/hello'
assert request.method == 'POST'
If you have some experience with Python you might be wondering how that object
can be global when Flask handles multiple requests at a time. The answer is
that :data:`.request` is actually a proxy, pointing at whatever request is
currently being handled by a given worker, which is managed internally by Flask
and Python. See :doc:`/appcontext` for much more information.
The other possibility is passing a whole WSGI environment to the
:meth:`~flask.Flask.request_context` method::
The current request method is available in the :attr:`~.Request.method`
attribute. To access form data (data transmitted in a ``POST`` or ``PUT``
request), use the :attr:`~flask.Request.form` attribute, which behaves like a
dict.
with app.request_context(environ):
assert request.method == 'POST'
.. code-block:: python
The Request Object
``````````````````
The request object is documented in the API section and we will not cover
it here in detail (see :class:`~flask.Request`). Here is a broad overview of
some of the most common operations. First of all you have to import it from
the ``flask`` module::
from flask import request
The current request method is available by using the
:attr:`~flask.Request.method` attribute. To access form data (data
transmitted in a ``POST`` or ``PUT`` request) you can use the
:attr:`~flask.Request.form` attribute. Here is a full example of the two
attributes mentioned above::
@app.route('/login', methods=['POST', 'GET'])
@app.route("/login", methods=["GET", "POST"])
def login():
error = None
if request.method == 'POST':
if valid_login(request.form['username'],
request.form['password']):
return log_the_user_in(request.form['username'])
if request.method == "POST":
if valid_login(request.form["username"], request.form["password"]):
return store_login(request.form["username"])
else:
error = 'Invalid username/password'
# the code below is executed if the request method
# was GET or the credentials were invalid
return render_template('login.html', error=error)
error = "Invalid username or password"
What happens if the key does not exist in the ``form`` attribute? In that
case a special :exc:`KeyError` is raised. You can catch it like a
standard :exc:`KeyError` but if you don't do that, a HTTP 400 Bad Request
error page is shown instead. So for many situations you don't have to
deal with that problem.
# Executed if the request method was GET or the credentials were invalid.
return render_template("login.html", error=error)
To access parameters submitted in the URL (``?key=value``) you can use the
:attr:`~flask.Request.args` attribute::
If the key does not exist in ``form``, a special :exc:`KeyError` is raised. You
can catch it like a normal ``KeyError``, otherwise it will return a HTTP 400
Bad Request error page. You can also use the
:meth:`~werkzeug.datastructures.MultiDict.get` method to get a default
instead of an error.
To access parameters submitted in the URL (``?key=value``), use the
:attr:`~.Request.args` attribute. Key errors behave the same as ``form``,
returning a 400 response if not caught.
.. code-block:: python
searchword = request.args.get('key', '')
We recommend accessing URL parameters with `get` or by catching the
:exc:`KeyError` because users might change the URL and presenting them a 400
bad request page in that case is not user friendly.
For a full list of methods and attributes of the request object, head over
to the :class:`~flask.Request` documentation.
For a full list of methods and attributes of the request object, see the
:class:`~.Request` documentation.
File Uploads
@ -758,22 +637,25 @@ The return value from a view function is automatically converted into
a response object for you. If the return value is a string it's
converted into a response object with the string as response body, a
``200 OK`` status code and a :mimetype:`text/html` mimetype. If the
return value is a dict, :func:`jsonify` is called to produce a response.
The logic that Flask applies to converting return values into response
objects is as follows:
return value is a dict or list, :func:`jsonify` is called to produce a
response. The logic that Flask applies to converting return values into
response objects is as follows:
1. If a response object of the correct type is returned it's directly
returned from the view.
2. If it's a string, a response object is created with that data and
the default parameters.
3. If it's a dict, a response object is created using ``jsonify``.
4. If a tuple is returned the items in the tuple can provide extra
3. If it's an iterator or generator returning strings or bytes, it is
treated as a streaming response.
4. If it's a dict or list, a response object is created using
:func:`~flask.json.jsonify`.
5. If a tuple is returned the items in the tuple can provide extra
information. Such tuples have to be in the form
``(response, status)``, ``(response, headers)``, or
``(response, status, headers)``. The ``status`` value will override
the status code and ``headers`` can be a list or dictionary of
additional header values.
5. If none of that works, Flask will assume the return value is a
6. If none of that works, Flask will assume the return value is a
valid WSGI application and convert that into a response object.
If you want to get hold of the resulting response object inside the view
@ -804,8 +686,8 @@ APIs with JSON
``````````````
A common response format when writing an API is JSON. It's easy to get
started writing such an API with Flask. If you return a ``dict`` from a
view, it will be converted to a JSON response.
started writing such an API with Flask. If you return a ``dict`` or
``list`` from a view, it will be converted to a JSON response.
.. code-block:: python
@ -818,20 +700,20 @@ view, it will be converted to a JSON response.
"image": url_for("user_image", filename=user.image),
}
Depending on your API design, you may want to create JSON responses for
types other than ``dict``. In that case, use the
:func:`~flask.json.jsonify` function, which will serialize any supported
JSON data type. Or look into Flask community extensions that support
more complex applications.
.. code-block:: python
from flask import jsonify
@app.route("/users")
def users_api():
users = get_all_users()
return jsonify([user.to_json() for user in users])
return [user.to_json() for user in users]
This is a shortcut to passing the data to the
:func:`~flask.json.jsonify` function, which will serialize any supported
JSON data type. That means that all the data in the dict or list must be
JSON serializable.
For complex types such as database models, you'll want to use a
serialization library to convert the data to valid JSON types first.
There are many serialization libraries and Flask API extensions
maintained by the community that support more complex applications.
.. _sessions:

View file

@ -1,265 +1,6 @@
.. currentmodule:: flask
:orphan:
The Request Context
===================
The request context keeps track of the request-level data during a
request. Rather than passing the request object to each function that
runs during a request, the :data:`request` and :data:`session` proxies
are accessed instead.
This is similar to :doc:`/appcontext`, which keeps track of the
application-level data independent of a request. A corresponding
application context is pushed when a request context is pushed.
Purpose of the Context
----------------------
When the :class:`Flask` application handles a request, it creates a
:class:`Request` object based on the environment it received from the
WSGI server. Because a *worker* (thread, process, or coroutine depending
on the server) handles only one request at a time, the request data can
be considered global to that worker during that request. Flask uses the
term *context local* for this.
Flask automatically *pushes* a request context when handling a request.
View functions, error handlers, and other functions that run during a
request will have access to the :data:`request` proxy, which points to
the request object for the current request.
Lifetime of the Context
-----------------------
When a Flask application begins handling a request, it pushes a request
context, which also pushes an :doc:`app context </appcontext>`. When the
request ends it pops the request context then the application context.
The context is unique to each thread (or other worker type).
:data:`request` cannot be passed to another thread, the other thread
will have a different context stack and will not know about the request
the parent thread was pointing to.
Context locals are implemented in Werkzeug. See :doc:`werkzeug:local`
for more information on how this works internally.
Manually Push a Context
-----------------------
If you try to access :data:`request`, or anything that uses it, outside
a request context, you'll get this error message:
.. code-block:: pytb
RuntimeError: Working outside of request context.
This typically means that you attempted to use functionality that
needed an active HTTP request. Consult the documentation on testing
for information about how to avoid this problem.
This should typically only happen when testing code that expects an
active request. One option is to use the
:meth:`test client <Flask.test_client>` to simulate a full request. Or
you can use :meth:`~Flask.test_request_context` in a ``with`` block, and
everything that runs in the block will have access to :data:`request`,
populated with your test data. ::
def generate_report(year):
format = request.args.get('format')
...
with app.test_request_context(
'/make_report/2017', data={'format': 'short'}):
generate_report()
If you see that error somewhere else in your code not related to
testing, it most likely indicates that you should move that code into a
view function.
For information on how to use the request context from the interactive
Python shell, see :doc:`/shell`.
How the Context Works
---------------------
The :meth:`Flask.wsgi_app` method is called to handle each request. It
manages the contexts during the request. Internally, the request and
application contexts work as stacks, :data:`_request_ctx_stack` and
:data:`_app_ctx_stack`. When contexts are pushed onto the stack, the
proxies that depend on them are available and point at information from
the top context on the stack.
When the request starts, a :class:`~ctx.RequestContext` is created and
pushed, which creates and pushes an :class:`~ctx.AppContext` first if
a context for that application is not already the top context. While
these contexts are pushed, the :data:`current_app`, :data:`g`,
:data:`request`, and :data:`session` proxies are available to the
original thread handling the request.
Because the contexts are stacks, other contexts may be pushed to change
the proxies during a request. While this is not a common pattern, it
can be used in advanced applications to, for example, do internal
redirects or chain different applications together.
After the request is dispatched and a response is generated and sent,
the request context is popped, which then pops the application context.
Immediately before they are popped, the :meth:`~Flask.teardown_request`
and :meth:`~Flask.teardown_appcontext` functions are executed. These
execute even if an unhandled exception occurred during dispatch.
.. _callbacks-and-errors:
Callbacks and Errors
--------------------
Flask dispatches a request in multiple stages which can affect the
request, response, and how errors are handled. The contexts are active
during all of these stages.
A :class:`Blueprint` can add handlers for these events that are specific
to the blueprint. The handlers for a blueprint will run if the blueprint
owns the route that matches the request.
#. Before each request, :meth:`~Flask.before_request` functions are
called. If one of these functions return a value, the other
functions are skipped. The return value is treated as the response
and the view function is not called.
#. If the :meth:`~Flask.before_request` functions did not return a
response, the view function for the matched route is called and
returns a response.
#. The return value of the view is converted into an actual response
object and passed to the :meth:`~Flask.after_request`
functions. Each function returns a modified or new response object.
#. After the response is returned, the contexts are popped, which calls
the :meth:`~Flask.teardown_request` and
:meth:`~Flask.teardown_appcontext` functions. These functions are
called even if an unhandled exception was raised at any point above.
If an exception is raised before the teardown functions, Flask tries to
match it with an :meth:`~Flask.errorhandler` function to handle the
exception and return a response. If no error handler is found, or the
handler itself raises an exception, Flask returns a generic
``500 Internal Server Error`` response. The teardown functions are still
called, and are passed the exception object.
If debug mode is enabled, unhandled exceptions are not converted to a
``500`` response and instead are propagated to the WSGI server. This
allows the development server to present the interactive debugger with
the traceback.
Teardown Callbacks
~~~~~~~~~~~~~~~~~~
The teardown callbacks are independent of the request dispatch, and are
instead called by the contexts when they are popped. The functions are
called even if there is an unhandled exception during dispatch, and for
manually pushed contexts. This means there is no guarantee that any
other parts of the request dispatch have run first. Be sure to write
these functions in a way that does not depend on other callbacks and
will not fail.
During testing, it can be useful to defer popping the contexts after the
request ends, so that their data can be accessed in the test function.
Use the :meth:`~Flask.test_client` as a ``with`` block to preserve the
contexts until the ``with`` block exits.
.. code-block:: python
from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def hello():
print('during view')
return 'Hello, World!'
@app.teardown_request
def show_teardown(exception):
print('after with block')
with app.test_request_context():
print('during with block')
# teardown functions are called after the context with block exits
with app.test_client() as client:
client.get('/')
# the contexts are not popped even though the request ended
print(request.path)
# the contexts are popped and teardown functions are called after
# the client with block exits
Signals
~~~~~~~
If :data:`~signals.signals_available` is true, the following signals are
sent:
#. :data:`request_started` is sent before the
:meth:`~Flask.before_request` functions are called.
#. :data:`request_finished` is sent after the
:meth:`~Flask.after_request` functions are called.
#. :data:`got_request_exception` is sent when an exception begins to
be handled, but before an :meth:`~Flask.errorhandler` is looked up or
called.
#. :data:`request_tearing_down` is sent after the
:meth:`~Flask.teardown_request` functions are called.
Context Preservation on Error
-----------------------------
At the end of a request, the request context is popped and all data
associated with it is destroyed. If an error occurs during development,
it is useful to delay destroying the data for debugging purposes.
When the development server is running in development mode (the
``FLASK_ENV`` environment variable is set to ``'development'``), the
error and data will be preserved and shown in the interactive debugger.
This behavior can be controlled with the
:data:`PRESERVE_CONTEXT_ON_EXCEPTION` config. As described above, it
defaults to ``True`` in the development environment.
Do not enable :data:`PRESERVE_CONTEXT_ON_EXCEPTION` in production, as it
will cause your application to leak memory on exceptions.
.. _notes-on-proxies:
Notes On Proxies
----------------
Some of the objects provided by Flask are proxies to other objects. The
proxies are accessed in the same way for each worker thread, but
point to the unique object bound to each worker behind the scenes as
described on this page.
Most of the time you don't have to care about that, but there are some
exceptions where it is good to know that this object is actually a proxy:
- The proxy objects cannot fake their type as the actual object types.
If you want to perform instance checks, you have to do that on the
object being proxied.
- The reference to the proxied object is needed in some situations,
such as sending :doc:`signals` or passing data to a background
thread.
If you need to access the underlying object that is proxied, use the
:meth:`~werkzeug.local.LocalProxy._get_current_object` method::
app = current_app._get_current_object()
my_signal.send(app)
Obsolete, see :doc:`/appcontext` instead.

View file

@ -3,9 +3,9 @@
Development Server
==================
Flask provides a ``run`` command to run the application with a
development server. In development mode, this server provides an
interactive debugger and will reload when code is changed.
Flask provides a ``run`` command to run the application with a development server. In
debug mode, this server provides an interactive debugger and will reload when code is
changed.
.. warning::
@ -18,58 +18,18 @@ interactive debugger and will reload when code is changed.
Command Line
------------
The ``flask run`` command line script is the recommended way to run the
development server. It requires setting the ``FLASK_APP`` environment
variable to point to your application, and ``FLASK_ENV=development`` to
fully enable development mode.
The ``flask run`` CLI command is the recommended way to run the development server. Use
the ``--app`` option to point to your application, and the ``--debug`` option to enable
debug mode.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
$ flask --app hello run --debug
.. code-block:: text
$ export FLASK_APP=hello
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP hello
$ export FLASK_ENV=development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=hello
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "hello"
> $env:FLASK_ENV = "development"
> flask run
This enables the development environment, including the interactive
debugger and reloader, and then starts the server on
http://localhost:5000/. Use ``flask run --help`` to see the available
options, and :doc:`/cli` for detailed instructions about configuring
and using the CLI.
.. note::
Prior to Flask 1.0 the ``FLASK_ENV`` environment variable was not
supported and you needed to enable debug mode by exporting
``FLASK_DEBUG=1``. This can still be used to control debug mode, but
you should prefer setting the development environment as shown
above.
This enables debug mode, including the interactive debugger and reloader, and then
starts the server on http://localhost:5000/. Use ``flask run --help`` to see the
available options, and :doc:`/cli` for detailed instructions about configuring and using
the CLI.
.. _address-already-in-use:
@ -116,44 +76,34 @@ following example shows that process id 6847 is using port 5000.
TCP 127.0.0.1:5000 0.0.0.0:0 LISTENING 6847
macOS Monterey and later automatically starts a service that uses port
5000. To disable the service, go to System Preferences, Sharing, and
disable "AirPlay Receiver".
5000. You can choose to disable this service instead of using a different port by
searching for "AirPlay Receiver" in System Settings and toggling it off.
Lazy or Eager Loading
~~~~~~~~~~~~~~~~~~~~~
Deferred Errors on Reload
~~~~~~~~~~~~~~~~~~~~~~~~~
When using the ``flask run`` command with the reloader, the server will
continue to run even if you introduce syntax errors or other
initialization errors into the code. Accessing the site will show the
interactive debugger for the error, rather than crashing the server.
This feature is called "lazy loading".
If a syntax error is already present when calling ``flask run``, it will
fail immediately and show the traceback rather than waiting until the
site is accessed. This is intended to make errors more visible initially
while still allowing the server to handle errors on reload.
To override this behavior and always fail immediately, even on reload,
pass the ``--eager-loading`` option. To always keep the server running,
even on the initial call, pass ``--lazy-loading``.
In Code
-------
As an alternative to the ``flask run`` command, the development server
can also be started from Python with the :meth:`Flask.run` method. This
method takes arguments similar to the CLI options to control the server.
The main difference from the CLI command is that the server will crash
if there are errors when reloading.
The development server can also be started from Python with the :meth:`Flask.run`
method. This method takes arguments similar to the CLI options to control the server.
The main difference from the CLI command is that the server will crash if there are
errors when reloading. ``debug=True`` can be passed to enable debug mode.
``debug=True`` can be passed to enable the debugger and reloader, but
the ``FLASK_ENV=development`` environment variable is still required to
fully enable development mode.
Place the call in a main block, otherwise it will interfere when trying
to import and run the application with a production server later.
Place the call in a main block, otherwise it will interfere when trying to import and
run the application with a production server later.
.. code-block:: python

View file

@ -1,56 +1,37 @@
Working with the Shell
======================
.. versionadded:: 0.3
One of the reasons everybody loves Python is the interactive shell. It allows
you to play around with code in real time and immediately get results back.
Flask provides the ``flask shell`` CLI command to start an interactive Python
shell with some setup done to make working with the Flask app easier.
One of the reasons everybody loves Python is the interactive shell. It
basically allows you to execute Python commands in real time and
immediately get results back. Flask itself does not come with an
interactive shell, because it does not require any specific setup upfront,
just import your application and start playing around.
.. code-block:: text
There are however some handy helpers to make playing around in the shell a
more pleasant experience. The main issue with interactive console
sessions is that you're not triggering a request like a browser does which
means that :data:`~flask.g`, :data:`~flask.request` and others are not
available. But the code you want to test might depend on them, so what
can you do?
This is where some helper functions come in handy. Keep in mind however
that these functions are not only there for interactive shell usage, but
also for unit testing and other situations that require a faked request
context.
Generally it's recommended that you read :doc:`reqcontext` first.
Command Line Interface
----------------------
Starting with Flask 0.11 the recommended way to work with the shell is the
``flask shell`` command which does a lot of this automatically for you.
For instance the shell is automatically initialized with a loaded
application context.
For more information see :doc:`/cli`.
$ flask shell
Creating a Request Context
--------------------------
``flask shell`` pushes an app context automatically, so :data:`.current_app` and
:data:`.g` are already available. However, there is no HTTP request being
handled in the shell, so :data:`.request` and :data:`.session` are not yet
available.
The easiest way to create a proper request context from the shell is by
using the :attr:`~flask.Flask.test_request_context` method which creates
us a :class:`~flask.ctx.RequestContext`:
>>> ctx = app.test_request_context()
Normally you would use the ``with`` statement to make this request object
active, but in the shell it's easier to use the
:meth:`~flask.ctx.RequestContext.push` and
:meth:`~flask.ctx.RequestContext.pop` methods by hand:
Normally you would use the ``with`` statement to make this context active, but
in the shell it's easier to call :meth:`~.RequestContext.push` and
:meth:`~.RequestContext.pop` manually:
>>> ctx.push()
From that point onwards you can work with the request object until you
call `pop`:
From that point onwards you can work with the request object until you call
``pop``:
>>> ctx.pop()

View file

@ -1,33 +1,28 @@
Signals
=======
.. versionadded:: 0.6
Signals are a lightweight way to notify subscribers of certain events during the
lifecycle of the application and each request. When an event occurs, it emits the
signal, which calls each subscriber.
Starting with Flask 0.6, there is integrated support for signalling in
Flask. This support is provided by the excellent `blinker`_ library and
will gracefully fall back if it is not available.
Signals are implemented by the `Blinker`_ library. See its documentation for detailed
information. Flask provides some built-in signals. Extensions may provide their own.
What are signals? Signals help you decouple applications by sending
notifications when actions occur elsewhere in the core framework or
another Flask extensions. In short, signals allow certain senders to
notify subscribers that something happened.
Many signals mirror Flask's decorator-based callbacks with similar names. For example,
the :data:`.request_started` signal is similar to the :meth:`~.Flask.before_request`
decorator. The advantage of signals over handlers is that they can be subscribed to
temporarily, and can't directly affect the application. This is useful for testing,
metrics, auditing, and more. For example, if you want to know what templates were
rendered at what parts of what requests, there is a signal that will notify you of that
information.
Flask comes with a couple of signals and other extensions might provide
more. Also keep in mind that signals are intended to notify subscribers
and should not encourage subscribers to modify data. You will notice that
there are signals that appear to do the same thing like some of the
builtin decorators do (eg: :data:`~flask.request_started` is very similar
to :meth:`~flask.Flask.before_request`). However, there are differences in
how they work. The core :meth:`~flask.Flask.before_request` handler, for
example, is executed in a specific order and is able to abort the request
early by returning a response. In contrast all signal handlers are
executed in undefined order and do not modify any data.
The big advantage of signals over handlers is that you can safely
subscribe to them for just a split second. These temporary
subscriptions are helpful for unit testing for example. Say you want to
know what templates were rendered as part of a request: signals allow you
to do exactly that.
Core Signals
------------
See :ref:`core-signals-list` for a list of all built-in signals. The :doc:`lifecycle`
page also describes the order that signals and decorators execute.
Subscribing to Signals
----------------------
@ -99,17 +94,12 @@ The example above would then look like this::
...
template, context = templates[0]
.. admonition:: Blinker API Changes
The :meth:`~blinker.base.Signal.connected_to` method arrived in Blinker
with version 1.1.
Creating Signals
----------------
If you want to use signals in your own application, you can use the
blinker library directly. The most common use case are named signals in a
custom :class:`~blinker.base.Namespace`.. This is what is recommended
custom :class:`~blinker.base.Namespace`. This is what is recommended
most of the time::
from blinker import Namespace
@ -123,12 +113,6 @@ The name for the signal here makes it unique and also simplifies
debugging. You can access the name of the signal with the
:attr:`~blinker.base.NamedSignal.name` attribute.
.. admonition:: For Extension Developers
If you are writing a Flask extension and you want to gracefully degrade for
missing blinker installations, you can do so by using the
:class:`flask.signals.Namespace` class.
.. _signals-sending:
Sending Signals
@ -160,17 +144,16 @@ function, you can pass ``current_app._get_current_object()`` as sender.
Signals and Flask's Request Context
-----------------------------------
Signals fully support :doc:`reqcontext` when receiving signals.
Context-local variables are consistently available between
:data:`~flask.request_started` and :data:`~flask.request_finished`, so you can
rely on :class:`flask.g` and others as needed. Note the limitations described
in :ref:`signals-sending` and the :data:`~flask.request_tearing_down` signal.
Context-local proxies are available between :data:`~flask.request_started` and
:data:`~flask.request_finished`, so you can rely on :class:`flask.g` and others
as needed. Note the limitations described in :ref:`signals-sending` and the
:data:`~flask.request_tearing_down` signal.
Decorator Based Signal Subscriptions
------------------------------------
With Blinker 1.1 you can also easily subscribe to signals by using the new
You can also easily subscribe to signals by using the
:meth:`~blinker.base.NamedSignal.connect_via` decorator::
from flask import template_rendered
@ -179,10 +162,5 @@ With Blinker 1.1 you can also easily subscribe to signals by using the new
def when_template_rendered(sender, template, context, **extra):
print(f'Template {template.name} is rendered with {context}')
Core Signals
------------
Take a look at :ref:`core-signals-list` for a list of all builtin signals.
.. _blinker: https://pypi.org/project/blinker/

View file

@ -1,37 +1,37 @@
Templates
=========
Flask leverages Jinja2 as its template engine. You are obviously free to use
a different template engine, but you still have to install Jinja2 to run
Flask leverages Jinja as its template engine. You are obviously free to use
a different template engine, but you still have to install Jinja to run
Flask itself. This requirement is necessary to enable rich extensions.
An extension can depend on Jinja2 being present.
An extension can depend on Jinja being present.
This section only gives a very quick introduction into how Jinja2
This section only gives a very quick introduction into how Jinja
is integrated into Flask. If you want information on the template
engine's syntax itself, head over to the official `Jinja2 Template
engine's syntax itself, head over to the official `Jinja Template
Documentation <https://jinja.palletsprojects.com/templates/>`_ for
more information.
Jinja Setup
-----------
Unless customized, Jinja2 is configured by Flask as follows:
Unless customized, Jinja is configured by Flask as follows:
- autoescaping is enabled for all templates ending in ``.html``,
``.htm``, ``.xml`` as well as ``.xhtml`` when using
``.htm``, ``.xml``, ``.xhtml``, as well as ``.svg`` when using
:func:`~flask.templating.render_template`.
- autoescaping is enabled for all strings when using
:func:`~flask.templating.render_template_string`.
- a template has the ability to opt in/out autoescaping with the
``{% autoescape %}`` tag.
- Flask inserts a couple of global functions and helpers into the
Jinja2 context, additionally to the values that are present by
Jinja context, additionally to the values that are present by
default.
Standard Context
----------------
The following global variables are available within Jinja2 templates
The following global variables are available within Jinja templates
by default:
.. data:: config
@ -115,7 +115,7 @@ markdown to HTML converter.
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
recommended way.
- Inside the template, use the ``|safe`` filter to explicitly mark a
@ -137,32 +137,58 @@ using in this block.
.. _registering-filters:
Registering Filters
-------------------
Registering Filters, Tests, and Globals
---------------------------------------
If you want to register your own filters in Jinja2 you have two ways to do
that. You can either put them by hand into the
:attr:`~flask.Flask.jinja_env` of the application or use the
:meth:`~flask.Flask.template_filter` decorator.
The Flask app and blueprints provide decorators and methods to register your own
filters, tests, and global functions for use in Jinja templates. They all follow
the same pattern, so the following examples only discuss filters.
The two following examples work the same and both reverse an object::
Decorate a function with :meth:`~.Flask.template_filter` to register it as a
template filter.
@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]
.. code-block:: python
def reverse_filter(s):
return s[::-1]
app.jinja_env.filters['reverse'] = reverse_filter
@app.template_filter
def reverse(s):
return reversed(s)
In case of the decorator the argument is optional if you want to use the
function name as name of the filter. Once registered, you can use the filter
in your templates in the same way as Jinja2's builtin filters, for example if
you have a Python list in context called `mylist`::
.. code-block:: jinja
{% for x in mylist | reverse %}
{% for item in data | reverse %}
{% endfor %}
By default it will use the name of the function as the name of the filter, but
that can be changed by passing a name to the decorator.
.. code-block:: python
@app.template_filter("reverse")
def reverse_filter(s):
return reversed(s)
A filter can be registered separately using :meth:`~.Flask.add_template_filter`.
The name is optional and will use the function name if not given.
.. code-block:: python
def reverse_filter(s):
return reversed(s)
app.add_template_filter(reverse_filter, "reverse")
For template tests, use the :meth:`~.Flask.template_test` decorator or
:meth:`~.Flask.add_template_test` method. For template global functions, use the
:meth:`~.Flask.template_global` decorator or :meth:`~.Flask.add_template_global`
method.
The same methods also exist on :class:`.Blueprint`, prefixed with ``app_`` to
indicate that the registered functions will be available to all templates, not
only when rendering from within the blueprint.
The Jinja environment is also available as :attr:`~.Flask.jinja_env`. It may be
modified directly, as you would when using Jinja outside Flask.
Context Processors
------------------
@ -201,3 +227,35 @@ templates::
You could also build `format_price` as a template filter (see
:ref:`registering-filters`), but this demonstrates how to pass functions in a
context processor.
Streaming
---------
It can be useful to not render the whole template as one complete
string, instead render it as a stream, yielding smaller incremental
strings. This can be used for streaming HTML in chunks to speed up
initial page load, or to save memory when rendering a very large
template.
The Jinja template engine supports rendering a template piece
by piece, returning an iterator of strings. Flask provides the
:func:`~flask.stream_template` and :func:`~flask.stream_template_string`
functions to make this easier to use.
.. code-block:: python
from flask import stream_template
@app.get("/timeline")
def timeline():
return stream_template("timeline.html")
These functions automatically apply the
:func:`~flask.stream_with_context` wrapper if a request is active, so that
:data:`.request`, :data:`.session`, and :data:`.g` remain available in the
template.
More headers cannot be sent after the body has begun. Therefore, you must
make sure all headers are set before starting the response. In particular,
if the template will access ``session``, be sure to do so in the view as
well so that the ``Vary: cookie`` header will be set.

View file

@ -192,7 +192,7 @@ which records the request that produced that response.
.. code-block:: python
def test_logout_redirect(client):
response = client.get("/logout")
response = client.get("/logout", follow_redirects=True)
# Check that there was one redirect response.
assert len(response.history) == 1
# Check that the second request was to the index page.
@ -275,11 +275,10 @@ command from the command line.
Tests that depend on an Active Context
--------------------------------------
You may have functions that are called from views or commands, that
expect an active :doc:`application context </appcontext>` or
:doc:`request context </reqcontext>` because they access ``request``,
``session``, or ``current_app``. Rather than testing them by making a
request or invoking the command, you can create and activate a context
You may have functions that are called from views or commands, that expect an
active :doc:`app context </appcontext>` because they access :data:`.request`,
:data:`.session`, :data:`.g`, or :data:`.current_app`. Rather than testing them by
making a request or invoking the command, you can create and activate a context
directly.
Use ``with app.app_context()`` to push an application context. For

View file

@ -305,7 +305,7 @@ The pattern ``{{ request.form['title'] or post['title'] }}`` is used to
choose what data appears in the form. When the form hasn't been
submitted, the original ``post`` data appears, but if invalid form data
was posted you want to display that so the user can fix the error, so
``request.form`` is used instead. :data:`request` is another variable
``request.form`` is used instead. :data:`.request` is another variable
that's automatically available in templates.

View file

@ -37,10 +37,10 @@ response is sent.
:caption: ``flaskr/db.py``
import sqlite3
from datetime import datetime
import click
from flask import current_app, g
from flask.cli import with_appcontext
def get_db():
@ -60,17 +60,17 @@ response is sent.
if db is not None:
db.close()
:data:`g` is a special object that is unique for each request. It is
:data:`.g` is a special object that is unique for each request. It is
used to store data that might be accessed by multiple functions during
the request. The connection is stored and reused instead of creating a
new connection if ``get_db`` is called a second time in the same
request.
:data:`current_app` is another special object that points to the Flask
:data:`.current_app` is another special object that points to the Flask
application handling the request. Since you used an application factory,
there is no application object when writing the rest of your code.
``get_db`` will be called when the application has been created and is
handling a request, so :data:`current_app` can be used.
handling a request, so :data:`.current_app` can be used.
:func:`sqlite3.connect` establishes a connection to the file pointed at
by the ``DATABASE`` configuration key. This file doesn't have to exist
@ -128,12 +128,16 @@ Add the Python functions that will run these SQL commands to the
@click.command('init-db')
@with_appcontext
def init_db_command():
"""Clear the existing data and create new tables."""
init_db()
click.echo('Initialized the database.')
sqlite3.register_converter(
"timestamp", lambda v: datetime.fromisoformat(v.decode())
)
:meth:`open_resource() <Flask.open_resource>` opens a file relative to
the ``flaskr`` package, which is useful since you won't necessarily know
where that location is when deploying the application later. ``get_db``
@ -144,6 +148,10 @@ read from the file.
that calls the ``init_db`` function and shows a success message to the
user. You can read :doc:`/cli` to learn more about writing commands.
The call to :func:`sqlite3.register_converter` tells Python how to
interpret timestamp values in the database. We convert the value to a
:class:`datetime.datetime`.
Register with the Application
-----------------------------
@ -196,15 +204,13 @@ previous page.
If you're still running the server from the previous page, you can
either stop the server, or run this command in a new terminal. If
you use a new terminal, remember to change to your project directory
and activate the env as described in :doc:`/installation`. You'll
also need to set ``FLASK_APP`` and ``FLASK_ENV`` as shown on the
previous page.
and activate the env as described in :doc:`/installation`.
Run the ``init-db`` command:
.. code-block:: none
$ flask init-db
$ flask --app flaskr init-db
Initialized the database.
There will now be a ``flaskr.sqlite`` file in the ``instance`` folder in

View file

@ -14,22 +14,13 @@ application.
Build and Install
-----------------
When you want to deploy your application elsewhere, you build a
distribution file. The current standard for Python distribution is the
*wheel* format, with the ``.whl`` extension. Make sure the wheel library
is installed first:
When you want to deploy your application elsewhere, you build a *wheel*
(``.whl``) file. Install and use the ``build`` tool to do this.
.. code-block:: none
$ pip install wheel
Running ``setup.py`` with Python gives you a command line tool to issue
build-related commands. The ``bdist_wheel`` command will build a wheel
distribution file.
.. code-block:: none
$ python setup.py bdist_wheel
$ pip install build
$ python -m build --wheel
You can find the file in ``dist/flaskr-1.0.0-py3-none-any.whl``. The
file name is in the format of {project name}-{version}-{python tag}
@ -48,39 +39,13 @@ Pip will install your project along with its dependencies.
Since this is a different machine, you need to run ``init-db`` again to
create the database in the instance folder.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=flaskr
$ flask init-db
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP flaskr
$ flask init-db
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=flaskr
> flask init-db
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "flaskr"
> flask init-db
$ flask --app flaskr init-db
When Flask detects that it's installed (not in editable mode), it uses
a different directory for the instance folder. You can find it at
``venv/var/flaskr-instance`` instead.
``.venv/var/flaskr-instance`` instead.
Configure the Secret Key
@ -103,7 +68,7 @@ Create the ``config.py`` file in the instance folder, which the factory
will read from if it exists. Copy the generated value into it.
.. code-block:: python
:caption: ``venv/var/flaskr-instance/config.py``
:caption: ``.venv/var/flaskr-instance/config.py``
SECRET_KEY = '192b9bdd22ab9ed4d12e236c78afcb9a393ec15f71bbf5dc987d54727823bcbf'
@ -127,7 +92,7 @@ first install it in the virtual environment:
$ pip install waitress
You need to tell Waitress about your application, but it doesn't use
``FLASK_APP`` like ``flask run`` does. You need to tell it to import and
``--app`` like ``flask run`` does. You need to tell it to import and
call the application factory to get an application object.
.. code-block:: none

View file

@ -56,10 +56,7 @@ directory should be treated as a package.
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
os.makedirs(app.instance_path, exist_ok=True)
# a simple page that says hello
@app.route('/hello')
@ -127,59 +124,28 @@ Run The Application
Now you can run your application using the ``flask`` command. From the
terminal, tell Flask where to find your application, then run it in
development mode. Remember, you should still be in the top-level
debug mode. Remember, you should still be in the top-level
``flask-tutorial`` directory, not the ``flaskr`` package.
Development mode shows an interactive debugger whenever a page raises an
Debug mode shows an interactive debugger whenever a page raises an
exception, and restarts the server whenever you make changes to the
code. You can leave it running and just reload the browser page as you
follow the tutorial.
.. tabs::
.. code-block:: text
.. group-tab:: Bash
.. code-block:: text
$ export FLASK_APP=flaskr
$ export FLASK_ENV=development
$ flask run
.. group-tab:: Fish
.. code-block:: text
$ set -x FLASK_APP flaskr
$ set -x FLASK_ENV development
$ flask run
.. group-tab:: CMD
.. code-block:: text
> set FLASK_APP=flaskr
> set FLASK_ENV=development
> flask run
.. group-tab:: Powershell
.. code-block:: text
> $env:FLASK_APP = "flaskr"
> $env:FLASK_ENV = "development"
> flask run
$ flask --app flaskr run --debug
You'll see output similar to this:
.. code-block:: none
.. code-block:: text
* Serving Flask app "flaskr"
* Environment: development
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 855-212-761
* Debugger PIN: nnn-nnn-nnn
Visit http://127.0.0.1:5000/hello in a browser and you should see the
"Hello, World!" message. Congratulations, you're now running your Flask

View file

@ -1,11 +1,10 @@
Make the Project Installable
============================
Making your project installable means that you can build a
*distribution* file and install that in another environment, just like
you installed Flask in your project's environment. This makes deploying
your project the same as installing any other library, so you're using
all the standard Python tools to manage everything.
Making your project installable means that you can build a *wheel* file and install that
in another environment, just like you installed Flask in your project's environment.
This makes deploying your project the same as installing any other library, so you're
using all the standard Python tools to manage everything.
Installing also comes with other benefits that might not be obvious from
the tutorial or as a new Python user, including:
@ -28,51 +27,27 @@ the tutorial or as a new Python user, including:
Describe the Project
--------------------
The ``setup.py`` file describes your project and the files that belong
to it.
The ``pyproject.toml`` file describes your project and how to build it.
.. code-block:: python
:caption: ``setup.py``
.. code-block:: toml
:caption: ``pyproject.toml``
from setuptools import find_packages, setup
[project]
name = "flaskr"
version = "1.0.0"
description = "The basic blog app built in the Flask tutorial."
dependencies = [
"flask",
]
setup(
name='flaskr',
version='1.0.0',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=[
'flask',
],
)
[build-system]
requires = ["flit_core<4"]
build-backend = "flit_core.buildapi"
``packages`` tells Python what package directories (and the Python files
they contain) to include. ``find_packages()`` finds these directories
automatically so you don't have to type them out. To include other
files, such as the static and templates directories,
``include_package_data`` is set. Python needs another file named
``MANIFEST.in`` to tell what this other data is.
.. code-block:: none
:caption: ``MANIFEST.in``
include flaskr/schema.sql
graft flaskr/static
graft flaskr/templates
global-exclude *.pyc
This tells Python to copy everything in the ``static`` and ``templates``
directories, and the ``schema.sql`` file, but to exclude all bytecode
files.
See the official `Packaging tutorial <packaging tutorial_>`_ and
`detailed guide <packaging guide_>`_ for more explanation of the files
and options used.
See the official `Packaging tutorial <packaging tutorial_>`_ for more
explanation of the files and options used.
.. _packaging tutorial: https://packaging.python.org/tutorials/packaging-projects/
.. _packaging guide: https://packaging.python.org/guides/distributing-packages-using-setuptools/
Install the Project
@ -84,10 +59,10 @@ Use ``pip`` to install your project in the virtual environment.
$ pip install -e .
This tells pip to find ``setup.py`` in the current directory and install
it in *editable* or *development* mode. Editable mode means that as you
make changes to your local code, you'll only need to re-install if you
change the metadata about the project, such as its dependencies.
This tells pip to find ``pyproject.toml`` in the current directory and install the
project in *editable* or *development* mode. Editable mode means that as you make
changes to your local code, you'll only need to re-install if you change the metadata
about the project, such as its dependencies.
You can observe that the project is now installed with ``pip list``.
@ -104,12 +79,10 @@ You can observe that the project is now installed with ``pip list``.
Jinja2 2.10
MarkupSafe 1.0
pip 9.0.3
setuptools 39.0.1
Werkzeug 0.14.1
wheel 0.30.0
Nothing changes from how you've been running your project so far.
``FLASK_APP`` is still set to ``flaskr`` and ``flask run`` still runs
``--app`` is still set to ``flaskr`` and ``flask run`` still runs
the application, but you can call it from anywhere, not just the
``flask-tutorial`` directory.

View file

@ -41,7 +41,7 @@ The project directory will contain:
* ``flaskr/``, a Python package containing your application code and
files.
* ``tests/``, a directory containing test modules.
* ``venv/``, a Python virtual environment where Flask and other
* ``.venv/``, a Python virtual environment where Flask and other
dependencies are installed.
* Installation files telling Python how to install your project.
* Version control config, such as `git`_. You should make a habit of
@ -80,9 +80,8 @@ By the end, your project layout will look like this:
│ ├── test_db.py
│ ├── test_auth.py
│ └── test_blog.py
├── venv/
├── setup.py
└── MANIFEST.in
├── .venv/
└── pyproject.toml
If you're using version control, the following files that are generated
while running your project should be ignored. There may be other files
@ -92,7 +91,7 @@ write. For example, with git:
.. code-block:: none
:caption: ``.gitignore``
venv/
.venv/
*.pyc
__pycache__/
@ -103,8 +102,4 @@ write. For example, with git:
.coverage
htmlcov/
dist/
build/
*.egg-info/
Continue to :doc:`factory`.

View file

@ -71,7 +71,7 @@ specific sections.
{% block content %}{% endblock %}
</section>
:data:`g` is automatically available in templates. Based on if
:data:`.g` is automatically available in templates. Based on if
``g.user`` is set (from ``load_logged_in_user``), either the username
and a log out link are displayed, or links to register and log in
are displayed. :func:`url_for` is also automatically available, and is

View file

@ -311,7 +311,7 @@ input and error messages without writing the same code three times.
The tests for the ``login`` view are very similar to those for
``register``. Rather than testing the data in the database,
:data:`session` should have ``user_id`` set after logging in.
:data:`.session` should have ``user_id`` set after logging in.
.. code-block:: python
:caption: ``tests/test_auth.py``
@ -336,10 +336,10 @@ The tests for the ``login`` view are very similar to those for
assert message in response.data
Using ``client`` in a ``with`` block allows accessing context variables
such as :data:`session` after the response is returned. Normally,
such as :data:`.session` after the response is returned. Normally,
accessing ``session`` outside of a request would raise an error.
Testing ``logout`` is the opposite of ``login``. :data:`session` should
Testing ``logout`` is the opposite of ``login``. :data:`.session` should
not contain ``user_id`` after logging out.
.. code-block:: python
@ -490,20 +490,18 @@ no longer exist in the database.
Running the Tests
-----------------
Some extra configuration, which is not required but makes running
tests with coverage less verbose, can be added to the project's
``setup.cfg`` file.
Some extra configuration, which is not required but makes running tests with coverage
less verbose, can be added to the project's ``pyproject.toml`` file.
.. code-block:: none
:caption: ``setup.cfg``
.. code-block:: toml
:caption: ``pyproject.toml``
[tool:pytest]
testpaths = tests
[tool.pytest.ini_options]
testpaths = ["tests"]
[coverage:run]
branch = True
source =
flaskr
[tool.coverage.run]
branch = true
source = ["flaskr"]
To run the tests, use the ``pytest`` command. It will find and run all
the test functions you've written.
@ -514,7 +512,7 @@ the test functions you've written.
========================= test session starts ==========================
platform linux -- Python 3.6.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
rootdir: /home/user/Projects/flask-tutorial, inifile: setup.cfg
rootdir: /home/user/Projects/flask-tutorial
collected 23 items
tests/test_auth.py ........ [ 34%]

View file

@ -208,13 +208,13 @@ There are a few differences from the ``register`` view:
password in the same way as the stored hash and securely compares
them. If they match, the password is valid.
#. :data:`session` is a :class:`dict` that stores data across requests.
#. :data:`.session` is a :class:`dict` that stores data across requests.
When validation succeeds, the user's ``id`` is stored in a new
session. The data is stored in a *cookie* that is sent to the
browser, and the browser then sends it back with subsequent requests.
Flask securely *signs* the data so that it can't be tampered with.
Now that the user's ``id`` is stored in the :data:`session`, it will be
Now that the user's ``id`` is stored in the :data:`.session`, it will be
available on subsequent requests. At the beginning of each request, if
a user is logged in their information should be loaded and made
available to other views.
@ -236,7 +236,7 @@ available to other views.
:meth:`bp.before_app_request() <Blueprint.before_app_request>` registers
a function that runs before the view function, no matter what URL is
requested. ``load_logged_in_user`` checks if a user id is stored in the
:data:`session` and gets that user's data from the database, storing it
:data:`.session` and gets that user's data from the database, storing it
on :data:`g.user <g>`, which lasts for the length of the request. If
there is no user id, or if the id doesn't exist, ``g.user`` will be
``None``.
@ -245,7 +245,7 @@ there is no user id, or if the id doesn't exist, ``g.user`` will be
Logout
------
To log out, you need to remove the user id from the :data:`session`.
To log out, you need to remove the user id from the :data:`.session`.
Then ``load_logged_in_user`` won't load a user on subsequent requests.
.. code-block:: python

View file

@ -1,235 +1,324 @@
Pluggable Views
===============
Class-based Views
=================
.. versionadded:: 0.7
.. currentmodule:: flask.views
Flask 0.7 introduces pluggable views inspired by the generic views from
Django which are based on classes instead of functions. The main
intention is that you can replace parts of the implementations and this
way have customizable pluggable views.
This page introduces using the :class:`View` and :class:`MethodView`
classes to write class-based views.
Basic Principle
---------------
A class-based view is a class that acts as a view function. Because it
is a class, different instances of the class can be created with
different arguments, to change the behavior of the view. This is also
known as generic, reusable, or pluggable views.
Consider you have a function that loads a list of objects from the
database and renders into a template::
An example of where this is useful is defining a class that creates an
API based on the database model it is initialized with.
@app.route('/users/')
def show_users(page):
For more complex API behavior and customization, look into the various
API extensions for Flask.
Basic Reusable View
-------------------
Let's walk through an example converting a view function to a view
class. We start with a view function that queries a list of users then
renders a template to show the list.
.. code-block:: python
@app.route("/users/")
def user_list():
users = User.query.all()
return render_template('users.html', users=users)
return render_template("users.html", users=users)
This is simple and flexible, but if you want to provide this view in a
generic fashion that can be adapted to other models and templates as well
you might want more flexibility. This is where pluggable class-based
views come into place. As the first step to convert this into a class
based view you would do this::
This works for the user model, but let's say you also had more models
that needed list pages. You'd need to write another view function for
each model, even though the only thing that would change is the model
and template name.
Instead, you can write a :class:`View` subclass that will query a model
and render a template. As the first step, we'll convert the view to a
class without any customization.
.. code-block:: python
from flask.views import View
class ShowUsers(View):
class UserList(View):
def dispatch_request(self):
users = User.query.all()
return render_template('users.html', objects=users)
return render_template("users.html", objects=users)
app.add_url_rule('/users/', view_func=ShowUsers.as_view('show_users'))
app.add_url_rule("/users/", view_func=UserList.as_view("user_list"))
As you can see what you have to do is to create a subclass of
:class:`flask.views.View` and implement
:meth:`~flask.views.View.dispatch_request`. Then we have to convert that
class into an actual view function by using the
:meth:`~flask.views.View.as_view` class method. The string you pass to
that function is the name of the endpoint that view will then have. But
this by itself is not helpful, so let's refactor the code a bit::
The :meth:`View.dispatch_request` method is the equivalent of the view
function. Calling :meth:`View.as_view` method will create a view
function that can be registered on the app with its
:meth:`~flask.Flask.add_url_rule` method. The first argument to
``as_view`` is the name to use to refer to the view with
:func:`~flask.url_for`.
.. note::
from flask.views import View
You can't decorate the class with ``@app.route()`` the way you'd
do with a basic view function.
Next, we need to be able to register the same view class for different
models and templates, to make it more useful than the original function.
The class will take two arguments, the model and template, and store
them on ``self``. Then ``dispatch_request`` can reference these instead
of hard-coded values.
.. code-block:: python
class ListView(View):
def get_template_name(self):
raise NotImplementedError()
def render_template(self, context):
return render_template(self.get_template_name(), **context)
def __init__(self, model, template):
self.model = model
self.template = template
def dispatch_request(self):
context = {'objects': self.get_objects()}
return self.render_template(context)
items = self.model.query.all()
return render_template(self.template, items=items)
class UserView(ListView):
Remember, we create the view function with ``View.as_view()`` instead of
creating the class directly. Any extra arguments passed to ``as_view``
are then passed when creating the class. Now we can register the same
view to handle multiple models.
def get_template_name(self):
return 'users.html'
.. code-block:: python
def get_objects(self):
return User.query.all()
app.add_url_rule(
"/users/",
view_func=ListView.as_view("user_list", User, "users.html"),
)
app.add_url_rule(
"/stories/",
view_func=ListView.as_view("story_list", Story, "stories.html"),
)
This of course is not that helpful for such a small example, but it's good
enough to explain the basic principle. When you have a class-based view
the question comes up what ``self`` points to. The way this works is that
whenever the request is dispatched a new instance of the class is created
and the :meth:`~flask.views.View.dispatch_request` method is called with
the parameters from the URL rule. The class itself is instantiated with
the parameters passed to the :meth:`~flask.views.View.as_view` function.
For instance you can write a class like this::
class RenderTemplateView(View):
def __init__(self, template_name):
self.template_name = template_name
URL Variables
-------------
Any variables captured by the URL are passed as keyword arguments to the
``dispatch_request`` method, as they would be for a regular view
function.
.. code-block:: python
class DetailView(View):
def __init__(self, model):
self.model = model
self.template = f"{model.__name__.lower()}/detail.html"
def dispatch_request(self, id)
item = self.model.query.get_or_404(id)
return render_template(self.template, item=item)
app.add_url_rule(
"/users/<int:id>",
view_func=DetailView.as_view("user_detail", User)
)
View Lifetime and ``self``
--------------------------
By default, a new instance of the view class is created every time a
request is handled. This means that it is safe to write other data to
``self`` during the request, since the next request will not see it,
unlike other forms of global state.
However, if your view class needs to do a lot of complex initialization,
doing it for every request is unnecessary and can be inefficient. To
avoid this, set :attr:`View.init_every_request` to ``False``, which will
only create one instance of the class and use it for every request. In
this case, writing to ``self`` is not safe. If you need to store data
during the request, use :data:`~flask.g` instead.
In the ``ListView`` example, nothing writes to ``self`` during the
request, so it is more efficient to create a single instance.
.. code-block:: python
class ListView(View):
init_every_request = False
def __init__(self, model, template):
self.model = model
self.template = template
def dispatch_request(self):
return render_template(self.template_name)
items = self.model.query.all()
return render_template(self.template, items=items)
And then you can register it like this::
Different instances will still be created each for each ``as_view``
call, but not for each request to those views.
View Decorators
---------------
The view class itself is not the view function. View decorators need to
be applied to the view function returned by ``as_view``, not the class
itself. Set :attr:`View.decorators` to a list of decorators to apply.
.. code-block:: python
class UserList(View):
decorators = [cache(minutes=2), login_required]
app.add_url_rule('/users/', view_func=UserList.as_view())
If you didn't set ``decorators``, you could apply them manually instead.
This is equivalent to:
.. code-block:: python
view = UserList.as_view("users_list")
view = cache(minutes=2)(view)
view = login_required(view)
app.add_url_rule('/users/', view_func=view)
Keep in mind that order matters. If you're used to ``@decorator`` style,
this is equivalent to:
.. code-block:: python
@app.route("/users/")
@login_required
@cache(minutes=2)
def user_list():
...
app.add_url_rule('/about', view_func=RenderTemplateView.as_view(
'about_page', template_name='about.html'))
Method Hints
------------
Pluggable views are attached to the application like a regular function by
either using :func:`~flask.Flask.route` or better
:meth:`~flask.Flask.add_url_rule`. That however also means that you would
have to provide the names of the HTTP methods the view supports when you
attach this. In order to move that information to the class you can
provide a :attr:`~flask.views.View.methods` attribute that has this
information::
A common pattern is to register a view with ``methods=["GET", "POST"]``,
then check ``request.method == "POST"`` to decide what to do. Setting
:attr:`View.methods` is equivalent to passing the list of methods to
``add_url_rule`` or ``route``.
.. code-block:: python
class MyView(View):
methods = ['GET', 'POST']
methods = ["GET", "POST"]
def dispatch_request(self):
if request.method == 'POST':
if request.method == "POST":
...
...
app.add_url_rule('/myview', view_func=MyView.as_view('myview'))
app.add_url_rule('/my-view', view_func=MyView.as_view('my-view'))
Method Based Dispatching
------------------------
This is equivalent to the following, except further subclasses can
inherit or change the methods.
For RESTful APIs it's especially helpful to execute a different function
for each HTTP method. With the :class:`flask.views.MethodView` you can
easily do that. Each HTTP method maps to a method of the class with the
same name (just in lowercase)::
.. code-block:: python
app.add_url_rule(
"/my-view",
view_func=MyView.as_view("my-view"),
methods=["GET", "POST"],
)
Method Dispatching and APIs
---------------------------
For APIs it can be helpful to use a different function for each HTTP
method. :class:`MethodView` extends the basic :class:`View` to dispatch
to different methods of the class based on the request method. Each HTTP
method maps to a method of the class with the same (lowercase) name.
:class:`MethodView` automatically sets :attr:`View.methods` based on the
methods defined by the class. It even knows how to handle subclasses
that override or define other methods.
We can make a generic ``ItemAPI`` class that provides get (detail),
patch (edit), and delete methods for a given model. A ``GroupAPI`` can
provide get (list) and post (create) methods.
.. code-block:: python
from flask.views import MethodView
class UserAPI(MethodView):
class ItemAPI(MethodView):
init_every_request = False
def __init__(self, model):
self.model = model
self.validator = generate_validator(model)
def _get_item(self, id):
return self.model.query.get_or_404(id)
def get(self, id):
item = self._get_item(id)
return jsonify(item.to_json())
def patch(self, id):
item = self._get_item(id)
errors = self.validator.validate(item, request.json)
if errors:
return jsonify(errors), 400
item.update_from_json(request.json)
db.session.commit()
return jsonify(item.to_json())
def delete(self, id):
item = self._get_item(id)
db.session.delete(item)
db.session.commit()
return "", 204
class GroupAPI(MethodView):
init_every_request = False
def __init__(self, model):
self.model = model
self.validator = generate_validator(model, create=True)
def get(self):
users = User.query.all()
...
items = self.model.query.all()
return jsonify([item.to_json() for item in items])
def post(self):
user = User.from_form_data(request.form)
...
errors = self.validator.validate(request.json)
app.add_url_rule('/users/', view_func=UserAPI.as_view('users'))
if errors:
return jsonify(errors), 400
That way you also don't have to provide the
:attr:`~flask.views.View.methods` attribute. It's automatically set based
on the methods defined in the class.
db.session.add(self.model.from_json(request.json))
db.session.commit()
return jsonify(item.to_json())
Decorating Views
----------------
def register_api(app, model, name):
item = ItemAPI.as_view(f"{name}-item", model)
group = GroupAPI.as_view(f"{name}-group", model)
app.add_url_rule(f"/{name}/<int:id>", view_func=item)
app.add_url_rule(f"/{name}/", view_func=group)
Since the view class itself is not the view function that is added to the
routing system it does not make much sense to decorate the class itself.
Instead you either have to decorate the return value of
:meth:`~flask.views.View.as_view` by hand::
register_api(app, User, "users")
register_api(app, Story, "stories")
def user_required(f):
"""Checks whether user is logged in or raises error 401."""
def decorator(*args, **kwargs):
if not g.user:
abort(401)
return f(*args, **kwargs)
return decorator
This produces the following views, a standard REST API!
view = user_required(UserAPI.as_view('users'))
app.add_url_rule('/users/', view_func=view)
Starting with Flask 0.8 there is also an alternative way where you can
specify a list of decorators to apply in the class declaration::
class UserAPI(MethodView):
decorators = [user_required]
Due to the implicit self from the caller's perspective you cannot use
regular view decorators on the individual methods of the view however,
keep this in mind.
Method Views for APIs
---------------------
Web APIs are often working very closely with HTTP verbs so it makes a lot
of sense to implement such an API based on the
:class:`~flask.views.MethodView`. That said, you will notice that the API
will require different URL rules that go to the same method view most of
the time. For instance consider that you are exposing a user object on
the web:
=============== =============== ======================================
URL Method Description
--------------- --------------- --------------------------------------
``/users/`` ``GET`` Gives a list of all users
``/users/`` ``POST`` Creates a new user
``/users/<id>`` ``GET`` Shows a single user
``/users/<id>`` ``PUT`` Updates a single user
``/users/<id>`` ``DELETE`` Deletes a single user
=============== =============== ======================================
So how would you go about doing that with the
:class:`~flask.views.MethodView`? The trick is to take advantage of the
fact that you can provide multiple rules to the same view.
Let's assume for the moment the view would look like this::
class UserAPI(MethodView):
def get(self, user_id):
if user_id is None:
# return a list of users
pass
else:
# expose a single user
pass
def post(self):
# create a new user
pass
def delete(self, user_id):
# delete a single user
pass
def put(self, user_id):
# update a single user
pass
So how do we hook this up with the routing system? By adding two rules
and explicitly mentioning the methods for each::
user_view = UserAPI.as_view('user_api')
app.add_url_rule('/users/', defaults={'user_id': None},
view_func=user_view, methods=['GET',])
app.add_url_rule('/users/', view_func=user_view, methods=['POST',])
app.add_url_rule('/users/<int:user_id>', view_func=user_view,
methods=['GET', 'PUT', 'DELETE'])
If you have a lot of APIs that look similar you can refactor that
registration code::
def register_api(view, endpoint, url, pk='id', pk_type='int'):
view_func = view.as_view(endpoint)
app.add_url_rule(url, defaults={pk: None},
view_func=view_func, methods=['GET',])
app.add_url_rule(url, view_func=view_func, methods=['POST',])
app.add_url_rule(f'{url}<{pk_type}:{pk}>', view_func=view_func,
methods=['GET', 'PUT', 'DELETE'])
register_api(UserAPI, 'user_api', '/users/', pk='user_id')
================= ========== ===================
URL Method Description
----------------- ---------- -------------------
``/users/`` ``GET`` List all users
``/users/`` ``POST`` Create a new user
``/users/<id>`` ``GET`` Show a single user
``/users/<id>`` ``PATCH`` Update a user
``/users/<id>`` ``DELETE`` Delete a user
``/stories/`` ``GET`` List all stories
``/stories/`` ``POST`` Create a new story
``/stories/<id>`` ``GET`` Show a single story
``/stories/<id>`` ``PATCH`` Update a story
``/stories/<id>`` ``DELETE`` Delete a story
================= ========== ===================

View file

@ -1,9 +1,43 @@
Security Considerations
=======================
Web applications usually face all kinds of security problems and it's very
hard to get everything right. Flask tries to solve a few of these things
for you, but there are a couple more you have to take care of yourself.
Web applications face many types of potential security problems, and it can be
hard to get everything right, or even to know what "right" is in general. Flask
tries to solve a few of these things by default, but there are other parts you
may have to take care of yourself. Many of these solutions are tradeoffs, and
will depend on each application's specific needs and threat model. Many hosting
platforms may take care of certain types of problems without the need for the
Flask application to handle them.
Resource Use
------------
A common category of attacks is "Denial of Service" (DoS or DDoS). This is a
very broad category, and different variants target different layers in a
deployed application. In general, something is done to increase how much
processing time or memory is used to handle each request, to the point where
there are not enough resources to handle legitimate requests.
Flask provides a few configuration options to handle resource use. They can
also be set on individual requests to customize only that request. The
documentation for each goes into more detail.
- :data:`MAX_CONTENT_LENGTH` or :attr:`.Request.max_content_length` controls
how much data will be read from a request. It is not set by default,
although it will still block truly unlimited streams unless the WSGI server
indicates support.
- :data:`MAX_FORM_MEMORY_SIZE` or :attr:`.Request.max_form_memory_size`
controls how large any non-file ``multipart/form-data`` field can be. It is
set to 500kB by default.
- :data:`MAX_FORM_PARTS` or :attr:`.Request.max_form_parts` controls how many
``multipart/form-data`` fields can be parsed. It is set to 1000 by default.
Combined with the default `max_form_memory_size`, this means that a form
will occupy at most 500MB of memory.
Regardless of these settings, you should also review what settings are available
from your operating system, container deployment (Docker etc), WSGI server, HTTP
server, and hosting platform. They typically have ways to set process resource
limits, timeouts, and other checks regardless of how Flask is configured.
.. _security-xss:
@ -17,13 +51,13 @@ tags. For more information on that have a look at the Wikipedia article
on `Cross-Site Scripting
<https://en.wikipedia.org/wiki/Cross-site_scripting>`_.
Flask configures Jinja2 to automatically escape all values unless
Flask configures Jinja to automatically escape all values unless
explicitly told otherwise. This should rule out all XSS problems caused
in templates, but there are still other places where you have to be
careful:
- generating HTML without the help of Jinja2
- calling :class:`~flask.Markup` on data submitted by users
- generating HTML without the help of Jinja
- calling :class:`~markupsafe.Markup` on data submitted by users
- sending out HTML from uploaded files, never do that, use the
``Content-Disposition: attachment`` header to prevent that problem.
- sending out textfiles from uploaded files. Some browsers are using
@ -31,7 +65,7 @@ careful:
trick a browser to execute HTML.
Another thing that is very important are unquoted attributes. While
Jinja2 can protect you from XSS issues by escaping HTML, there is one
Jinja can protect you from XSS issues by escaping HTML, there is one
thing it cannot protect you from: XSS by attribute injection. To counter
this possible attack vector, be sure to always quote your attributes with
either double or single quotes when using Jinja expressions in them:
@ -124,7 +158,7 @@ recommend reviewing each of the headers below for use in your application.
The `Flask-Talisman`_ extension can be used to manage HTTPS and the security
headers for you.
.. _Flask-Talisman: https://github.com/GoogleCloudPlatform/flask-talisman
.. _Flask-Talisman: https://github.com/wntrblm/flask-talisman
HTTP Strict Transport Security (HSTS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -235,17 +269,25 @@ values (or any values that need secure signatures).
.. _samesite_support: https://caniuse.com/#feat=same-site-cookie-attribute
HTTP Public Key Pinning (HPKP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Host Header Validation
----------------------
This tells the browser to authenticate with the server using only the specific
certificate key to prevent MITM attacks.
The ``Host`` header is used by the client to indicate what host name the request
was made to. This is used, for example, by ``url_for(..., _external=True)`` to
generate full URLs, for use in email or other messages outside the browser
window.
.. warning::
Be careful when enabling this, as it is very difficult to undo if you set up
or upgrade your key incorrectly.
By default the app doesn't know what host(s) it is allowed to be accessed
through, and assumes any host is valid. Although browsers do not allow setting
the ``Host`` header, requests made by attackers in other scenarios could set
the ``Host`` header to a value they want.
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning
When deploying your application, set :data:`TRUSTED_HOSTS` to restrict what
values the ``Host`` header may be.
The ``Host`` header may be modified by proxies in between the client and your
application. See :doc:`deploying/proxy_fix` to tell your app which proxy values
to trust.
Copy/Paste to Terminal

27
examples/celery/README.md Normal file
View file

@ -0,0 +1,27 @@
Background Tasks with Celery
============================
This example shows how to configure Celery with Flask, how to set up an API for
submitting tasks and polling results, and how to use that API with JavaScript. See
[Flask's documentation about Celery](https://flask.palletsprojects.com/patterns/celery/).
From this directory, create a virtualenv and install the application into it. Then run a
Celery worker.
```shell
$ python3 -m venv .venv
$ . ./.venv/bin/activate
$ pip install -r requirements.txt && pip install -e .
$ celery -A make_celery worker --loglevel INFO
```
In a separate terminal, activate the virtualenv and run the Flask development server.
```shell
$ . ./.venv/bin/activate
$ flask -A task_app run --debug
```
Go to http://localhost:5000/ and use the forms to submit tasks. You can see the polling
requests in the browser dev tools and the Flask logs. You can see the tasks submitting
and completing in the Celery logs.

View file

@ -0,0 +1,4 @@
from task_app import create_app
flask_app = create_app()
celery_app = flask_app.extensions["celery"]

View file

@ -0,0 +1,17 @@
[project]
name = "flask-example-celery"
version = "1.0.0"
description = "Example Flask application with Celery background tasks."
readme = "README.md"
classifiers = ["Private :: Do Not Upload"]
dependencies = ["flask", "celery[redis]"]
[build-system]
requires = ["flit_core<4"]
build-backend = "flit_core.buildapi"
[tool.flit.module]
name = "task_app"
[tool.ruff]
src = ["src"]

View file

@ -0,0 +1,58 @@
#
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --resolver=backtracking pyproject.toml
#
amqp==5.1.1
# via kombu
async-timeout==4.0.2
# via redis
billiard==3.6.4.0
# via celery
blinker==1.6.2
# via flask
celery[redis]==5.2.7
# via flask-example-celery (pyproject.toml)
click==8.1.3
# via
# celery
# click-didyoumean
# click-plugins
# click-repl
# flask
click-didyoumean==0.3.0
# via celery
click-plugins==1.1.1
# via celery
click-repl==0.2.0
# via celery
flask==2.3.2
# via flask-example-celery (pyproject.toml)
itsdangerous==2.1.2
# via flask
jinja2==3.1.2
# via flask
kombu==5.2.4
# via celery
markupsafe==2.1.2
# via
# jinja2
# werkzeug
prompt-toolkit==3.0.38
# via click-repl
pytz==2023.3
# via celery
redis==4.5.4
# via celery
six==1.16.0
# via click-repl
vine==5.0.0
# via
# amqp
# celery
# kombu
wcwidth==0.2.6
# via prompt-toolkit
werkzeug==2.3.3
# via flask

Some files were not shown because too many files have changed in this diff Show more