Compare commits
535 Commits
Author | SHA1 | Date |
---|---|---|
|
adf363679d | |
|
c2705ffd9c | |
|
330123258e | |
|
85793d6c22 | |
|
2c1b30d050 | |
|
1292419ddf | |
|
4dd52ca9c7 | |
|
55c6255657 | |
|
ed1c9e953e | |
|
edebd37044 | |
|
daf1510a4b | |
|
d8259eb119 | |
|
38b4c1e19b | |
|
9822a03515 | |
|
49b7e7bc8f | |
|
b228ca3d87 | |
|
ff64079a51 | |
|
1dfd7cd555 | |
|
d44f1c6523 | |
|
c56c5ec7c4 | |
|
0f83958247 | |
|
7fea7cf156 | |
|
24824ff666 | |
|
53b8f08218 | |
|
5addaf833b | |
|
85c5d93cbd | |
|
85cc710464 | |
|
284273e3c5 | |
|
f17d986948 | |
|
d6009c0aeb | |
|
2b42a803a2 | |
|
211cce038a | |
|
a7b67c99f9 | |
|
a758915893 | |
|
e974128863 | |
|
f04c5e6964 | |
|
c07b201ce3 | |
|
adeea00707 | |
|
7bf3be8dfa | |
|
a42c4d54a3 | |
|
184ec3c545 | |
|
a5f9742398 | |
|
52df9eed45 | |
|
e7e5380776 | |
|
bbaf13333f | |
|
57e7286948 | |
|
7fff56f517 | |
|
73d6504063 | |
|
cbb6c36692 | |
|
fb54159861 | |
|
bc143499cf | |
|
941efd4a36 | |
|
0109e496f6 | |
|
11c45eeba3 | |
|
b78b5a210b | |
|
e785166507 | |
|
410e5ab7ed | |
|
bfffe87d4c | |
|
73ce26c3e8 | |
|
41ec5760a2 | |
|
2732c4db66 | |
|
c94d2a77db | |
|
315ebc1176 | |
|
7d5d187458 | |
|
c7c8dc38ea | |
|
2ae36c8dd5 | |
|
5ea0ab8ea2 | |
|
da60039486 | |
|
08c480b3b3 | |
|
f51a23839a | |
|
04b070fa26 | |
|
75a8327cfd | |
|
165af0a090 | |
|
235c52fa10 | |
|
f61172b8dd | |
|
959052fb8d | |
|
5b525e9797 | |
|
60a11a730e | |
|
6b361ce06b | |
|
6b054f8f38 | |
|
f2674c5bb4 | |
|
54c3f87af9 | |
|
ea08f155d8 | |
|
b394a994e6 | |
|
dcbe86bd15 | |
|
d5b7a05ab2 | |
|
d22bfcd4cf | |
|
4fec712f32 | |
|
18ffe1eaf6 | |
|
bc098406af | |
|
ab81496641 | |
|
70602a196a | |
|
6748a09341 | |
|
22c48a738b | |
|
2eab96a32a | |
|
f49dbfd3e4 | |
|
7b21d43d4c | |
|
4f7156f2c3 | |
|
10bdf61a0f | |
|
4995a775df | |
|
07c7d5730a | |
|
470e2b8d17 | |
|
a20bcff8dc | |
|
e13373f838 | |
|
7522c4bcdb | |
|
2c31603042 | |
|
6c44dd4bb8 | |
|
98ae718976 | |
|
c62b03bcfd | |
|
a9b99b3489 | |
|
8aa161a437 | |
|
df201ed152 | |
|
ce08bc704e | |
|
9efc1ebeeb | |
|
6f2014d353 | |
|
c7a53888a1 | |
|
62c56e08c4 | |
|
8f37c82f61 | |
|
39e7208366 | |
|
227838c472 | |
|
99ce7ed0e4 | |
|
1d610e44b3 | |
|
e8b91cd38a | |
|
9e831e915f | |
|
5e8cb74018 | |
|
2778b7c23f | |
|
96800fb673 | |
|
8f2bc008ad | |
|
9b5549313e | |
|
68150d4caf | |
|
74721b48f0 | |
|
d273f87a41 | |
|
52ccd66735 | |
|
dffe303482 | |
|
52c060f718 | |
|
c5a5576522 | |
|
bca18041b0 | |
|
b337d21058 | |
|
e63ead4208 | |
|
2fec0b206c | |
|
111e5bd312 | |
|
db49548d71 | |
|
f93dd6e826 | |
|
7e53070307 | |
|
c77b099cbb | |
|
eeb5f95a0f | |
|
40b78fa2ea | |
|
4e6384da32 | |
|
2c5d652493 | |
|
176fdfa000 | |
|
2d31dce826 | |
|
29a94bd102 | |
|
0f2ae2b933 | |
|
8a6cdf1e2a | |
|
326ad3f43c | |
|
a791997041 | |
|
4fe0aebab7 | |
|
a8956feba1 | |
|
28d5a4d718 | |
|
5353f306fe | |
|
321bd74b95 | |
|
66af0e55ef | |
|
3d357273b5 | |
|
926ab92118 | |
|
088b58dbce | |
|
7621b3d96a | |
|
e165f3aef4 | |
|
d718ecf6d3 | |
|
0ce27278d2 | |
|
07c8f19bfd | |
|
0d2100ed17 | |
|
e3535f9971 | |
|
422e05e28d | |
|
f567ab9068 | |
|
6d126e1013 | |
|
c7da8c2aa3 | |
|
bb16048ad7 | |
|
767ad19b10 | |
|
a2f495b9ff | |
|
4a1766c252 | |
|
255c8d66af | |
|
bea5876e46 | |
|
9101439d7b | |
|
67ed36910d | |
|
4e894892bc | |
|
d64ecfb244 | |
|
860a25c390 | |
|
273123f6b8 | |
|
fc605b575b | |
|
a936b0c610 | |
|
4f42c64203 | |
|
eb1182a10e | |
|
a363642a32 | |
|
57add386c9 | |
|
823e279e0d | |
|
11c15ddfeb | |
|
224c639bf9 | |
|
f48802acbb | |
|
b7278186c4 | |
|
ccf125bf30 | |
|
db0fe9436e | |
|
2c7f57ad5b | |
|
f958b6500b | |
|
346d1abaff | |
|
19610a9e46 | |
|
aee16df63b | |
|
61182249cb | |
|
c12a5d874c | |
|
5e22cc9eec | |
|
5fdce4c331 | |
|
adb7dd99c2 | |
|
b739390955 | |
|
db461112c7 | |
|
7320e311a0 | |
|
a855756017 | |
|
be508c6184 | |
|
6ab71ed7cf | |
|
87d5f5b9a9 | |
|
98a7f9fcf0 | |
|
0e59442f6c | |
|
b90a4f1f4a | |
|
ad36383951 | |
|
6b422a05f3 | |
|
d5e321b792 | |
|
d2030595dc | |
|
d7209a9570 | |
|
1af8f95785 | |
|
3435d2ff15 | |
|
ecc057dd48 | |
|
3207af8827 | |
|
94e80b3da9 | |
|
f32dddc71c | |
|
484a7cc9a7 | |
|
a4bada52d0 | |
|
4df377cfbf | |
|
233be7a0fa | |
|
f622b1cade | |
|
5fcc999b7d | |
|
da3a0ddfe2 | |
|
5e059be1b3 | |
|
bae6ee888f | |
|
81b3c85f51 | |
|
08d3185e87 | |
|
6000e80acf | |
|
7b5e176d1a | |
|
5a48a0fe6b | |
|
700fc7d928 | |
|
8fdab74cc8 | |
|
24ec38d6a0 | |
|
c2f65dd1cf | |
|
63ff4185f9 | |
|
708d62d717 | |
|
c275573147 | |
|
12a1c4940d | |
|
77f6c72cf9 | |
|
8a66990c61 | |
|
05eebe36ab | |
|
1d5abfadd7 | |
|
399aa8531c | |
|
b55ccae72a | |
|
089f6a1c50 | |
|
b64f848d2c | |
|
452b78f243 | |
|
78ced0093a | |
|
d61198941a | |
|
b97165db75 | |
|
4104f29956 | |
|
66743d4f9d | |
|
258311d098 | |
|
5308db0637 | |
|
59fd6aa104 | |
|
560383fe14 | |
|
6277036567 | |
|
ce27ddeba1 | |
|
54e05a2824 | |
|
9a12f34bbe | |
|
54ff9b2972 | |
|
6edfd78c9f | |
|
4431ada1a2 | |
|
24653528cc | |
|
33d8886226 | |
|
04920b3076 | |
|
6ee5dcc0ec | |
|
c4bfd367e2 | |
|
29f1bd22d7 | |
|
8d9519df09 | |
|
7af0271f47 | |
|
be6ec06894 | |
|
beedaa4eff | |
|
bb9937593d | |
|
541bc8dfc2 | |
|
3652ecd9e0 | |
|
14232513fd | |
|
3252f2bc54 | |
|
438edcdf01 | |
|
b7c1290528 | |
|
8037487165 | |
|
e8076d9114 | |
|
ecc4a38b7c | |
|
24c6508d39 | |
|
98cef9fcca | |
|
0c97a411b4 | |
|
faef9a0fce | |
|
293041a290 | |
|
153433f612 | |
|
65271c105f | |
|
a6007373b5 | |
|
3205b53c7c | |
|
9f9550247a | |
|
90967ccb9a | |
|
5bb30270d2 | |
|
1d8b53f782 | |
|
bc5dd3894b | |
|
318592511c | |
|
80cf589a26 | |
|
cc80a47f5b | |
|
3f6b243cec | |
|
72c85e80c8 | |
|
0ec7f713d6 | |
|
a64588f87a | |
|
0e0e8ddcdc | |
|
04994df59f | |
|
6a12b191f7 | |
|
9e9acfb3fe | |
|
0273664009 | |
|
a887e179b8 | |
|
aa6d4c3e92 | |
|
6d49a1e4b7 | |
|
826514b8eb | |
|
c49ce2e1eb | |
|
3237fff4b8 | |
|
6d266f6363 | |
|
17e146ad94 | |
|
80ae10f402 | |
|
7d399e80c3 | |
|
b1385919be | |
|
6a5277d341 | |
|
dcc86ebfce | |
|
180ff8853c | |
|
8a72b74161 | |
|
7255be9626 | |
|
f215de030e | |
|
65bc763634 | |
|
a0db890853 | |
|
11da927fd9 | |
|
cb825687a5 | |
|
51bf0fdd90 | |
|
0da5788efb | |
|
326484a8d1 | |
|
1ce4d95de9 | |
|
1fb188636e | |
|
f62580b947 | |
|
47a89da558 | |
|
09789f2a34 | |
|
aea13d5a10 | |
|
15a0d4afd4 | |
|
f39c71609e | |
|
3c85ec953f | |
|
6b9acd565c | |
|
46b328854a | |
|
f38f3a745a | |
|
b1bdd97564 | |
|
d67c47b81f | |
|
7bfbcfab87 | |
|
8933d75443 | |
|
cc55d7b3cf | |
|
aca7d5637d | |
|
ec2b2394dc | |
|
a7ae372f2f | |
|
4bcd4be6b7 | |
|
8e33b7b3e2 | |
|
4be9f52142 | |
|
bda295d37f | |
|
4d6ae8273a | |
|
c8cf4694c6 | |
|
935ee742b4 | |
|
9930b0fe8e | |
|
ed8ddb6a3a | |
|
84e11a1e82 | |
|
367e1df785 | |
|
2be71d323d | |
|
d614d6bf8c | |
|
32d2f47ed1 | |
|
c9b6110dec | |
|
7dbb2f7e05 | |
|
a3e4013f89 | |
|
fb20cbbf1e | |
|
c49757a459 | |
|
18e703bc93 | |
|
fc74a114b3 | |
|
40f31c3078 | |
|
31fd9c8791 | |
|
38f02e04f4 | |
|
e7264776bd | |
|
ae07dead24 | |
|
0f477df86a | |
|
55332be325 | |
|
b80baaf359 | |
|
2abb7513dc | |
|
d0bf462866 | |
|
4911012cf4 | |
|
57e926c791 | |
|
859d63902e | |
|
0a00e1b608 | |
|
1d7281fe07 | |
|
e374853c75 | |
|
97c830190f | |
|
bda08b11c6 | |
|
ca12e8ebb7 | |
|
7b31099252 | |
|
723091b903 | |
|
dcd25d8f07 | |
|
1e160c199b | |
|
ec8ca69195 | |
|
b7b753b96c | |
|
0afeb1d11c | |
|
4cf8b78c6c | |
|
f3b8f57054 | |
|
c990bba94a | |
|
adedb2a64e | |
|
e1aedecdc6 | |
|
37badc3ce8 | |
|
70f906c51c | |
|
8705dd39c4 | |
|
9532cba45d | |
|
0bc7356ce1 | |
|
f07fb2b607 | |
|
721abdc381 | |
|
0867dce42c | |
|
0ec9192cf2 | |
|
345f18442c | |
|
5f4072423e | |
|
8728c3e4cd | |
|
eb33b8c809 | |
|
79ebf6c39c | |
|
73739a29f4 | |
|
cd1b68cf6e | |
|
0c5f18ab91 | |
|
d48deba273 | |
|
2b2a764143 | |
|
83d777bebf | |
|
b4345cb4eb | |
|
2e8fe7b2f2 | |
|
9659b11a45 | |
|
f139024b1c | |
|
a4ea5df5d5 | |
|
44ffe6c6d6 | |
|
cfa863c357 | |
|
9a4d370ea2 | |
|
6931b25293 | |
|
84c007d34f | |
|
182ce3dd15 | |
|
49498a323b | |
|
f7d9956c0f | |
|
59f81950fe | |
|
8239765a44 | |
|
a05c0c6b72 | |
|
9cb1a7a52d | |
|
e1e4e82096 | |
|
b626a93879 | |
|
c9a5660cfd | |
|
c24f8c8199 | |
|
fa0ceb62f2 | |
|
67c4c7bac2 | |
|
e39d78a0ad | |
|
daf6966c89 | |
|
a361ef6368 | |
|
c2688e4f06 | |
|
e8178f7bfa | |
|
4909e8ff86 | |
|
6a6c83789f | |
|
29676a273a | |
|
15f2ca2c24 | |
|
7ed89d3f9d | |
|
b8b410014d | |
|
7ee9ceb71e | |
|
2f67e0fe4a | |
|
bc3ec352f0 | |
|
b8eb83940c | |
|
3cdcc729a7 | |
|
5cdfeae2e8 | |
|
2ad4d8d717 | |
|
b10b6d4af1 | |
|
4c288bc97e | |
|
4256fc6304 | |
|
c690f529f2 | |
|
fc03d0dfab | |
|
2a33c17854 | |
|
704b68948f | |
|
9c02f07f9b | |
|
1ee22e1736 | |
|
6650764e97 | |
|
604de4b1dc | |
|
ed5b240417 | |
|
aa040c085c | |
|
a18ae3d752 | |
|
4ddb3f73ba | |
|
88069bd417 | |
|
f822891065 | |
|
74c256872b | |
|
94a23a3e24 | |
|
ef85270d9a | |
|
3a35977d5f | |
|
78b42b9ac2 | |
|
261e4a6cf2 | |
|
8f13f5b6d6 | |
|
6d6d986fc5 | |
|
9da947a279 | |
|
3812a52e96 | |
|
836866dc19 | |
|
cabda59353 | |
|
d7b6c1f670 | |
|
fa1ee70668 | |
|
bb1f83c265 | |
|
74e5263c88 | |
|
eeebb5adc7 | |
|
910179f9b0 | |
|
7464e17c5e | |
|
066a35dd32 | |
|
cc66213e57 | |
|
3dc6db9d0c | |
|
75e92090ee | |
|
0d8c8ba71b | |
|
9c3deeee96 | |
|
2c78771238 | |
|
c34c84b690 | |
|
00be8d24ac | |
|
73b9bacbf7 | |
|
36af821edf | |
|
c779ac4f5f | |
|
87584e89fe | |
|
795d3e25aa | |
|
21aaf0ef9a | |
|
cb4ee20117 | |
|
01dec18891 |
|
@ -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"
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
|
|
25
.flake8
|
@ -1,25 +0,0 @@
|
|||
[flake8]
|
||||
extend-select =
|
||||
# bugbear
|
||||
B
|
||||
# bugbear opinions
|
||||
B9
|
||||
# implicit str concat
|
||||
ISC
|
||||
extend-ignore =
|
||||
# slice notation whitespace, invalid
|
||||
E203
|
||||
# line length, handled by bugbear B950
|
||||
E501
|
||||
# bare except, handled by bugbear B001
|
||||
E722
|
||||
# zip with strict=, requires python >= 3.10
|
||||
B905
|
||||
# string formatting opinion, B028 renamed to B907
|
||||
B028
|
||||
B907
|
||||
# up to 88 allowed by bugbear B950
|
||||
max-line-length = 80
|
||||
per-file-ignores =
|
||||
# __init__ exports names
|
||||
src/flask/__init__.py: F401
|
|
@ -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.
|
||||
-->
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
|
@ -1,9 +0,0 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
day: "monday"
|
||||
time: "16:00"
|
||||
timezone: "UTC"
|
|
@ -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.
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
name: 'Lock threads'
|
||||
# Lock closed issues that have not received any further activity for
|
||||
# two weeks. This does not close open issues, only humans may do that.
|
||||
# We find that it is easier to respond to new issues with fresh examples
|
||||
# rather than continuing discussions on old issues.
|
||||
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:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
discussions: write
|
||||
concurrency:
|
||||
group: lock
|
||||
|
||||
jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@c1b35aecc5cdb1a34539d14196df55838bb2f836
|
||||
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
|
||||
with:
|
||||
issue-inactive-days: 14
|
||||
pr-inactive-days: 14
|
||||
discussion-inactive-days: 14
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
name: pre-commit
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main, stable]
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0
|
||||
with:
|
||||
enable-cache: true
|
||||
prune-cache: false
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
id: setup-python
|
||||
with:
|
||||
python-version-file: pyproject.toml
|
||||
- uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit|${{ hashFiles('pyproject.toml', '.pre-commit-config.yaml') }}
|
||||
- run: uv run --locked --group pre-commit pre-commit run --show-diff-on-failure --color=always --all-files
|
||||
- uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
|
||||
if: ${{ !cancelled() }}
|
|
@ -1,72 +1,58 @@
|
|||
name: Publish
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
tags: ['*']
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
hash: ${{ steps.hash.outputs.hash }}
|
||||
artifact-id: ${{ steps.upload-artifact.outputs.artifact-id }}
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
|
||||
- uses: actions/setup-python@5ccb29d8773c3f3f653e1705f474dfaa8a06a912
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
python-version: '3.x'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: 'requirements/*.txt'
|
||||
- run: pip install -r requirements/build.txt
|
||||
# Use the commit date instead of the current date during the build.
|
||||
persist-credentials: false
|
||||
- uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0
|
||||
with:
|
||||
enable-cache: true
|
||||
prune-cache: false
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version-file: pyproject.toml
|
||||
- run: echo "SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV
|
||||
- run: python -m build
|
||||
# Generate hashes used for provenance.
|
||||
- name: generate hash
|
||||
id: hash
|
||||
run: cd dist && echo "hash=$(sha256sum * | base64 -w0)" >> $GITHUB_OUTPUT
|
||||
- uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
|
||||
- run: uv build
|
||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
id: upload-artifact
|
||||
with:
|
||||
path: ./dist
|
||||
provenance:
|
||||
needs: ['build']
|
||||
permissions:
|
||||
actions: read
|
||||
id-token: write
|
||||
contents: write
|
||||
# Can't pin with hash due to how this workflow works.
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0
|
||||
with:
|
||||
base64-subjects: ${{ needs.build.outputs.hash }}
|
||||
name: dist
|
||||
path: dist/
|
||||
if-no-files-found: error
|
||||
create-release:
|
||||
# Upload the sdist, wheels, and provenance to a GitHub release. They remain
|
||||
# available as build artifacts for a while as well.
|
||||
needs: ['provenance']
|
||||
needs: [build]
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
|
||||
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
artifact-ids: ${{ needs.build.outputs.artifact-id }}
|
||||
path: dist/
|
||||
- name: create release
|
||||
run: >
|
||||
gh release create --draft --repo ${{ github.repository }}
|
||||
${{ github.ref_name }}
|
||||
*.intoto.jsonl/* artifact/*
|
||||
run: gh release create --draft --repo ${{ github.repository }} ${{ github.ref_name }} dist/*
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
publish-pypi:
|
||||
needs: ['provenance']
|
||||
# Wait for approval before attempting to upload to PyPI. This allows reviewing the
|
||||
# files in the draft release.
|
||||
environment: 'publish'
|
||||
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@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
|
||||
# Try uploading to Test PyPI first, in case something fails.
|
||||
- uses: pypa/gh-action-pypi-publish@c7f29f7adef1a245bd91520e94867e5c6eedddcc
|
||||
- uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
with:
|
||||
password: ${{ secrets.TEST_PYPI_TOKEN }}
|
||||
repository_url: https://test.pypi.org/legacy/
|
||||
packages_dir: artifact/
|
||||
- uses: pypa/gh-action-pypi-publish@c7f29f7adef1a245bd91520e94867e5c6eedddcc
|
||||
artifact-ids: ${{ needs.build.outputs.artifact-id }}
|
||||
path: dist/
|
||||
- uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
|
||||
with:
|
||||
password: ${{ secrets.PYPI_TOKEN }}
|
||||
packages_dir: artifact/
|
||||
packages-dir: "dist/"
|
||||
|
|
|
@ -1,58 +1,51 @@
|
|||
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']
|
||||
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.11', os: ubuntu-latest, tox: py311}
|
||||
- {name: Windows, python: '3.11', os: windows-latest, tox: py311}
|
||||
- {name: Mac, python: '3.11', os: macos-latest, tox: py311}
|
||||
- {name: '3.12-dev', python: '3.12-dev', os: ubuntu-latest, tox: py312}
|
||||
- {name: '3.10', python: '3.10', os: ubuntu-latest, tox: py310}
|
||||
- {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.9', os: ubuntu-latest, tox: pypy39}
|
||||
- {name: 'Pallets Minimum Versions', python: '3.11', os: ubuntu-latest, tox: py311-min}
|
||||
- {name: 'Pallets Development Versions', python: '3.8', os: ubuntu-latest, tox: py38-dev}
|
||||
- {name: Typing, python: '3.11', os: ubuntu-latest, tox: typing}
|
||||
- {python: '3.13'}
|
||||
- {name: Windows, python: '3.13', os: windows-latest}
|
||||
- {name: Mac, python: '3.13', os: macos-latest}
|
||||
- {python: '3.12'}
|
||||
- {python: '3.11'}
|
||||
- {python: '3.10'}
|
||||
- {name: PyPy, python: 'pypy-3.11', tox: pypy3.11}
|
||||
- {name: Minimum Versions, python: '3.13', tox: tests-min}
|
||||
- {name: Development Versions, python: '3.10', tox: tests-dev}
|
||||
steps:
|
||||
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c
|
||||
- uses: actions/setup-python@5ccb29d8773c3f3f653e1705f474dfaa8a06a912
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0
|
||||
with:
|
||||
enable-cache: true
|
||||
prune-cache: false
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.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: uv run --locked tox run -e ${{ matrix.tox || format('py{0}', matrix.python) }}
|
||||
typing:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: astral-sh/setup-uv@d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1 # v6.5.0
|
||||
with:
|
||||
enable-cache: true
|
||||
prune-cache: false
|
||||
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||
with:
|
||||
python-version-file: pyproject.toml
|
||||
- name: cache mypy
|
||||
uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12
|
||||
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: ./.mypy_cache
|
||||
key: mypy|${{ matrix.python }}|${{ hashFiles('setup.cfg') }}
|
||||
if: matrix.tox == 'typing'
|
||||
- run: pip install tox
|
||||
- run: tox run -e ${{ matrix.tox }}
|
||||
key: mypy|${{ hashFiles('pyproject.toml') }}
|
||||
- run: uv run --locked tox run -e typing
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -1,37 +1,18 @@
|
|||
ci:
|
||||
autoupdate_branch: "2.1.x"
|
||||
autoupdate_schedule: monthly
|
||||
repos:
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v3.3.2
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: 54a455f7ce629598b7535ff828fd5fb796f4b83f # frozen: v0.12.9
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: ["--py37-plus"]
|
||||
- repo: https://github.com/asottile/reorder_python_imports
|
||||
rev: v3.9.0
|
||||
- id: ruff
|
||||
- id: ruff-format
|
||||
- repo: https://github.com/astral-sh/uv-pre-commit
|
||||
rev: f9572a6b06237978e1d52fad0ae55bac5e36da26 # frozen: 0.8.12
|
||||
hooks:
|
||||
- id: reorder-python-imports
|
||||
name: Reorder Python imports (src, tests)
|
||||
files: "^(?!examples/)"
|
||||
args: ["--application-directories", "src"]
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 23.3.0
|
||||
hooks:
|
||||
- id: black
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
- flake8-bugbear
|
||||
- flake8-implicit-str-concat
|
||||
- repo: https://github.com/peterdemin/pip-compile-multi
|
||||
rev: v2.6.2
|
||||
hooks:
|
||||
- id: pip-compile-multi-verify
|
||||
- id: uv-lock
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.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
|
||||
|
|
|
@ -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
|
||||
|
|
213
CHANGES.rst
|
@ -1,3 +1,208 @@
|
|||
Version 3.2.0
|
||||
-------------
|
||||
|
||||
Unreleased
|
||||
|
||||
- Drop support for Python 3.9. :pr:`5730`
|
||||
- Remove previously deprecated code: ``__version__``. :pr:`5648`
|
||||
- ``RequestContext`` has merged with ``AppContext``. ``RequestContext`` is now
|
||||
a deprecated alias. If an app context is already pushed, it is not reused
|
||||
when dispatching a request. This greatly simplifies the internal code for tracking
|
||||
the active context. :issue:`5639`
|
||||
- ``template_filter``, ``template_test``, and ``template_global`` decorators
|
||||
can be used without parentheses. :issue:`5729`
|
||||
|
||||
|
||||
Version 3.1.2
|
||||
-------------
|
||||
|
||||
Released 2025-08-19
|
||||
|
||||
- ``stream_with_context`` does not fail inside async views. :issue:`5774`
|
||||
- When using ``follow_redirects`` in the test client, the final state
|
||||
of ``session`` is correct. :issue:`5786`
|
||||
- Relax type hint for passing bytes IO to ``send_file``. :issue:`5776`
|
||||
|
||||
|
||||
Version 3.1.1
|
||||
-------------
|
||||
|
||||
Released 2025-05-13
|
||||
|
||||
- Fix signing key selection order when key rotation is enabled via
|
||||
``SECRET_KEY_FALLBACKS``. :ghsa:`4grg-w6v8-c28g`
|
||||
- Fix type hint for ``cli_runner.invoke``. :issue:`5645`
|
||||
- ``flask --help`` loads the app and plugins first to make sure all commands
|
||||
are shown. :issue:`5673`
|
||||
- Mark sans-io base class as being able to handle views that return
|
||||
``AsyncIterable``. This is not accurate for Flask, but makes typing easier
|
||||
for Quart. :pr:`5659`
|
||||
|
||||
|
||||
Version 3.1.0
|
||||
-------------
|
||||
|
||||
Released 2024-11-13
|
||||
|
||||
- Drop support for Python 3.8. :pr:`5623`
|
||||
- Update minimum dependency versions to latest feature releases.
|
||||
Werkzeug >= 3.1, ItsDangerous >= 2.2, Blinker >= 1.9. :pr:`5624,5633`
|
||||
- Provide a configuration option to control automatic option
|
||||
responses. :pr:`5496`
|
||||
- ``Flask.open_resource``/``open_instance_resource`` and
|
||||
``Blueprint.open_resource`` take an ``encoding`` parameter to use when
|
||||
opening in text mode. It defaults to ``utf-8``. :issue:`5504`
|
||||
- ``Request.max_content_length`` can be customized per-request instead of only
|
||||
through the ``MAX_CONTENT_LENGTH`` config. Added
|
||||
``MAX_FORM_MEMORY_SIZE`` and ``MAX_FORM_PARTS`` config. Added documentation
|
||||
about resource limits to the security page. :issue:`5625`
|
||||
- Add support for the ``Partitioned`` cookie attribute (CHIPS), with the
|
||||
``SESSION_COOKIE_PARTITIONED`` config. :issue:`5472`
|
||||
- ``-e path`` takes precedence over default ``.env`` and ``.flaskenv`` files.
|
||||
``load_dotenv`` loads default files in addition to a path unless
|
||||
``load_defaults=False`` is passed. :issue:`5628`
|
||||
- Support key rotation with the ``SECRET_KEY_FALLBACKS`` config, a list of old
|
||||
secret keys that can still be used for unsigning. Extensions will need to
|
||||
add support. :issue:`5621`
|
||||
- Fix how setting ``host_matching=True`` or ``subdomain_matching=False``
|
||||
interacts with ``SERVER_NAME``. Setting ``SERVER_NAME`` no longer restricts
|
||||
requests to only that domain. :issue:`5553`
|
||||
- ``Request.trusted_hosts`` is checked during routing, and can be set through
|
||||
the ``TRUSTED_HOSTS`` config. :issue:`5636`
|
||||
|
||||
|
||||
Version 3.0.3
|
||||
-------------
|
||||
|
||||
Released 2024-04-07
|
||||
|
||||
- The default ``hashlib.sha1`` may not be available in FIPS builds. Don't
|
||||
access it at import time so the developer has time to change the default.
|
||||
:issue:`5448`
|
||||
- Don't initialize the ``cli`` attribute in the sansio scaffold, but rather in
|
||||
the ``Flask`` concrete class. :pr:`5270`
|
||||
|
||||
|
||||
Version 3.0.2
|
||||
-------------
|
||||
|
||||
Released 2024-02-03
|
||||
|
||||
- Correct type for ``jinja_loader`` property. :issue:`5388`
|
||||
- Fix error with ``--extra-files`` and ``--exclude-patterns`` CLI options.
|
||||
:issue:`5391`
|
||||
|
||||
|
||||
Version 3.0.1
|
||||
-------------
|
||||
|
||||
Released 2024-01-18
|
||||
|
||||
- Correct type for ``path`` argument to ``send_file``. :issue:`5336`
|
||||
- Fix a typo in an error message for the ``flask run --key`` option. :pr:`5344`
|
||||
- Session data is untagged without relying on the built-in ``json.loads``
|
||||
``object_hook``. This allows other JSON providers that don't implement that.
|
||||
:issue:`5381`
|
||||
- Address more type findings when using mypy strict mode. :pr:`5383`
|
||||
|
||||
|
||||
Version 3.0.0
|
||||
-------------
|
||||
|
||||
Released 2023-09-30
|
||||
|
||||
- Remove previously deprecated code. :pr:`5223`
|
||||
- Deprecate the ``__version__`` attribute. Use feature detection, or
|
||||
``importlib.metadata.version("flask")``, instead. :issue:`5230`
|
||||
- Restructure the code such that the Flask (app) and Blueprint
|
||||
classes have Sans-IO bases. :pr:`5127`
|
||||
- Allow self as an argument to url_for. :pr:`5264`
|
||||
- Require Werkzeug >= 3.0.0.
|
||||
|
||||
|
||||
Version 2.3.3
|
||||
-------------
|
||||
|
||||
Released 2023-08-21
|
||||
|
||||
- Python 3.12 compatibility.
|
||||
- Require Werkzeug >= 2.3.7.
|
||||
- Use ``flit_core`` instead of ``setuptools`` as build backend.
|
||||
- Refactor how an app's root and instance paths are determined. :issue:`5160`
|
||||
|
||||
|
||||
Version 2.3.2
|
||||
-------------
|
||||
|
||||
Released 2023-05-01
|
||||
|
||||
- Set ``Vary: Cookie`` header when the session is accessed, modified, or refreshed.
|
||||
- Update Werkzeug requirement to >=2.3.3 to apply recent bug fixes.
|
||||
:ghsa:`m2qf-hxjv-5gpq`
|
||||
|
||||
|
||||
Version 2.3.1
|
||||
-------------
|
||||
|
||||
Released 2023-04-25
|
||||
|
||||
- Restore deprecated ``from flask import Markup``. :issue:`5084`
|
||||
|
||||
|
||||
Version 2.3.0
|
||||
-------------
|
||||
|
||||
Released 2023-04-25
|
||||
|
||||
- Drop support for Python 3.7. :pr:`5072`
|
||||
- Update minimum requirements to the latest versions: Werkzeug>=2.3.0, Jinja2>3.1.2,
|
||||
itsdangerous>=2.1.2, click>=8.1.3.
|
||||
- Remove previously deprecated code. :pr:`4995`
|
||||
|
||||
- The ``push`` and ``pop`` methods of the deprecated ``_app_ctx_stack`` and
|
||||
``_request_ctx_stack`` objects are removed. ``top`` still exists to give
|
||||
extensions more time to update, but it will be removed.
|
||||
- The ``FLASK_ENV`` environment variable, ``ENV`` config key, and ``app.env``
|
||||
property are removed.
|
||||
- The ``session_cookie_name``, ``send_file_max_age_default``, ``use_x_sendfile``,
|
||||
``propagate_exceptions``, and ``templates_auto_reload`` properties on ``app``
|
||||
are removed.
|
||||
- The ``JSON_AS_ASCII``, ``JSON_SORT_KEYS``, ``JSONIFY_MIMETYPE``, and
|
||||
``JSONIFY_PRETTYPRINT_REGULAR`` config keys are removed.
|
||||
- The ``app.before_first_request`` and ``bp.before_app_first_request`` decorators
|
||||
are removed.
|
||||
- ``json_encoder`` and ``json_decoder`` attributes on app and blueprint, and the
|
||||
corresponding ``json.JSONEncoder`` and ``JSONDecoder`` classes, are removed.
|
||||
- The ``json.htmlsafe_dumps`` and ``htmlsafe_dump`` functions are removed.
|
||||
- Calling setup methods on blueprints after registration is an error instead of a
|
||||
warning. :pr:`4997`
|
||||
|
||||
- Importing ``escape`` and ``Markup`` from ``flask`` is deprecated. Import them
|
||||
directly from ``markupsafe`` instead. :pr:`4996`
|
||||
- The ``app.got_first_request`` property is deprecated. :pr:`4997`
|
||||
- The ``locked_cached_property`` decorator is deprecated. Use a lock inside the
|
||||
decorated function if locking is needed. :issue:`4993`
|
||||
- Signals are always available. ``blinker>=1.6.2`` is a required dependency. The
|
||||
``signals_available`` attribute is deprecated. :issue:`5056`
|
||||
- Signals support ``async`` subscriber functions. :pr:`5049`
|
||||
- Remove uses of locks that could cause requests to block each other very briefly.
|
||||
:issue:`4993`
|
||||
- Use modern packaging metadata with ``pyproject.toml`` instead of ``setup.cfg``.
|
||||
:pr:`4947`
|
||||
- Ensure subdomains are applied with nested blueprints. :issue:`4834`
|
||||
- ``config.from_file`` can use ``text=False`` to indicate that the parser wants a
|
||||
binary file instead. :issue:`4989`
|
||||
- If a blueprint is created with an empty name it raises a ``ValueError``.
|
||||
:issue:`5010`
|
||||
- ``SESSION_COOKIE_DOMAIN`` does not fall back to ``SERVER_NAME``. The default is not
|
||||
to set the domain, which modern browsers interpret as an exact match rather than
|
||||
a subdomain match. Warnings about ``localhost`` and IP addresses are also removed.
|
||||
:issue:`5051`
|
||||
- The ``routes`` command shows each rule's ``subdomain`` or ``host`` when domain
|
||||
matching is in use. :issue:`5004`
|
||||
- Use postponed evaluation of annotations. :pr:`5071`
|
||||
|
||||
|
||||
Version 2.2.5
|
||||
-------------
|
||||
|
||||
|
@ -227,7 +432,7 @@ Released 2022-03-28
|
|||
or ``AppContext.g`` instead. :issue:`3898`
|
||||
- ``copy_current_request_context`` can decorate async functions.
|
||||
:pr:`4303`
|
||||
- The CLI uses ``importlib.metadata`` instead of ``setuptools`` to
|
||||
- The CLI uses ``importlib.metadata`` instead of ``pkg_resources`` to
|
||||
load command entry points. :issue:`4419`
|
||||
- Overriding ``FlaskClient.open`` will not cause an error on redirect.
|
||||
:issue:`3396`
|
||||
|
@ -704,7 +909,7 @@ Released 2018-04-26
|
|||
explicitly for each exception if you want to avoid traversing the
|
||||
MRO. :pr:`2362`
|
||||
- Fix incorrect JSON encoding of aware, non-UTC datetimes. :pr:`2374`
|
||||
- Template auto reloading will honor debug mode even even if
|
||||
- Template auto reloading will honor debug mode even if
|
||||
``Flask.jinja_env`` was already accessed. :pr:`2373`
|
||||
- The following old deprecated code was removed. :issue:`2385`
|
||||
|
||||
|
@ -1186,7 +1391,7 @@ Released 2011-09-29, codename Rakija
|
|||
of Flask itself and no longer of the test client. This cleaned up
|
||||
some internal logic and lowers the odds of runaway request contexts
|
||||
in unittests.
|
||||
- Fixed the Jinja2 environment's ``list_templates`` method not
|
||||
- Fixed the Jinja environment's ``list_templates`` method not
|
||||
returning the correct names when blueprints or modules were
|
||||
involved.
|
||||
|
||||
|
@ -1272,7 +1477,7 @@ Released 2010-12-31
|
|||
|
||||
- Fixed an issue where the default ``OPTIONS`` response was not
|
||||
exposing all valid methods in the ``Allow`` header.
|
||||
- Jinja2 template loading syntax now allows "./" in front of a
|
||||
- Jinja template loading syntax now allows "./" in front of a
|
||||
template load path. Previously this caused issues with module
|
||||
setups.
|
||||
- Fixed an issue where the subdomain setting for modules was ignored
|
||||
|
|
|
@ -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
|
227
CONTRIBUTING.rst
|
@ -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://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/>`__.
|
11
MANIFEST.in
|
@ -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
|
|
@ -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/
|
82
README.rst
|
@ -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
|
|
@ -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.
|
Before Width: | Height: | Size: 77 KiB |
|
@ -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 |
Before Width: | Height: | Size: 6.8 KiB |
|
@ -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.0 KiB |
Before Width: | Height: | Size: 14 KiB |
|
@ -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 |
|
@ -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 |
Before Width: | Height: | Size: 259 B |
Before Width: | Height: | Size: 241 B |
166
docs/api.rst
|
@ -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
|
||||
|
@ -158,20 +149,21 @@ another, a global variable is not good enough because it would break in
|
|||
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`.
|
||||
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.
|
||||
|
@ -185,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
|
||||
|
||||
|
@ -217,10 +208,6 @@ Useful Functions and Classes
|
|||
|
||||
.. autofunction:: send_from_directory
|
||||
|
||||
.. autofunction:: escape
|
||||
|
||||
.. autoclass:: Markup
|
||||
:members: escape, unescape, striptags
|
||||
|
||||
Message Flashing
|
||||
----------------
|
||||
|
@ -270,12 +257,6 @@ HTML ``<script>`` tags.
|
|||
:members:
|
||||
:member-order: bysource
|
||||
|
||||
.. autoclass:: JSONEncoder
|
||||
:members:
|
||||
|
||||
.. autoclass:: JSONDecoder
|
||||
:members:
|
||||
|
||||
.. automodule:: flask.json.tag
|
||||
|
||||
|
||||
|
@ -309,31 +290,31 @@ Stream Helpers
|
|||
Useful Internals
|
||||
----------------
|
||||
|
||||
.. autoclass:: flask.ctx.RequestContext
|
||||
:members:
|
||||
|
||||
.. data:: flask.globals.request_ctx
|
||||
|
||||
The current :class:`~flask.ctx.RequestContext`. If a request context
|
||||
is not active, accessing attributes on this proxy will raise a
|
||||
``RuntimeError``.
|
||||
|
||||
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:`request` and :data:`session` instead.
|
||||
|
||||
.. autoclass:: flask.ctx.AppContext
|
||||
:members:
|
||||
|
||||
.. data:: flask.globals.app_ctx
|
||||
|
||||
The current :class:`~flask.ctx.AppContext`. If an app context is not
|
||||
active, accessing attributes on this proxy will raise a
|
||||
``RuntimeError``.
|
||||
A proxy to the active :class:`.AppContext`.
|
||||
|
||||
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` and :data:`g` instead.
|
||||
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:
|
||||
|
@ -343,14 +324,9 @@ 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
|
||||
|
||||
|
@ -517,7 +493,6 @@ The following signals exist in Flask:
|
|||
|
||||
.. versionadded:: 0.10
|
||||
|
||||
|
||||
.. data:: message_flashed
|
||||
|
||||
This signal is sent when the application is flashing a message. The
|
||||
|
@ -535,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
|
||||
-----------------
|
||||
|
|
|
@ -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,72 +67,120 @@ 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.
|
||||
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 requet 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)
|
||||
|
||||
|
||||
Lifcycle 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 and will not fail.
|
||||
|
||||
|
||||
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.
|
||||
|
|
|
@ -23,12 +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
|
||||
|
|
|
@ -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.
|
||||
|
|
41
docs/cli.rst
|
@ -288,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"
|
||||
|
||||
|
@ -446,24 +446,16 @@ 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
|
||||
|
@ -501,19 +493,12 @@ 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 ``--app``. ::
|
||||
|
|
25
docs/conf.py
|
@ -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),
|
||||
|
@ -31,7 +38,6 @@ intersphinx_mapping = {
|
|||
"wtforms": ("https://wtforms.readthedocs.io/", 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 -----------------------------------------------------
|
||||
|
||||
|
|
207
docs/config.rst
|
@ -65,18 +65,6 @@ Builtin Configuration Values
|
|||
|
||||
The following configuration values are used internally by Flask:
|
||||
|
||||
.. py:data:: ENV
|
||||
|
||||
What environment the app is running in. The :attr:`~flask.Flask.env` attribute maps
|
||||
to this config key.
|
||||
|
||||
Default: ``'production'``
|
||||
|
||||
.. deprecated:: 2.2
|
||||
Will be removed in Flask 2.3. Use ``--debug`` instead.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
.. py:data:: DEBUG
|
||||
|
||||
Whether debug mode is enabled. When using ``flask run`` to start the development
|
||||
|
@ -137,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
|
||||
|
@ -146,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
|
||||
|
@ -174,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
|
||||
|
@ -226,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 /
|
||||
|
@ -265,57 +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.
|
||||
|
||||
.. deprecated:: 2.2
|
||||
Will be removed in Flask 2.3. Set ``app.json.ensure_ascii``
|
||||
instead.
|
||||
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.
|
||||
|
||||
.. py:data:: JSON_SORT_KEYS
|
||||
Default: ``500_000``
|
||||
|
||||
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.
|
||||
.. versionadded:: 3.1
|
||||
|
||||
Default: ``True``
|
||||
.. py:data:: MAX_FORM_PARTS
|
||||
|
||||
.. deprecated:: 2.2
|
||||
Will be removed in Flask 2.3. Set ``app.json.sort_keys``
|
||||
instead.
|
||||
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.
|
||||
|
||||
.. py:data:: JSONIFY_PRETTYPRINT_REGULAR
|
||||
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.
|
||||
|
||||
:func:`~flask.jsonify` responses will be output with newlines,
|
||||
spaces, and indentation for easier reading by humans. Always enabled
|
||||
in debug mode.
|
||||
Default: ``1_000``
|
||||
|
||||
Default: ``False``
|
||||
|
||||
.. deprecated:: 2.2
|
||||
Will be removed in Flask 2.3. Set ``app.json.compact`` instead.
|
||||
|
||||
.. py:data:: JSONIFY_MIMETYPE
|
||||
|
||||
The mimetype of ``jsonify`` responses.
|
||||
|
||||
Default: ``'application/json'``
|
||||
|
||||
.. deprecated:: 2.2
|
||||
Will be removed in Flask 2.3. Set ``app.json.mimetype`` instead.
|
||||
.. versionadded:: 3.1
|
||||
|
||||
.. py:data:: TEMPLATES_AUTO_RELOAD
|
||||
|
||||
|
@ -338,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``
|
||||
|
||||
|
@ -381,14 +437,17 @@ The following configuration values are used internally by Flask:
|
|||
.. versionchanged:: 2.2
|
||||
Removed ``PRESERVE_CONTEXT_ON_EXCEPTION``.
|
||||
|
||||
.. versionchanged:: 2.2
|
||||
``JSON_AS_ASCII``, ``JSON_SORT_KEYS``,
|
||||
``JSONIFY_MIMETYPE``, and ``JSONIFY_PRETTYPRINT_REGULAR`` will be
|
||||
removed in Flask 2.3. The default ``app.json`` provider has
|
||||
.. 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.2
|
||||
``ENV`` will be removed in Flask 2.3. Use ``--debug`` instead.
|
||||
.. versionchanged:: 2.3
|
||||
``ENV`` was removed.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
Added :data:`PROVIDE_AUTOMATIC_OPTIONS` to control the default
|
||||
addition of autogenerated OPTIONS responses.
|
||||
|
||||
|
||||
Configuring from Python Files
|
||||
|
@ -469,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:
|
||||
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -34,8 +34,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 eventlet
|
||||
|
||||
|
|
|
@ -33,8 +33,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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -150,7 +150,7 @@ 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
|
||||
|
@ -169,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
|
||||
|
@ -208,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.
|
||||
|
||||
|
|
|
@ -231,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
|
||||
|
|
|
@ -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,13 +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 request, use
|
||||
:meth:`~flask.Flask.teardown_request`.
|
||||
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
|
||||
|
@ -293,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/
|
||||
|
|
|
@ -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,14 +19,13 @@ 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
|
||||
|
@ -50,14 +52,13 @@ community-maintained extensions to add even more functionality.
|
|||
views
|
||||
lifecycle
|
||||
appcontext
|
||||
reqcontext
|
||||
blueprints
|
||||
extensions
|
||||
cli
|
||||
server
|
||||
shell
|
||||
patterns/index
|
||||
security
|
||||
web-security
|
||||
deploying/index
|
||||
async-await
|
||||
|
||||
|
|
|
@ -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://blinker.readthedocs.io/en/stable/
|
||||
.. _python-dotenv: https://github.com/theskumar/python-dotenv#readme
|
||||
.. _watchdog: https://pythonhosted.org/watchdog/
|
||||
|
||||
|
@ -85,7 +84,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 +94,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 +102,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 +118,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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -117,15 +117,12 @@ the view function, and pass the return value back to the server. But there are m
|
|||
parts that you can use to customize its behavior.
|
||||
|
||||
#. WSGI server calls the Flask object, which calls :meth:`.Flask.wsgi_app`.
|
||||
#. A :class:`.RequestContext` object is created. This converts the WSGI ``environ``
|
||||
dict into a :class:`.Request` object. It also creates an :class:`AppContext` object.
|
||||
#. The :doc:`app context <appcontext>` is pushed, which makes :data:`.current_app` and
|
||||
:data:`.g` available.
|
||||
#. 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 :doc:`request context <reqcontext>` is pushed, which makes :attr:`.request` and
|
||||
:class:`.session` available.
|
||||
#. The session is opened, loading any existing session data using the app's
|
||||
:attr:`~.Flask.session_interface`, an instance of :class:`.SessionInterface`.
|
||||
#. 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.
|
||||
|
@ -141,7 +138,8 @@ parts that you can use to customize its behavior.
|
|||
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, then cleared.
|
||||
#. 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
|
||||
|
@ -154,14 +152,19 @@ parts that you can use to customize its behavior.
|
|||
#. 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.
|
||||
#. The request context is popped, :attr:`.request` and :class:`.session` are no longer
|
||||
available.
|
||||
#. 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` and :data:`.g` are no longer
|
||||
available.
|
||||
#. 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
|
||||
|
|
|
@ -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'),
|
||||
):
|
||||
|
|
|
@ -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,7 +77,9 @@ 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
|
||||
|
||||
|
@ -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,10 +135,12 @@ 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:
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -99,9 +99,9 @@ to the factory like this:
|
|||
|
||||
.. code-block:: text
|
||||
|
||||
$ flask --app hello:create_app(local_auth=True) run``
|
||||
$ flask --app 'hello:create_app(local_auth=True)' run
|
||||
|
||||
Then the ``create_app`` factory in ``myapp`` is called with the keyword
|
||||
Then the ``create_app`` factory in ``hello`` is called with the keyword
|
||||
argument ``local_auth=True``. See :doc:`/cli` for more detail.
|
||||
|
||||
Factory Improvements
|
||||
|
|
|
@ -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`::
|
||||
|
|
|
@ -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,
|
||||
|
@ -197,7 +197,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>
|
||||
|
||||
|
||||
|
|
|
@ -80,7 +80,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
|
||||
|
|
|
@ -42,19 +42,20 @@ 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",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["flit_core<4"]
|
||||
build-backend = "flit_core.buildapi"
|
||||
|
||||
Install your application so it is importable:
|
||||
|
||||
|
@ -100,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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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::
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ debug environments with profilers and other things you might have enabled.
|
|||
Streaming from Templates
|
||||
------------------------
|
||||
|
||||
The Jinja2 template engine supports rendering a template piece by
|
||||
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.
|
||||
|
@ -49,13 +49,13 @@ the template.
|
|||
Streaming with Context
|
||||
----------------------
|
||||
|
||||
The :data:`~flask.request` will not be active while the generator is
|
||||
running, because the view has already returned at that point. If you try
|
||||
to access ``request``, you'll get a ``RuntimeError``.
|
||||
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``.
|
||||
|
||||
If your generator function relies on data in ``request``, use the
|
||||
:func:`~flask.stream_with_context` wrapper. This will keep the request
|
||||
context active during the generator.
|
||||
:func:`.stream_with_context` wrapper. This will keep the request context active
|
||||
during the generator.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -139,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
|
||||
|
@ -260,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
|
||||
|
||||
|
@ -354,12 +352,12 @@ 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, any anything else.
|
||||
emails, and anything else.
|
||||
|
||||
For a reference to HTML, CSS, and other web APIs, use the `MDN Web Docs`_.
|
||||
|
||||
|
@ -375,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
|
||||
|
@ -394,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:
|
||||
|
@ -404,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 %}
|
||||
|
@ -419,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
|
||||
|
@ -451,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 interanlly 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
|
||||
|
|
|
@ -1,248 +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 has
|
||||
a different context space and will not know about the request the parent
|
||||
thread was pointing to.
|
||||
|
||||
Context locals are implemented using Python's :mod:`contextvars` and
|
||||
Werkzeug's :class:`~werkzeug.local.LocalProxy`. Python manages the
|
||||
lifetime of context vars automatically, and local proxy wraps that
|
||||
low-level interface to make the data easier to work with.
|
||||
|
||||
|
||||
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", query_string={"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 like stacks. When contexts are pushed, the
|
||||
proxies that depend on them are available and point at information from
|
||||
the top item.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
.. _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.
|
||||
|
|
|
@ -76,8 +76,8 @@ 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.
|
||||
|
||||
|
||||
Deferred Errors on Reload
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
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``, ``.xhtml``, as well as ``.svg`` when using
|
||||
|
@ -25,13 +25,13 @@ Unless customized, Jinja2 is configured by Flask as follows:
|
|||
- 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 avaialble 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
|
||||
------------------
|
||||
|
@ -211,7 +237,7 @@ 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 Jinja2 template engine supports rendering a template piece
|
||||
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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ response is sent.
|
|||
:caption: ``flaskr/db.py``
|
||||
|
||||
import sqlite3
|
||||
from datetime import datetime
|
||||
|
||||
import click
|
||||
from flask import current_app, g
|
||||
|
@ -59,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
|
||||
|
@ -132,6 +133,11 @@ Add the Python functions that will run these SQL commands to the
|
|||
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``
|
||||
|
@ -142,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
|
||||
-----------------------------
|
||||
|
|
|
@ -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}
|
||||
|
@ -54,7 +45,7 @@ create the database in the instance folder.
|
|||
|
||||
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
|
||||
|
@ -77,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'
|
||||
|
||||
|
|
|
@ -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,50 +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,
|
||||
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
|
||||
|
@ -83,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``.
|
||||
|
||||
|
@ -103,9 +79,7 @@ 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.
|
||||
``--app`` is still set to ``flaskr`` and ``flask run`` still runs
|
||||
|
|
|
@ -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,8 +80,8 @@ By the end, your project layout will look like this:
|
|||
│ ├── test_db.py
|
||||
│ ├── test_auth.py
|
||||
│ └── test_blog.py
|
||||
├── venv/
|
||||
├── setup.py
|
||||
├── .venv/
|
||||
├── pyproject.toml
|
||||
└── MANIFEST.in
|
||||
|
||||
If you're using version control, the following files that are generated
|
||||
|
@ -92,7 +92,7 @@ write. For example, with git:
|
|||
.. code-block:: none
|
||||
:caption: ``.gitignore``
|
||||
|
||||
venv/
|
||||
.venv/
|
||||
|
||||
*.pyc
|
||||
__pycache__/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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%]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -249,7 +249,7 @@ provide get (list) and post (create) methods.
|
|||
init_every_request = False
|
||||
|
||||
def __init__(self, model):
|
||||
self.model
|
||||
self.model = model
|
||||
self.validator = generate_validator(model)
|
||||
|
||||
def _get_item(self, id):
|
||||
|
|
|
@ -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
|
|
@ -3,9 +3,15 @@ name = "flask-example-celery"
|
|||
version = "1.0.0"
|
||||
description = "Example Flask application with Celery background tasks."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.7"
|
||||
dependencies = ["flask>=2.2.2", "celery[redis]>=5.2.7"]
|
||||
classifiers = ["Private :: Do Not Upload"]
|
||||
dependencies = ["flask", "celery[redis]"]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
requires = ["flit_core<4"]
|
||||
build-backend = "flit_core.buildapi"
|
||||
|
||||
[tool.flit.module]
|
||||
name = "task_app"
|
||||
|
||||
[tool.ruff]
|
||||
src = ["src"]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#
|
||||
# This file is autogenerated by pip-compile with Python 3.10
|
||||
# This file is autogenerated by pip-compile with Python 3.11
|
||||
# by the following command:
|
||||
#
|
||||
# pip-compile --resolver=backtracking pyproject.toml
|
||||
|
@ -10,6 +10,8 @@ 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
|
||||
|
@ -25,7 +27,7 @@ click-plugins==1.1.1
|
|||
# via celery
|
||||
click-repl==0.2.0
|
||||
# via celery
|
||||
flask==2.2.3
|
||||
flask==2.3.2
|
||||
# via flask-example-celery (pyproject.toml)
|
||||
itsdangerous==2.1.2
|
||||
# via flask
|
||||
|
@ -37,11 +39,11 @@ markupsafe==2.1.2
|
|||
# via
|
||||
# jinja2
|
||||
# werkzeug
|
||||
prompt-toolkit==3.0.37
|
||||
prompt-toolkit==3.0.38
|
||||
# via click-repl
|
||||
pytz==2022.7.1
|
||||
pytz==2023.3
|
||||
# via celery
|
||||
redis==4.5.1
|
||||
redis==4.5.4
|
||||
# via celery
|
||||
six==1.16.0
|
||||
# via click-repl
|
||||
|
@ -52,5 +54,5 @@ vine==5.0.0
|
|||
# kombu
|
||||
wcwidth==0.2.6
|
||||
# via prompt-toolkit
|
||||
werkzeug==2.2.3
|
||||
werkzeug==2.3.3
|
||||
# via flask
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
venv/
|
||||
.venv/
|
||||
*.pyc
|
||||
__pycache__/
|
||||
instance/
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
include LICENSE.rst
|
||||
graft js_example/templates
|
||||
graft tests
|
||||
global-exclude *.pyc
|
|
@ -15,7 +15,7 @@ page. Demonstrates using |fetch|_, |XMLHttpRequest|_, and
|
|||
.. |jQuery.ajax| replace:: ``jQuery.ajax``
|
||||
.. _jQuery.ajax: https://api.jquery.com/jQuery.ajax/
|
||||
|
||||
.. _Flask docs: https://flask.palletsprojects.com/patterns/jquery/
|
||||
.. _Flask docs: https://flask.palletsprojects.com/patterns/javascript/
|
||||
|
||||
|
||||
Install
|
||||
|
@ -23,8 +23,8 @@ Install
|
|||
|
||||
.. code-block:: text
|
||||
|
||||
$ python3 -m venv venv
|
||||
$ . venv/bin/activate
|
||||
$ python3 -m venv .venv
|
||||
$ . .venv/bin/activate
|
||||
$ pip install -e .
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ from flask import jsonify
|
|||
from flask import render_template
|
||||
from flask import request
|
||||
|
||||
from js_example import app
|
||||
from . import app
|
||||
|
||||
|
||||
@app.route("/", defaults={"js": "fetch"})
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
[project]
|
||||
name = "js_example"
|
||||
version = "1.1.0"
|
||||
description = "Demonstrates making AJAX requests to Flask."
|
||||
readme = "README.rst"
|
||||
license = {file = "LICENSE.txt"}
|
||||
maintainers = [{name = "Pallets", email = "contact@palletsprojects.com"}]
|
||||
classifiers = ["Private :: Do Not Upload"]
|
||||
dependencies = ["flask"]
|
||||
|
||||
[project.urls]
|
||||
Documentation = "https://flask.palletsprojects.com/patterns/javascript/"
|
||||
|
||||
[project.optional-dependencies]
|
||||
test = ["pytest"]
|
||||
|
||||
[build-system]
|
||||
requires = ["flit_core<4"]
|
||||
build-backend = "flit_core.buildapi"
|
||||
|
||||
[tool.flit.module]
|
||||
name = "js_example"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
filterwarnings = ["error"]
|
||||
|
||||
[tool.coverage.run]
|
||||
branch = true
|
||||
source = ["js_example", "tests"]
|
||||
|
||||
[tool.ruff]
|
||||
src = ["src"]
|
|
@ -1,29 +0,0 @@
|
|||
[metadata]
|
||||
name = js_example
|
||||
version = 1.1.0
|
||||
url = https://flask.palletsprojects.com/patterns/jquery/
|
||||
license = BSD-3-Clause
|
||||
maintainer = Pallets
|
||||
maintainer_email = contact@palletsprojects.com
|
||||
description = Demonstrates making AJAX requests to Flask.
|
||||
long_description = file: README.rst
|
||||
long_description_content_type = text/x-rst
|
||||
|
||||
[options]
|
||||
packages = find:
|
||||
include_package_data = true
|
||||
install_requires =
|
||||
Flask
|
||||
|
||||
[options.extras_require]
|
||||
test =
|
||||
pytest
|
||||
blinker
|
||||
|
||||
[tool:pytest]
|
||||
testpaths = tests
|
||||
|
||||
[coverage:run]
|
||||
branch = True
|
||||
source =
|
||||
js_example
|
|
@ -1,3 +0,0 @@
|
|||
from setuptools import setup
|
||||
|
||||
setup()
|
|
@ -5,7 +5,7 @@ from flask import template_rendered
|
|||
@pytest.mark.parametrize(
|
||||
("path", "template_name"),
|
||||
(
|
||||
("/", "xhr.html"),
|
||||
("/", "fetch.html"),
|
||||
("/plain", "xhr.html"),
|
||||
("/fetch", "fetch.html"),
|
||||
("/jquery", "jquery.html"),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
venv/
|
||||
.venv/
|
||||
*.pyc
|
||||
__pycache__/
|
||||
instance/
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
include LICENSE.rst
|
||||
include flaskr/schema.sql
|
||||
graft flaskr/static
|
||||
graft flaskr/templates
|
||||
graft tests
|
||||
global-exclude *.pyc
|
|
@ -23,13 +23,13 @@ default Git version is the main branch. ::
|
|||
|
||||
Create a virtualenv and activate it::
|
||||
|
||||
$ python3 -m venv venv
|
||||
$ . venv/bin/activate
|
||||
$ python3 -m venv .venv
|
||||
$ . .venv/bin/activate
|
||||
|
||||
Or on Windows cmd::
|
||||
|
||||
$ py -3 -m venv venv
|
||||
$ venv\Scripts\activate.bat
|
||||
$ py -3 -m venv .venv
|
||||
$ .venv\Scripts\activate.bat
|
||||
|
||||
Install Flaskr::
|
||||
|
||||
|
|
|
@ -31,12 +31,13 @@ def create_app(test_config=None):
|
|||
return "Hello, World!"
|
||||
|
||||
# register the database commands
|
||||
from flaskr import db
|
||||
from . import db
|
||||
|
||||
db.init_app(app)
|
||||
|
||||
# apply the blueprints to the app
|
||||
from flaskr import auth, blog
|
||||
from . import auth
|
||||
from . import blog
|
||||
|
||||
app.register_blueprint(auth.bp)
|
||||
app.register_blueprint(blog.bp)
|
||||
|
|
|
@ -11,7 +11,7 @@ from flask import url_for
|
|||
from werkzeug.security import check_password_hash
|
||||
from werkzeug.security import generate_password_hash
|
||||
|
||||
from flaskr.db import get_db
|
||||
from .db import get_db
|
||||
|
||||
bp = Blueprint("auth", __name__, url_prefix="/auth")
|
||||
|
||||
|
|