Compare commits
2614 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a5a9658896 | ||
![]() |
91d7e6a77d | ||
![]() |
eb3d78f687 | ||
![]() |
d255d1aae1 | ||
![]() |
47215d4635 | ||
![]() |
38ff9069f3 | ||
![]() |
4dde4572ec | ||
![]() |
31d14704cb | ||
![]() |
6a89f4b2fe | ||
![]() |
16256522f6 | ||
![]() |
205795d1e8 | ||
![]() |
9cbe1fb8ad | ||
![]() |
31d7ba8f8c | ||
![]() |
dc3c4d1393 | ||
![]() |
929d270569 | ||
![]() |
93714df051 | ||
![]() |
6e61eab872 | ||
![]() |
6848ff24d8 | ||
![]() |
666371bb92 | ||
![]() |
4a2b82e42e | ||
![]() |
5dd1623192 | ||
![]() |
976da69e79 | ||
![]() |
11a0b15194 | ||
![]() |
c21999a248 | ||
![]() |
c17230ef94 | ||
![]() |
049983cb70 | ||
![]() |
e374409567 | ||
![]() |
4068a0d83d | ||
![]() |
70da5e9879 | ||
![]() |
f48506d620 | ||
![]() |
f2cc83c1ba | ||
![]() |
273825dab6 | ||
![]() |
9a7dafd531 | ||
![]() |
50117d174c | ||
![]() |
af67801062 | ||
![]() |
6eaab2a7e5 | ||
![]() |
d680af3709 | ||
![]() |
a8c2d77c91 | ||
![]() |
6e1c787e5d | ||
![]() |
932088e37e | ||
![]() |
1a63b9bec0 | ||
![]() |
61aa16f6ac | ||
![]() |
71cd53b64e | ||
![]() |
89188f5fc6 | ||
![]() |
a245ab3773 | ||
![]() |
ac1f56118a | ||
![]() |
53820bc241 | ||
![]() |
009954003c | ||
![]() |
8f265b8169 | ||
![]() |
5ee36fd933 | ||
![]() |
08a81c81be | ||
![]() |
5a0ed75171 | ||
![]() |
d62a92fac9 | ||
![]() |
88c918e72f | ||
![]() |
c8aab8fb3d | ||
![]() |
ecacfd396b | ||
![]() |
3c361e9852 | ||
![]() |
a5d7d03413 | ||
![]() |
259e458847 | ||
![]() |
cb49c2b26d | ||
![]() |
dfc0704831 | ||
![]() |
d238995f1b | ||
![]() |
6f5303e080 | ||
![]() |
5e7f6998bd | ||
![]() |
c7a71cd00c | ||
![]() |
9cb9e88678 | ||
![]() |
30c53b6857 | ||
![]() |
4ad8168bb0 | ||
![]() |
28f5b3c301 | ||
![]() |
c573019e7f | ||
![]() |
029f564032 | ||
![]() |
2abe66b670 | ||
![]() |
911485d52e | ||
![]() |
4744a89c33 | ||
![]() |
f7040ccec8 | ||
![]() |
518152d97e | ||
![]() |
0e44e9cacb | ||
![]() |
bfb54b0969 | ||
![]() |
154863d6c6 | ||
![]() |
a3ff0c13b7 | ||
![]() |
95ee518aec | ||
![]() |
71d3d87bcc | ||
![]() |
b276b91c21 | ||
![]() |
064168f3c8 | ||
![]() |
db39e127bf | ||
![]() |
13e9ab7ba9 | ||
![]() |
92e7463721 | ||
![]() |
8e720365c2 | ||
![]() |
d4041161c7 | ||
![]() |
f32437bf13 | ||
![]() |
0909e94527 | ||
![]() |
aef2673c38 | ||
![]() |
4c14910d5b | ||
![]() |
beae35f921 | ||
![]() |
ad4e526c77 | ||
![]() |
4422d0c34d | ||
![]() |
ad9183d21d | ||
![]() |
d70636ba2e | ||
![]() |
da23f85675 | ||
![]() |
3f4663b9f8 | ||
![]() |
65d7447cf6 | ||
![]() |
5369291c27 | ||
![]() |
1c4925edf7 | ||
![]() |
6b9edfd05c | ||
![]() |
97f33f42df | ||
![]() |
15a588a90c | ||
![]() |
82421e7efc | ||
![]() |
f891995b48 | ||
![]() |
5052321801 | ||
![]() |
23ce4eaaa4 | ||
![]() |
23a430c4ad | ||
![]() |
ec158ffa69 | ||
![]() |
6e32270036 | ||
![]() |
43ba381e7b | ||
![]() |
16503319e5 | ||
![]() |
389363ab71 | ||
![]() |
7f894c45b3 | ||
![]() |
4726cf1910 | ||
![]() |
d352a4155e | ||
![]() |
e5010286b4 | ||
![]() |
358498db96 | ||
![]() |
e4999401ab | ||
![]() |
c8df0aa2cb | ||
![]() |
5fb207176b | ||
![]() |
a12b560478 | ||
![]() |
753ee992a6 | ||
![]() |
09089b1bd3 | ||
![]() |
7ddbe5e844 | ||
![]() |
ab5a7038af | ||
![]() |
4f3c780dc3 | ||
![]() |
71f7765a4c | ||
![]() |
0392d1dcfc | ||
![]() |
7827b1b41d | ||
![]() |
8e9342e188 | ||
![]() |
2f6f2bfa76 | ||
![]() |
dee09d7fff | ||
![]() |
9cf38a0a83 | ||
![]() |
3def3d3569 | ||
![]() |
e100a14fd4 | ||
![]() |
2fa28f1711 | ||
![]() |
9d415e4ec6 | ||
![]() |
312ab298fd | ||
![]() |
2fc21ad576 | ||
![]() |
8f6c87c3d6 | ||
![]() |
4429e76532 | ||
![]() |
e4be70bae8 | ||
![]() |
13d5a44278 | ||
![]() |
aba333bfb6 | ||
![]() |
b59da498cc | ||
![]() |
70382f21ba | ||
![]() |
0e1bf89fad | ||
![]() |
6c48c8b3ba | ||
![]() |
d1c5e8003b | ||
![]() |
ce926a34f2 | ||
![]() |
a744041e38 | ||
![]() |
2f90a85df1 | ||
![]() |
a411bc06e3 | ||
![]() |
1668e1532f | ||
![]() |
b87982769f | ||
![]() |
65b53a5f3f | ||
![]() |
49789b7841 | ||
![]() |
c249004c30 | ||
![]() |
4ee2e57ec8 | ||
![]() |
86ae5f981c | ||
![]() |
2bfa65e0de | ||
![]() |
293278bb08 | ||
![]() |
5d683c6ea4 | ||
![]() |
78b6723149 | ||
![]() |
3a6cc7389c | ||
![]() |
cc97287f8e | ||
![]() |
00218aa9f2 | ||
![]() |
874718db94 | ||
![]() |
bb4474897f | ||
![]() |
0cb342aef4 | ||
![]() |
030987480c | ||
![]() |
f6fdc80b40 | ||
![]() |
361c242473 | ||
![]() |
32962d1e1c | ||
![]() |
6e0a6871b5 | ||
![]() |
0030425c8c | ||
![]() |
c9dbc8ed26 | ||
![]() |
44b108b564 | ||
![]() |
2a8e91052f | ||
![]() |
0c9df02e66 | ||
![]() |
7523e87937 | ||
![]() |
d4fb44e986 | ||
![]() |
68b654d981 | ||
![]() |
88bc6d8966 | ||
![]() |
ac388d644b | ||
![]() |
bb517ddcca | ||
![]() |
b8d991420b | ||
![]() |
4a416e177a | ||
![]() |
8dfa49b648 | ||
![]() |
8b0eaa097c | ||
![]() |
101151b419 | ||
![]() |
4669036f45 | ||
![]() |
9bf9067c99 | ||
![]() |
a7bc8b56ba | ||
![]() |
371985d129 | ||
![]() |
3eae00898d | ||
![]() |
dc3ccba527 | ||
![]() |
b91ffed010 | ||
![]() |
8c07e388cd | ||
![]() |
98ce4bdeb2 | ||
![]() |
4659069350 | ||
![]() |
080d41627a | ||
![]() |
d799c5f03c | ||
![]() |
abe062b371 | ||
![]() |
b5a00ac1ca | ||
![]() |
f282865362 | ||
![]() |
377c2ada38 | ||
![]() |
264453459e | ||
![]() |
3d383d7b97 | ||
![]() |
c0cc26021b | ||
![]() |
96c027bad5 | ||
![]() |
b2a1bc69f5 | ||
![]() |
426742b3e2 | ||
![]() |
ab35121864 | ||
![]() |
cf3c205fa5 | ||
![]() |
19f6544923 | ||
![]() |
f641830d26 | ||
![]() |
a8d55e180c | ||
![]() |
55c36e0240 | ||
![]() |
2c03eee329 | ||
![]() |
65e28b8c22 | ||
![]() |
dfd33dd63d | ||
![]() |
722a6db8d9 | ||
![]() |
9c576c74db | ||
![]() |
523db190a7 | ||
![]() |
95631b9686 | ||
![]() |
0860bfe1f1 | ||
![]() |
85e7b712b9 | ||
![]() |
b731a6b48c | ||
![]() |
cde02b5936 | ||
![]() |
abeb8d0bc0 | ||
![]() |
9a9f72ad64 | ||
![]() |
392a497366 | ||
![]() |
36e6a6c506 | ||
![]() |
a361b345ad | ||
![]() |
f5bd6e3b2f | ||
![]() |
6c7df68c7c | ||
![]() |
5b82884f8b | ||
![]() |
f0f81ec458 | ||
![]() |
71cc30e5cd | ||
![]() |
645310cff6 | ||
![]() |
2f30b5748a | ||
![]() |
5e1ef96934 | ||
![]() |
57e98b62b3 | ||
![]() |
3262878ebd | ||
![]() |
5e12edbc38 | ||
![]() |
50a606adee | ||
![]() |
f995612073 | ||
![]() |
bc08383acd | ||
![]() |
b83a1a184c | ||
![]() |
59dd6814f8 | ||
![]() |
f7abf3db1b | ||
![]() |
cf1d2148ac | ||
![]() |
b5f2bd9b0e | ||
![]() |
ba2670e99c | ||
![]() |
6ffc4d9756 | ||
![]() |
595d2c76ac | ||
![]() |
d9796e9b1e | ||
![]() |
404c5f9f9e | ||
![]() |
a937e08ef0 | ||
![]() |
ef4f058a6c | ||
![]() |
69c5dde9bf | ||
![]() |
945885d501 | ||
![]() |
9d0b54c90d | ||
![]() |
2e5c288fea | ||
![]() |
f32ef20b74 | ||
![]() |
e2eefaac55 | ||
![]() |
e1cfbf0fd9 | ||
![]() |
08c5689441 | ||
![]() |
8dbda247d6 | ||
![]() |
71a631237d | ||
![]() |
e22ff3828b | ||
![]() |
b1b12e004e | ||
![]() |
5308fec354 | ||
![]() |
0ba57d4701 | ||
![]() |
54ca6a6178 | ||
![]() |
7dd4a78cf2 | ||
![]() |
52ff49512a | ||
![]() |
5a48b94089 | ||
![]() |
ba1c73d947 | ||
![]() |
4732b6bdfa | ||
![]() |
a6e78b70ab | ||
![]() |
bb1174afc5 | ||
![]() |
df8abe9cfd | ||
![]() |
c3bca97ee1 | ||
![]() |
c3b6fa1bba | ||
![]() |
94d496afe1 | ||
![]() |
7b7a572f9b | ||
![]() |
1b8cb742f9 | ||
![]() |
3492d180a8 | ||
![]() |
021da38373 | ||
![]() |
ac784759d5 | ||
![]() |
36eda2cd62 | ||
![]() |
08a4b3013f | ||
![]() |
1dd0332e8b | ||
![]() |
a90877ac31 | ||
![]() |
8b7ea27a48 | ||
![]() |
8df80e276b | ||
![]() |
30572c972d | ||
![]() |
53da4dd091 | ||
![]() |
108a4a99c7 | ||
![]() |
7c180376d6 | ||
![]() |
f39b8b32f7 | ||
![]() |
c543d19f8a | ||
![]() |
80fca9aef7 | ||
![]() |
5bb9aa0c2c | ||
![]() |
83c746ee57 | ||
![]() |
aff6604636 | ||
![]() |
2c80571a8a | ||
![]() |
d964b552af | ||
![]() |
48f8b37b74 | ||
![]() |
141be0028d | ||
![]() |
a140c47195 | ||
![]() |
0c3a8392f2 | ||
![]() |
16875b1f41 | ||
![]() |
b1f31f2eeb | ||
![]() |
d16b9e5a02 | ||
![]() |
680484bdc8 | ||
![]() |
05cd44b5dd | ||
![]() |
ba374139f4 | ||
![]() |
72a745bfd5 | ||
![]() |
3a6fac7d59 | ||
![]() |
28ba8e53df | ||
![]() |
9b26358e63 | ||
![]() |
e21521f45c | ||
![]() |
30479765cb | ||
![]() |
53a571ec6c | ||
![]() |
ad97cac313 | ||
![]() |
1a352ddf55 | ||
![]() |
5ba43decf2 | ||
![]() |
8f06d035cb | ||
![]() |
b716f48c84 | ||
![]() |
42b1e7143e | ||
![]() |
eba7821a6d | ||
![]() |
93a0246c03 | ||
![]() |
dfd1787a49 | ||
![]() |
4998fd54c0 | ||
![]() |
7be5f0ed3d | ||
![]() |
938d2b5923 | ||
![]() |
13630a79ad | ||
![]() |
2586989eb7 | ||
![]() |
6763e2bb0a | ||
![]() |
15a8b5c894 | ||
![]() |
8a2ea626c6 | ||
![]() |
01f238de79 | ||
![]() |
7bed5a5c3c | ||
![]() |
2fea954dcf | ||
![]() |
d4660d0ca7 | ||
![]() |
824f41d6e0 | ||
![]() |
1165663ec1 | ||
![]() |
b1a57a8b62 | ||
![]() |
d76925cf35 | ||
![]() |
400f54c7ec | ||
![]() |
ec7e4390e8 | ||
![]() |
5ca8bb85cd | ||
![]() |
5c624f8b76 | ||
![]() |
2c25af8cf5 | ||
![]() |
be905e0009 | ||
![]() |
0d2d62eae5 | ||
![]() |
00a1ee0cb6 | ||
![]() |
f0d44822bc | ||
![]() |
e771e4e019 | ||
![]() |
82e5f57edd | ||
![]() |
93a697f6ea | ||
![]() |
a733d32715 | ||
![]() |
c41d7136e8 | ||
![]() |
bb65dda277 | ||
![]() |
e1e9a7cf20 | ||
![]() |
27f64ddae2 | ||
![]() |
4b968dc611 | ||
![]() |
170177feb0 | ||
![]() |
eef44ae179 | ||
![]() |
161efc67a3 | ||
![]() |
dbfc11f4c5 | ||
![]() |
e5ea4f5019 | ||
![]() |
62d0b05309 | ||
![]() |
aae8f13d9a | ||
![]() |
eac900d363 | ||
![]() |
cd0c3d3eea | ||
![]() |
b461cc338c | ||
![]() |
7c34b57e92 | ||
![]() |
c35a53fe24 | ||
![]() |
055c78b475 | ||
![]() |
a9a52ef1e9 | ||
![]() |
a760989354 | ||
![]() |
dee95fd1c0 | ||
![]() |
9c48c7d39b | ||
![]() |
fc5e3b4ede | ||
![]() |
baf96275bf | ||
![]() |
3a45d3291b | ||
![]() |
c7307c1f85 | ||
![]() |
dec46d5c4a | ||
![]() |
93313e6385 | ||
![]() |
070236677c | ||
![]() |
6b86921c7a | ||
![]() |
8f3e076661 | ||
![]() |
37f0a51063 | ||
![]() |
d6343c367f | ||
![]() |
bad9fd0258 | ||
![]() |
d402d0362e | ||
![]() |
209579f280 | ||
![]() |
9e23e75fb4 | ||
![]() |
8f8c00a99d | ||
![]() |
bb5501f4c4 | ||
![]() |
d3cbcf0e46 | ||
![]() |
15502182e3 | ||
![]() |
375319038f | ||
![]() |
4c29846cb1 | ||
![]() |
c942a5c51c | ||
![]() |
a913e712a7 | ||
![]() |
7f63ad5484 | ||
![]() |
a498c29ec9 | ||
![]() |
973c315790 | ||
![]() |
aea2e4e7f4 | ||
![]() |
55a5ab4be1 | ||
![]() |
5377a6eee3 | ||
![]() |
6057da71f3 | ||
![]() |
e91b3d40a2 | ||
![]() |
b89f9a57e0 | ||
![]() |
b850e49cb3 | ||
![]() |
6b68c3702e | ||
![]() |
5f17e9591b | ||
![]() |
64f0496d9e | ||
![]() |
0d5b2a0f69 | ||
![]() |
c08b153cee | ||
![]() |
a434ffa8b7 | ||
![]() |
967c4e6a4e | ||
![]() |
3f1e9ff528 | ||
![]() |
96cc49e31e | ||
![]() |
94e5f82a81 | ||
![]() |
ffca01ffff | ||
![]() |
0165c9c644 | ||
![]() |
7b47a4bebc | ||
![]() |
a46ea4fc59 | ||
![]() |
4358a7eefd | ||
![]() |
b958cdc151 | ||
![]() |
afb527b37c | ||
![]() |
65b76f2762 | ||
![]() |
e54685d34d | ||
![]() |
6009e6d35d | ||
![]() |
d5f09dd9d8 | ||
![]() |
ffae6f56c5 | ||
![]() |
838563c751 | ||
![]() |
83705b91c2 | ||
![]() |
5abeae8f46 | ||
![]() |
693f2a5014 | ||
![]() |
5545264cea | ||
![]() |
e04f206c50 | ||
![]() |
e9459792a4 | ||
![]() |
dadf76ce72 | ||
![]() |
33d7f4da6b | ||
![]() |
5f79291b55 | ||
![]() |
792a72bdf4 | ||
![]() |
c32e7fd678 | ||
![]() |
76ef641743 | ||
![]() |
1f0f4ef5d5 | ||
![]() |
933d005e5d | ||
![]() |
f8f215772c | ||
![]() |
a0066e5752 | ||
![]() |
976a4c764d | ||
![]() |
0d7e2f0d67 | ||
![]() |
6c03dd87b1 | ||
![]() |
0c252e7904 | ||
![]() |
8f4e0ad3c8 | ||
![]() |
95b5260b27 | ||
![]() |
2f48e81e0b | ||
![]() |
7028eae083 | ||
![]() |
574a9c27a6 | ||
![]() |
f9414f89f3 | ||
![]() |
fcdbeb7bd4 | ||
![]() |
206992fe40 | ||
![]() |
31337ba92a | ||
![]() |
150d75b7c6 | ||
![]() |
7475897a03 | ||
![]() |
449bc417a3 | ||
![]() |
262f89f2b6 | ||
![]() |
38337446cf | ||
![]() |
ac1331ea4c | ||
![]() |
2b947e831f | ||
![]() |
112715eb80 | ||
![]() |
ea9cf365bc | ||
![]() |
b9b3b4051a | ||
![]() |
ecb6db29e6 | ||
![]() |
6515dde64b | ||
![]() |
01d2a2aa3c | ||
![]() |
39e12accb8 | ||
![]() |
39fe6ea5b1 | ||
![]() |
fc4b7df088 | ||
![]() |
35f28f7a64 | ||
![]() |
614be40438 | ||
![]() |
bde0428d0c | ||
![]() |
63567c2ae4 | ||
![]() |
ec10f337b6 | ||
![]() |
d0f0e73e96 | ||
![]() |
b4fe2c8a6b | ||
![]() |
33da0771d1 | ||
![]() |
75994cd915 | ||
![]() |
c0839afdde | ||
![]() |
5961da3f57 | ||
![]() |
41f1809351 | ||
![]() |
5fbdcb62e4 | ||
![]() |
677b83e9f8 | ||
![]() |
6a5c8becac | ||
![]() |
fd23b99d60 | ||
![]() |
634b586df3 | ||
![]() |
4ca3e98082 | ||
![]() |
d18a776964 | ||
![]() |
d6b4d7d265 | ||
![]() |
33ee4c21b3 | ||
![]() |
a026cd7195 | ||
![]() |
7b1bce8d90 | ||
![]() |
217a7c5161 | ||
![]() |
2949e3422d | ||
![]() |
16ea99b0c0 | ||
![]() |
19b84ce9f0 | ||
![]() |
e5aed4c067 | ||
![]() |
9e048bc0c3 | ||
![]() |
5d7b0735ce | ||
![]() |
12521cd5b4 | ||
![]() |
7dbd3eb5e8 | ||
![]() |
96364aacc0 | ||
![]() |
fc18f86964 | ||
![]() |
fb3d368a78 | ||
![]() |
f41435fae3 | ||
![]() |
5928c50057 | ||
![]() |
1de4bcef55 | ||
![]() |
7b7559309d | ||
![]() |
066df2c142 | ||
![]() |
0c4a9b1dce | ||
![]() |
65a7060d3b | ||
![]() |
3483e7b061 | ||
![]() |
13094e02bc | ||
![]() |
ed777e9d5b | ||
![]() |
8ad80a282a | ||
![]() |
0b7eb49839 | ||
![]() |
de3b40c2e6 | ||
![]() |
efa0aaf2c2 | ||
![]() |
bd4e1cdc1e | ||
![]() |
eb8df1fc18 | ||
![]() |
9a8e49751d | ||
![]() |
58e15134fd | ||
![]() |
875be11ae5 | ||
![]() |
3f7c9ea3f5 | ||
![]() |
33aa4daac8 | ||
![]() |
58e4087d4b | ||
![]() |
0072fd1573 | ||
![]() |
5d5ed10a45 | ||
![]() |
5ee8ee7b04 | ||
![]() |
521ae7f60e | ||
![]() |
27c8c12420 | ||
![]() |
3d1f100781 | ||
![]() |
16d36fc17f | ||
![]() |
eddb5bad91 | ||
![]() |
23e1b5ee3f | ||
![]() |
9e053bef19 | ||
![]() |
cf234fca15 | ||
![]() |
050a563e1d | ||
![]() |
c347ff742e | ||
![]() |
db1c819fe1 | ||
![]() |
9f2818ee29 | ||
![]() |
26aa6d23c7 | ||
![]() |
ec7e894eb3 | ||
![]() |
71a08382d6 | ||
![]() |
09224f8676 | ||
![]() |
008b8ac394 | ||
![]() |
a357add14e | ||
![]() |
0cfd7b528b | ||
![]() |
9ba4fe05df | ||
![]() |
35786b4b74 | ||
![]() |
c7430d805a | ||
![]() |
8a3fbb555f | ||
![]() |
a62c84a954 | ||
![]() |
4aba74d050 | ||
![]() |
ab2cb88cf4 | ||
![]() |
e79ec7d7e0 | ||
![]() |
ccdb74a9a7 | ||
![]() |
7b96d633db | ||
![]() |
938c49b899 | ||
![]() |
761eef7d96 | ||
![]() |
83511a0ba7 | ||
![]() |
cf9ccdae47 | ||
![]() |
d81096fdc0 | ||
![]() |
6c8e20a859 | ||
![]() |
6239fa4f56 | ||
![]() |
1b324ae981 | ||
![]() |
bedf68a9b2 | ||
![]() |
496e87e4ba | ||
![]() |
fa4f85eb32 | ||
![]() |
1b1dfedc74 | ||
![]() |
230941ff4f | ||
![]() |
4658e0f2f3 | ||
![]() |
7c3c532dae | ||
![]() |
7c04c9a227 | ||
![]() |
44973125c1 | ||
![]() |
6aaccd1e8b | ||
![]() |
e7001b0074 | ||
![]() |
aacbd022cf | ||
![]() |
ae1874ce34 | ||
![]() |
8abba597a8 | ||
![]() |
9987893963 | ||
![]() |
638322d905 | ||
![]() |
ae40f960ff | ||
![]() |
d969fdc19f | ||
![]() |
710024125e | ||
![]() |
9a39aff803 | ||
![]() |
78e912ea45 | ||
![]() |
aa6ea5b5a0 | ||
![]() |
48800e657f | ||
![]() |
120f0262f7 | ||
![]() |
4db075ffc1 | ||
![]() |
60b4efad67 | ||
![]() |
319388d78b | ||
![]() |
ce71514d71 | ||
![]() |
7833d70d9e | ||
![]() |
16961fab9d | ||
![]() |
861e87347a | ||
![]() |
91f6abaa81 | ||
![]() |
d380b52f9a | ||
![]() |
d656a06a19 | ||
![]() |
258dbee3b9 | ||
![]() |
6b9287b076 | ||
![]() |
dac0514441 | ||
![]() |
bffdb3b5c2 | ||
![]() |
e908ca8cef | ||
![]() |
801595e24a | ||
![]() |
ba9b432993 | ||
![]() |
b565072ed9 | ||
![]() |
caa1b4d69b | ||
![]() |
865536c5c4 | ||
![]() |
784d5cce52 | ||
![]() |
0fd08c6114 | ||
![]() |
cd779b6e4f | ||
![]() |
3430907046 | ||
![]() |
2f776eba85 | ||
![]() |
b9cd2ed1f1 | ||
![]() |
850b63f642 | ||
![]() |
a9c669f17b | ||
![]() |
075affec23 | ||
![]() |
3411a12c40 | ||
![]() |
28899356c8 | ||
![]() |
2b5f8d20de | ||
![]() |
243f240e5f | ||
![]() |
0a25868a86 | ||
![]() |
fccbc1adc4 | ||
![]() |
3f6a978328 | ||
![]() |
a6077a1790 | ||
![]() |
179a07942e | ||
![]() |
c3aed01096 | ||
![]() |
028778ed56 | ||
![]() |
2d72874b0b | ||
![]() |
4c45d30400 | ||
![]() |
ecbe5c839f | ||
![]() |
ed1f367a8a | ||
![]() |
a4185a0ba7 | ||
![]() |
e81a8ce073 | ||
![]() |
e506c89304 | ||
![]() |
fcdc9c83c5 | ||
![]() |
be0d539746 | ||
![]() |
4f9739ed2c | ||
![]() |
0df37fa653 | ||
![]() |
3e932505b0 | ||
![]() |
01be691936 | ||
![]() |
134c414fe5 | ||
![]() |
c54a8b10bb | ||
![]() |
6fc3381229 | ||
![]() |
927c0e082e | ||
![]() |
7674e917e4 | ||
![]() |
e13f42c17b | ||
![]() |
b7d4121586 | ||
![]() |
fbcd4b9767 | ||
![]() |
17c5e28727 | ||
![]() |
e62b29ca44 | ||
![]() |
1e4b1c4d1a | ||
![]() |
ae91852cd5 | ||
![]() |
2011f3a0b2 | ||
![]() |
228a31ee0a | ||
![]() |
8bf2bdff74 | ||
![]() |
41862eca61 | ||
![]() |
21307b397b | ||
![]() |
3f9c94ba4a | ||
![]() |
aa270d3ac2 | ||
![]() |
a15d9552c4 | ||
![]() |
2363c0653e | ||
![]() |
651c98d19a | ||
![]() |
c1a7e0e3cd | ||
![]() |
80b32d0c71 | ||
![]() |
3842eb36fd | ||
![]() |
7c7bedfa5d | ||
![]() |
5dafa9a170 | ||
![]() |
b397637bb9 | ||
![]() |
95a0b2db2c | ||
![]() |
83864f890a | ||
![]() |
a019ff61e3 | ||
![]() |
b3ada6308b | ||
![]() |
4e50295bf0 | ||
![]() |
32eb8abb63 | ||
![]() |
84b41123f2 | ||
![]() |
23f2d33394 | ||
![]() |
97f288a534 | ||
![]() |
68d5039c5f | ||
![]() |
9d07988d75 | ||
![]() |
1eaa2e3a5f | ||
![]() |
c7f2399ded | ||
![]() |
650ab61c2e | ||
![]() |
b7df86e7dd | ||
![]() |
72b445621b | ||
![]() |
ba0e9baffa | ||
![]() |
503622438a | ||
![]() |
d5e9aae425 | ||
![]() |
a2666a2b8a | ||
![]() |
966b05b47e | ||
![]() |
78fe97b9cb | ||
![]() |
d2094fed38 | ||
![]() |
e2d65ba57c | ||
![]() |
c9d8ab4b27 | ||
![]() |
891f99d71d | ||
![]() |
3f47fa9f99 | ||
![]() |
b1c23fdbaa | ||
![]() |
62e0e5b9ec | ||
![]() |
fb61834a2e | ||
![]() |
8fbbe94fe1 | ||
![]() |
ab706dda7d | ||
![]() |
b2d4132a14 | ||
![]() |
322cf89c92 | ||
![]() |
09acd64ba1 | ||
![]() |
072fcfe03e | ||
![]() |
13079c6e30 | ||
![]() |
1b1a51c1bb | ||
![]() |
39d134994d | ||
![]() |
5f9e98554f | ||
![]() |
0d9a21718f | ||
![]() |
daf42c5f43 | ||
![]() |
3685b4de85 | ||
![]() |
2631f10c5e | ||
![]() |
f21db60859 | ||
![]() |
c15158224b | ||
![]() |
a57c14c70b | ||
![]() |
bb2bd2fe53 | ||
![]() |
aebe2b5809 | ||
![]() |
9172399b8c | ||
![]() |
22c0d97783 | ||
![]() |
3ead529693 | ||
![]() |
e36f398aa6 | ||
![]() |
18cd4caf70 | ||
![]() |
80df45ba6d | ||
![]() |
16d262e3e5 | ||
![]() |
83e3d4ca1f | ||
![]() |
1c9141bd5d | ||
![]() |
1b984422db | ||
![]() |
b6453e9fac | ||
![]() |
7b8e3624b8 | ||
![]() |
8a56da84e6 | ||
![]() |
14a00490e2 | ||
![]() |
29bf967a7e | ||
![]() |
eeb79f2587 | ||
![]() |
6d1741694d | ||
![]() |
746dccf8f9 | ||
![]() |
28a897e599 | ||
![]() |
21ebf6d777 | ||
![]() |
a2dbbb25a1 | ||
![]() |
2a64dabe82 | ||
![]() |
046ca6eaf1 | ||
![]() |
3661afa461 | ||
![]() |
12f1985375 | ||
![]() |
bb800c9db8 | ||
![]() |
262048df95 | ||
![]() |
9255eb6902 | ||
![]() |
56d386f152 | ||
![]() |
193dbe89cd | ||
![]() |
601e158ffe | ||
![]() |
42b9fa3779 | ||
![]() |
4767a67acd | ||
![]() |
4c8cc84b64 | ||
![]() |
c5efc4b64b | ||
![]() |
25e2151fdf | ||
![]() |
cb10e261a2 | ||
![]() |
bd89c7f269 | ||
![]() |
d4ef151cc4 | ||
![]() |
669cfa33df | ||
![]() |
f70ab2f68a | ||
![]() |
900020ddc9 | ||
![]() |
ec428135ce | ||
![]() |
8e2a1a61a5 | ||
![]() |
5fb8f5d3e7 | ||
![]() |
c68523150f | ||
![]() |
ae2b8f0056 | ||
![]() |
ef6d78c580 | ||
![]() |
ccd4c9615c | ||
![]() |
7d6e60ab7d | ||
![]() |
9615e37ef9 | ||
![]() |
6be12ba773 | ||
![]() |
03855d316b | ||
![]() |
9f07109616 | ||
![]() |
6a4a3f617f | ||
![]() |
f32c9be41f | ||
![]() |
d83d829e0a | ||
![]() |
99e56ef74b | ||
![]() |
df23692802 | ||
![]() |
b68a7fe7ae | ||
![]() |
5c9ba189bc | ||
![]() |
5631a31099 | ||
![]() |
f4bc0efc31 | ||
![]() |
53f45810ff | ||
![]() |
d58151a0eb | ||
![]() |
de582d2fc7 | ||
![]() |
653ac7ee14 | ||
![]() |
0b4769289a | ||
![]() |
3bedb223fc | ||
![]() |
94a1720e04 | ||
![]() |
d0c8808340 | ||
![]() |
dd32d81726 | ||
![]() |
378a732968 | ||
![]() |
b2e82685b4 | ||
![]() |
566940e052 | ||
![]() |
dab802fbf4 | ||
![]() |
7bca95205d | ||
![]() |
669e2ed5b0 | ||
![]() |
783eb1a6e8 | ||
![]() |
9b9599b12f | ||
![]() |
6ed0d3def7 | ||
![]() |
c42731a55c | ||
![]() |
abf8534ea9 | ||
![]() |
773a66bc5b | ||
![]() |
269100eac1 | ||
![]() |
2a15583b87 | ||
![]() |
b534df242b | ||
![]() |
734730640a | ||
![]() |
bee7cfa6aa | ||
![]() |
d5813152ab | ||
![]() |
eacf78b83c | ||
![]() |
348964fe12 | ||
![]() |
e5c7589fc0 | ||
![]() |
4260528645 | ||
![]() |
34fe26e51b | ||
![]() |
8a59907319 | ||
![]() |
52deebaf65 | ||
![]() |
1e05b22fbc | ||
![]() |
ab56af5d15 | ||
![]() |
123f00eee6 | ||
![]() |
42bf103269 | ||
![]() |
c8d2a462e3 | ||
![]() |
08794ae1cf | ||
![]() |
4f70dba935 | ||
![]() |
b926a2c9b0 | ||
![]() |
52bdd1d5a2 | ||
![]() |
bc7d0f0da5 | ||
![]() |
6a8e9c9e95 | ||
![]() |
211a922f3c | ||
![]() |
2758a3ade6 | ||
![]() |
ef3c9eae73 | ||
![]() |
9cf2e1b519 | ||
![]() |
51c2f7a599 | ||
![]() |
5bdd046b11 | ||
![]() |
95526a82de | ||
![]() |
af7ad0a621 | ||
![]() |
1473753d43 | ||
![]() |
b36bd21813 | ||
![]() |
f8f0241c27 | ||
![]() |
1af16836d4 | ||
![]() |
757974714e | ||
![]() |
eed22a7a24 | ||
![]() |
0242bc999f | ||
![]() |
b89c533818 | ||
![]() |
2cb05ab865 | ||
![]() |
391639210e | ||
![]() |
99f34c9f50 | ||
![]() |
d418cc9950 | ||
![]() |
6dfafb0787 | ||
![]() |
7067295e67 | ||
![]() |
2af229eb1a | ||
![]() |
8dd8e9916e | ||
![]() |
96af1fe7cf | ||
![]() |
cb3a03356b | ||
![]() |
68aa2ae3ce | ||
![]() |
52de354e24 | ||
![]() |
f4f90cada4 | ||
![]() |
62420e0f40 | ||
![]() |
102e651741 | ||
![]() |
65daaaf64b | ||
![]() |
b7a6f36e95 | ||
![]() |
a86a10b128 | ||
![]() |
0b728ade3a | ||
![]() |
74f05108d7 | ||
![]() |
9d4d15ddc7 | ||
![]() |
0c5c6dff8f | ||
![]() |
391fcdc83d | ||
![]() |
d76d5e2c5f | ||
![]() |
f0ada573bb | ||
![]() |
ec5b790b51 | ||
![]() |
613b23748d | ||
![]() |
cea1547e08 | ||
![]() |
fd5ae01e1d | ||
![]() |
9b6b93d467 | ||
![]() |
ca179c12a1 | ||
![]() |
4d527035ae | ||
![]() |
19b42830ea | ||
![]() |
f5162f8ab1 | ||
![]() |
ff38a3c6b6 | ||
![]() |
94e85686b5 | ||
![]() |
aea4a8ed33 | ||
![]() |
05dd3b2e9d | ||
![]() |
040468755c | ||
![]() |
50b359fdb2 | ||
![]() |
72f2e18a84 | ||
![]() |
b36dc22b45 | ||
![]() |
15b1c875f5 | ||
![]() |
13804dc380 | ||
![]() |
9bea23da29 | ||
![]() |
7005fabd4d | ||
![]() |
de8c37ad00 | ||
![]() |
a80499c4b7 | ||
![]() |
82f7f847ba | ||
![]() |
4880761fe0 | ||
![]() |
87ab0b386d | ||
![]() |
c42c274002 | ||
![]() |
2d82b8951f | ||
![]() |
b7702bc3e8 | ||
![]() |
9c6b83501f | ||
![]() |
5189d8b14c | ||
![]() |
e13053ed89 | ||
![]() |
efa77cf5ec | ||
![]() |
f6355bd075 | ||
![]() |
e3dfce88ff | ||
![]() |
939b5ea095 | ||
![]() |
e6fba01682 | ||
![]() |
1623d397be | ||
![]() |
09678d601d | ||
![]() |
67d51f7e1b | ||
![]() |
aa7f2759a6 | ||
![]() |
9b9dd67797 | ||
![]() |
3f73bc075a | ||
![]() |
f2a55d01ea | ||
![]() |
56989a017b | ||
![]() |
bf029c1b9d | ||
![]() |
ada5918bc8 | ||
![]() |
375ebd39f0 | ||
![]() |
a33ebbaf11 | ||
![]() |
19b304b0fc | ||
![]() |
0b64fe6746 | ||
![]() |
e978121d58 | ||
![]() |
4efd450b32 | ||
![]() |
d2670664ba | ||
![]() |
fa7405fe9c | ||
![]() |
33297f48a5 | ||
![]() |
956793e066 | ||
![]() |
1bfbc67c62 | ||
![]() |
b5287184e9 | ||
![]() |
7c9957e058 | ||
![]() |
fca7cb9fb0 | ||
![]() |
268d254d85 | ||
![]() |
181adebf82 | ||
![]() |
06297a1918 | ||
![]() |
aa0874b6d8 | ||
![]() |
822ced6294 | ||
![]() |
1a59614f79 | ||
![]() |
f2d528e52a | ||
![]() |
f7adc5f84c | ||
![]() |
e955e833c4 | ||
![]() |
096c44b910 | ||
![]() |
efb9a42045 | ||
![]() |
296cda7801 | ||
![]() |
90b9d73244 | ||
![]() |
c8b0e7f2a7 | ||
![]() |
6ce88ab5a4 | ||
![]() |
e13ab805df | ||
![]() |
e58ea8c7b4 | ||
![]() |
dd5bac61cb | ||
![]() |
6270b27a97 | ||
![]() |
f89ba1d39f | ||
![]() |
8b5d137d8f | ||
![]() |
2629fab649 | ||
![]() |
92cd10c6a8 | ||
![]() |
cc3edb90dc | ||
![]() |
c60ba81984 | ||
![]() |
ece3cdaa2e | ||
![]() |
4cb40f2042 | ||
![]() |
0e9f350982 | ||
![]() |
cf439f01f8 | ||
![]() |
f1f1b8a630 | ||
![]() |
d4d1df03c9 | ||
![]() |
92b73a6f4f | ||
![]() |
b63c06c75a | ||
![]() |
3e3bce422e | ||
![]() |
e3a27c2cc4 | ||
![]() |
f13f451084 | ||
![]() |
df0e3de911 | ||
![]() |
8466be8728 | ||
![]() |
5cf2144b3f | ||
![]() |
7c182f63c8 | ||
![]() |
056180782c | ||
![]() |
ff0d5870e9 | ||
![]() |
b70176f8c7 | ||
![]() |
e3655b525d | ||
![]() |
e63d0091af | ||
![]() |
7b0af2d80d | ||
![]() |
7d79a86d4d | ||
![]() |
ba46aff069 | ||
![]() |
7a65471ba5 | ||
![]() |
c7c46da975 | ||
![]() |
c708e8425f | ||
![]() |
905c51bef0 | ||
![]() |
bd87098b7e | ||
![]() |
5f486cc25f | ||
![]() |
f79fb72a33 | ||
![]() |
0505aa2dda | ||
![]() |
485ff32e42 | ||
![]() |
5ead67972f | ||
![]() |
9c860dbff3 | ||
![]() |
a20ad99638 | ||
![]() |
8ef7bf8e7b | ||
![]() |
0d5be1969a | ||
![]() |
d06ea9bfc3 | ||
![]() |
57e79882e1 | ||
![]() |
20d1ab60c7 | ||
![]() |
277c2ce2d2 | ||
![]() |
34e51f01d1 | ||
![]() |
f4b4e3a58c | ||
![]() |
def2e033c8 | ||
![]() |
dfec18278b | ||
![]() |
cd5bdecda3 | ||
![]() |
9b6217ba41 | ||
![]() |
272f6e195d | ||
![]() |
aa9bf04dfe | ||
![]() |
9ae6dfb6d2 | ||
![]() |
619bb79a2f | ||
![]() |
0cad831eca | ||
![]() |
f15a7fb588 | ||
![]() |
1bdf9ca057 | ||
![]() |
c8c370b784 | ||
![]() |
63182f55f7 | ||
![]() |
41759248e2 | ||
![]() |
3149d5a66d | ||
![]() |
8b13597099 | ||
![]() |
36032cc26e | ||
![]() |
4cb107aedc | ||
![]() |
176f8d1981 | ||
![]() |
9a26030bd5 | ||
![]() |
6778f4d9e0 | ||
![]() |
fd61b9e3e2 | ||
![]() |
298d5cdf24 | ||
![]() |
1bf1c9d006 | ||
![]() |
7dc62be5cf | ||
![]() |
be580a6a5b | ||
![]() |
8ce519668b | ||
![]() |
801258c46a | ||
![]() |
32a1db3622 | ||
![]() |
ed1f3daacc | ||
![]() |
b7d74c82ba | ||
![]() |
c3b31a6fb0 | ||
![]() |
f4c55bbc07 | ||
![]() |
a16842f7bc | ||
![]() |
439a38664f | ||
![]() |
5cc12fd945 | ||
![]() |
fe116fff5a | ||
![]() |
06aaaf4727 | ||
![]() |
6deb9b49b2 | ||
![]() |
d59e92d3e5 | ||
![]() |
cc83c1f0cf | ||
![]() |
1fe7306af8 | ||
![]() |
c796d73fc3 | ||
![]() |
eb93f884f3 | ||
![]() |
3673feb256 | ||
![]() |
7c9c783e9d | ||
![]() |
74a4b9efaa | ||
![]() |
4466e8cce1 | ||
![]() |
b689037984 | ||
![]() |
db1ba21d88 | ||
![]() |
50d270ef7c | ||
![]() |
d1a578b555 | ||
![]() |
76e9859cf8 | ||
![]() |
add9d363c5 | ||
![]() |
1498baab0f | ||
![]() |
df7f63d45d | ||
![]() |
f7425126a1 | ||
![]() |
790047e450 | ||
![]() |
9198b5b0be | ||
![]() |
d534acb79d | ||
![]() |
d100f54551 | ||
![]() |
7a9e100b0f | ||
![]() |
fafe23d7c2 | ||
![]() |
9a08bdae4a | ||
![]() |
bcc11fa7fe | ||
![]() |
7d0c0fdf7c | ||
![]() |
0e33d46ead | ||
![]() |
efbacc17cf | ||
![]() |
bd6dbd9090 | ||
![]() |
076cf51fb2 | ||
![]() |
f8a6af1e28 | ||
![]() |
96912f436d | ||
![]() |
f0e162442f | ||
![]() |
04b8dd989f | ||
![]() |
5851c8bd91 | ||
![]() |
78efcf93f8 | ||
![]() |
bb35bc3898 | ||
![]() |
f38783bdef | ||
![]() |
d8f9986089 | ||
![]() |
3e616b599a | ||
![]() |
d38fc17191 | ||
![]() |
7ae0eb0dc3 | ||
![]() |
9082eb56a7 | ||
![]() |
c578974246 | ||
![]() |
fec81ffe73 | ||
![]() |
30e6a310f1 | ||
![]() |
a87934d434 | ||
![]() |
b398c1fe72 | ||
![]() |
6f813f940e | ||
![]() |
d52498b787 | ||
![]() |
79e35bbdf6 | ||
![]() |
1814ff05f4 | ||
![]() |
ec226e33cb | ||
![]() |
6abdf9f9c1 | ||
![]() |
212da1029e | ||
![]() |
afea15e4a7 | ||
![]() |
39ff02b6e4 | ||
![]() |
b238be54a4 | ||
![]() |
377c9890a3 | ||
![]() |
599834b0e1 | ||
![]() |
a39a7ca9d5 | ||
![]() |
cd22745e6b | ||
![]() |
334649dfd4 | ||
![]() |
becbc5f9ef | ||
![]() |
a7dd73c657 | ||
![]() |
f9b29fd7e7 | ||
![]() |
f770e16f6d | ||
![]() |
9092ee9f0e | ||
![]() |
01257f65a6 | ||
![]() |
c1222175b3 | ||
![]() |
5ff481952d | ||
![]() |
baa689ad43 | ||
![]() |
2f30f4f69f | ||
![]() |
202a4c6525 | ||
![]() |
7928b9b3a2 | ||
![]() |
e1c9020268 | ||
![]() |
04a12b436e | ||
![]() |
818a8c2196 | ||
![]() |
b6715464fd | ||
![]() |
8f2d543d9f | ||
![]() |
6cf320bedb | ||
![]() |
a850ce5086 | ||
![]() |
ef3bdf5408 | ||
![]() |
94b9bc7950 | ||
![]() |
8a07463a67 | ||
![]() |
2995b23929 | ||
![]() |
eb4276373b | ||
![]() |
79df52e519 | ||
![]() |
3dfb31b1b9 | ||
![]() |
c4c4ed70d9 | ||
![]() |
45422df1b7 | ||
![]() |
e0b7624414 | ||
![]() |
b0ecb3170f | ||
![]() |
fc8b5f378a | ||
![]() |
d42cb7ddb3 | ||
![]() |
6454ac0944 | ||
![]() |
31cf83f10b | ||
![]() |
cc84005593 | ||
![]() |
915d2732a1 | ||
![]() |
44bc47361e | ||
![]() |
3619b07843 | ||
![]() |
ad3f588c79 | ||
![]() |
a2fc37121b | ||
![]() |
7f36d20123 | ||
![]() |
d1a8e8b042 | ||
![]() |
c39ddd00d3 | ||
![]() |
d55e453bd5 | ||
![]() |
bffed27bdb | ||
![]() |
fffcb158f1 | ||
![]() |
eca98a54eb | ||
![]() |
46ed2c5270 | ||
![]() |
23ea0b7ec9 | ||
![]() |
ef26cb283b | ||
![]() |
b8bb77eff6 | ||
![]() |
9c75ad3de1 | ||
![]() |
0b38dea613 | ||
![]() |
7e4a9e3bc2 | ||
![]() |
36f12c822f | ||
![]() |
0cbea0f5d3 | ||
![]() |
e735fe54c3 | ||
![]() |
e911e2e1df | ||
![]() |
1d75f6c2be | ||
![]() |
ad8a168469 | ||
![]() |
74fc502089 | ||
![]() |
dfc2166d8b | ||
![]() |
2b70346db4 | ||
![]() |
090df6f224 | ||
![]() |
745a1d6e94 | ||
![]() |
0fe0796870 | ||
![]() |
224b56bd3a | ||
![]() |
571b5b544d | ||
![]() |
220b40f7f4 | ||
![]() |
60774c5a49 | ||
![]() |
6d37ef7256 | ||
![]() |
e083224df1 | ||
![]() |
5ef567405f | ||
![]() |
ea2521f430 | ||
![]() |
82cb182fe7 | ||
![]() |
3fe31ff551 | ||
![]() |
48d45f1ca4 | ||
![]() |
ddf2a604d1 | ||
![]() |
8b920d9d56 | ||
![]() |
f2c0489452 | ||
![]() |
f5a2d19199 | ||
![]() |
86fed12d91 | ||
![]() |
7ca3ad5d4c | ||
![]() |
1eecffce97 | ||
![]() |
5c341a2b00 | ||
![]() |
0ab64e9803 | ||
![]() |
27108334f1 | ||
![]() |
788253cbe8 | ||
![]() |
4b6e89a526 | ||
![]() |
68fd1b66b5 | ||
![]() |
5806666949 | ||
![]() |
a76d8108fe | ||
![]() |
2135294e2e | ||
![]() |
ed1c563d1f | ||
![]() |
74efa3a108 | ||
![]() |
49c29e6862 | ||
![]() |
17d7f24825 | ||
![]() |
f23c3da4ff | ||
![]() |
cabcf50fbe | ||
![]() |
8b23b5d389 | ||
![]() |
37eb2c1db6 | ||
![]() |
9751a37343 | ||
![]() |
ed3bdd3443 | ||
![]() |
285ad9bdc1 | ||
![]() |
16f5914c90 | ||
![]() |
72d56a89a2 | ||
![]() |
1135c8c1b1 | ||
![]() |
ec4339bd47 | ||
![]() |
6c0fbef843 | ||
![]() |
040c85a43b | ||
![]() |
420554c737 | ||
![]() |
f20b854dd2 | ||
![]() |
3844cec7a4 | ||
![]() |
0db49f7520 | ||
![]() |
f8dedcaa1e | ||
![]() |
f8b1122467 | ||
![]() |
f3bf5e9a5c | ||
![]() |
ba1dbacd35 | ||
![]() |
4036f1c121 | ||
![]() |
22ad697d1f | ||
![]() |
a10d7469cd | ||
![]() |
06c3153d22 | ||
![]() |
9677158b75 | ||
![]() |
226a73141b | ||
![]() |
da3201bf35 | ||
![]() |
7daebc6aea | ||
![]() |
d9002769cf | ||
![]() |
6d0b30953a | ||
![]() |
09d6452475 | ||
![]() |
6a61fce84e | ||
![]() |
11017902be | ||
![]() |
bd7333723e | ||
![]() |
6648250fb9 | ||
![]() |
a94a2d46d0 | ||
![]() |
ab97018c78 | ||
![]() |
be702b0924 | ||
![]() |
c5c10cfb50 | ||
![]() |
5682d642a6 | ||
![]() |
62c6d7274c | ||
![]() |
4f8633375d | ||
![]() |
9f559818e5 | ||
![]() |
5f329f72ee | ||
![]() |
7303a06f83 | ||
![]() |
e34de96b24 | ||
![]() |
42cd424274 | ||
![]() |
9426e94314 | ||
![]() |
7a1dab3319 | ||
![]() |
d63ec84745 | ||
![]() |
0e7e2f4e5b | ||
![]() |
46521240a9 | ||
![]() |
a8827a5d95 | ||
![]() |
ca0bc1cb7d | ||
![]() |
8c28ce7d79 | ||
![]() |
5b051f0891 | ||
![]() |
c93de9450a | ||
![]() |
96976fa892 | ||
![]() |
c14e99cef0 | ||
![]() |
c91a806774 | ||
![]() |
2f0076f429 | ||
![]() |
a1ffc6d55b | ||
![]() |
9bdf7a9980 | ||
![]() |
81494453b0 | ||
![]() |
008cbe5ce7 | ||
![]() |
5ee35e7eeb | ||
![]() |
1a98e70281 | ||
![]() |
8e3f3977bd | ||
![]() |
04b04f094c | ||
![]() |
9c02cdbad9 | ||
![]() |
c30e805623 | ||
![]() |
cd81538ce3 | ||
![]() |
68cb280513 | ||
![]() |
19466a15b4 | ||
![]() |
d54b406cba | ||
![]() |
72254a7af9 | ||
![]() |
52feff266e | ||
![]() |
2c3f50e34a | ||
![]() |
2b0258c13a | ||
![]() |
2585900692 | ||
![]() |
48c2dcb110 | ||
![]() |
10a378bd46 | ||
![]() |
3fe3c2c79f | ||
![]() |
52c2a8484e | ||
![]() |
21435c1863 | ||
![]() |
1ea3ab7fe8 | ||
![]() |
1b0ad2c3cd | ||
![]() |
aa4821864a | ||
![]() |
283762224c | ||
![]() |
f50a37fc88 | ||
![]() |
076f0515ca | ||
![]() |
049f12096d | ||
![]() |
f09c0393ba | ||
![]() |
472bbcf293 | ||
![]() |
7a3f9daccf | ||
![]() |
76511d61e0 | ||
![]() |
8e7475ccf6 | ||
![]() |
820d8c7bf5 | ||
![]() |
cfc75b4f1a | ||
![]() |
98567fe5a8 | ||
![]() |
05bb812e2b | ||
![]() |
c9876a6c88 | ||
![]() |
979b5a52d3 | ||
![]() |
e70535e8d7 | ||
![]() |
ed8725bf6c | ||
![]() |
098cd70e82 | ||
![]() |
969dac2033 | ||
![]() |
49b1d667f1 | ||
![]() |
bca1e08411 | ||
![]() |
bf6ed217c2 | ||
![]() |
bb8e9c6438 | ||
![]() |
f128ed5b1f | ||
![]() |
ff5786d61b | ||
![]() |
ca596c8ecd | ||
![]() |
c3bcafb514 | ||
![]() |
a9c7d95e9b | ||
![]() |
63bbcb5152 | ||
![]() |
01042c1d98 | ||
![]() |
5bf722c7ae | ||
![]() |
c2191153cf | ||
![]() |
5bcbc5a337 | ||
![]() |
f721f90add | ||
![]() |
0e92d8ce2c | ||
![]() |
727d6a1b61 | ||
![]() |
666c0847b7 | ||
![]() |
0a411f9bba | ||
![]() |
49f3ba39f9 | ||
![]() |
794128a053 | ||
![]() |
e6be3b2313 | ||
![]() |
9150767574 | ||
![]() |
75f2180cb1 | ||
![]() |
c5cdcf0f95 | ||
![]() |
ea5b07f636 | ||
![]() |
477e6b8663 | ||
![]() |
a0d8418b40 | ||
![]() |
006fb08024 | ||
![]() |
4578f6016b | ||
![]() |
5b06bcc57d | ||
![]() |
d4bb14a511 | ||
![]() |
6d2f5da506 | ||
![]() |
c96df86111 | ||
![]() |
86f87cf4ac | ||
![]() |
770a8fb288 | ||
![]() |
c4e3a98ea7 | ||
![]() |
07e95dba4f | ||
![]() |
9bc1abcd00 | ||
![]() |
4d515b05f3 | ||
![]() |
64edf7ad9c | ||
![]() |
7610c0fb2e | ||
![]() |
0189e4ed59 | ||
![]() |
8018c9b91d | ||
![]() |
4b3920daba | ||
![]() |
d876e3ed5c | ||
![]() |
086b5daa53 | ||
![]() |
4b877e3f6b | ||
![]() |
8ce749e339 | ||
![]() |
752ddfa7fc | ||
![]() |
8700c96c4d | ||
![]() |
e3852ceeca | ||
![]() |
225ea49b6f | ||
![]() |
15fd49037f | ||
![]() |
2fb4697e12 | ||
![]() |
1a9f770317 | ||
![]() |
62871ec9b3 | ||
![]() |
39c64214ee | ||
![]() |
9aec5febb8 | ||
![]() |
91b2167eba | ||
![]() |
00d40a35cd | ||
![]() |
f96ab02767 | ||
![]() |
4ce699e57f | ||
![]() |
4ee042c330 | ||
![]() |
0b23f4ff81 | ||
![]() |
5cef1634ed | ||
![]() |
1b0286916e | ||
![]() |
a8f764c161 | ||
![]() |
1d719252cb | ||
![]() |
d8cebe1188 | ||
![]() |
329ebf6a5d | ||
![]() |
c836441a75 | ||
![]() |
074d36eeba | ||
![]() |
f6eb35f67d | ||
![]() |
77f70a0792 | ||
![]() |
12dafd07b8 | ||
![]() |
9fb8bec715 | ||
![]() |
eb1146c6b6 | ||
![]() |
730f7c5e41 | ||
![]() |
5cabc9cff2 | ||
![]() |
ddc039ed2e | ||
![]() |
a146ebd856 | ||
![]() |
5ee7b6caeb | ||
![]() |
9c4b0f7b15 | ||
![]() |
2e5d1ddff9 | ||
![]() |
24bdb1ce98 | ||
![]() |
8eb59ad4dc | ||
![]() |
d8c8ccd180 | ||
![]() |
a46e004f07 | ||
![]() |
173f94216a | ||
![]() |
1a74accd65 | ||
![]() |
2979e03148 | ||
![]() |
4bdb9a2c8e | ||
![]() |
8f6fa5e9ff | ||
![]() |
986135ff76 | ||
![]() |
c9cbc00e36 | ||
![]() |
c9a40c180a | ||
![]() |
125cb17fcb | ||
![]() |
53a5bd2319 | ||
![]() |
4fd68f9af3 | ||
![]() |
c4417b399b | ||
![]() |
c2a3e42a53 | ||
![]() |
73c04f5a89 | ||
![]() |
195f707f14 | ||
![]() |
bc20dc5c62 | ||
![]() |
8b4ca51805 | ||
![]() |
e2e25eb751 | ||
![]() |
9572ecc5ea | ||
![]() |
97d8b9e908 | ||
![]() |
c59a8a60eb | ||
![]() |
158da0927a | ||
![]() |
78a7338346 | ||
![]() |
90e5c8d39b | ||
![]() |
7a6f2d8336 | ||
![]() |
f49554aa57 | ||
![]() |
0a72168f8f | ||
![]() |
5011bfef55 | ||
![]() |
6038813d03 | ||
![]() |
fee9de96de | ||
![]() |
35e028cd99 | ||
![]() |
145cdd5c1b | ||
![]() |
762b2782ee | ||
![]() |
91f031b661 | ||
![]() |
eab809d410 | ||
![]() |
826f1b4713 | ||
![]() |
fa1a95ae91 | ||
![]() |
63babae63d | ||
![]() |
db9924a399 | ||
![]() |
5d23c7644b | ||
![]() |
ef81a9f547 | ||
![]() |
747c21da70 | ||
![]() |
439ff11d13 | ||
![]() |
947364e15f | ||
![]() |
750115b727 | ||
![]() |
a55efc832d | ||
![]() |
c96bd21389 | ||
![]() |
dd241bd6fa | ||
![]() |
0dbde7400f | ||
![]() |
2587f6753d | ||
![]() |
4155e76a81 | ||
![]() |
756bd19181 | ||
![]() |
fbb2344895 | ||
![]() |
bda6c85638 | ||
![]() |
df4a149cd0 | ||
![]() |
80f27b1db9 | ||
![]() |
d5d1d3b45a | ||
![]() |
c797c3f22d | ||
![]() |
375ed23216 | ||
![]() |
7b66a56cad | ||
![]() |
7216bf7835 | ||
![]() |
8b24c35ac7 | ||
![]() |
f80a6ae228 | ||
![]() |
9b3fbe4593 | ||
![]() |
f99a723627 | ||
![]() |
181ffb00a7 | ||
![]() |
222eca64d7 | ||
![]() |
1b687f3feb | ||
![]() |
2228104bff | ||
![]() |
402c3752c4 | ||
![]() |
69a8bb5e1f | ||
![]() |
0d76f9e030 | ||
![]() |
eb8f65c58b | ||
![]() |
e0e27a671e | ||
![]() |
b65eb69d9f | ||
![]() |
8118e542fb | ||
![]() |
c866759bd4 | ||
![]() |
429f7377cb | ||
![]() |
40776e5324 | ||
![]() |
621343112d | ||
![]() |
eb06e6ba51 | ||
![]() |
da91b16244 | ||
![]() |
918e2ba8d0 | ||
![]() |
f50dc83829 | ||
![]() |
e8a9b4743b | ||
![]() |
f34226425e | ||
![]() |
e27c7ba36f | ||
![]() |
1aad527956 | ||
![]() |
173c62acb6 | ||
![]() |
76605d7dfe | ||
![]() |
32be1a6496 | ||
![]() |
c7d43aa544 | ||
![]() |
198bf55b7b | ||
![]() |
75378d3567 | ||
![]() |
55cb371569 | ||
![]() |
5bb97d25d0 | ||
![]() |
b2017cae77 | ||
![]() |
35af903d4a | ||
![]() |
426e00b6f4 | ||
![]() |
8e62b3e438 | ||
![]() |
4265ad5f23 | ||
![]() |
c181eb0539 | ||
![]() |
e0f06753c6 | ||
![]() |
8aafd72ef0 | ||
![]() |
48549ce97b | ||
![]() |
47abf83960 | ||
![]() |
be0f3731b4 | ||
![]() |
b755431b93 | ||
![]() |
04ff393875 | ||
![]() |
7841274300 | ||
![]() |
235687d983 | ||
![]() |
3d75e6ed95 | ||
![]() |
eb9af8bceb | ||
![]() |
39ea434513 | ||
![]() |
f0a956467c | ||
![]() |
e48bd08095 | ||
![]() |
5d00717f39 | ||
![]() |
3fff685c44 | ||
![]() |
1e75265eed | ||
![]() |
b6ac3ef445 | ||
![]() |
421f78f3e6 | ||
![]() |
b71fdcfc20 | ||
![]() |
021e9b228a | ||
![]() |
00d4533022 | ||
![]() |
fd5faeb5dd | ||
![]() |
e7c8035ed7 | ||
![]() |
e427e38da8 | ||
![]() |
1f24abc3d2 | ||
![]() |
76e62779ba | ||
![]() |
1af343ef50 | ||
![]() |
412ffd1592 | ||
![]() |
b141fec573 | ||
![]() |
d2e14abfd5 | ||
![]() |
d4abca0480 | ||
![]() |
529f5822ee | ||
![]() |
395d85a12f | ||
![]() |
4379a4b067 | ||
![]() |
ad8e1cbf62 | ||
![]() |
dc5a70b0de | ||
![]() |
b5d1f52ea4 | ||
![]() |
221cf235b5 | ||
![]() |
7720e31a31 | ||
![]() |
d812affef0 | ||
![]() |
5c19eb34bf | ||
![]() |
e18ebaee3d | ||
![]() |
dbcbf12456 | ||
![]() |
c04b44057c | ||
![]() |
60aa60f48e | ||
![]() |
2848d7c80e | ||
![]() |
9fcdacb624 | ||
![]() |
cf1713b085 | ||
![]() |
f049a4ca67 | ||
![]() |
55f860da2f | ||
![]() |
b5369e611c | ||
![]() |
3d1dd1c6ac | ||
![]() |
10a363b275 | ||
![]() |
d865c5e2b6 | ||
![]() |
9fac37588c | ||
![]() |
aac0d58417 | ||
![]() |
b37e6187d4 | ||
![]() |
20138ee85f | ||
![]() |
6dc569cde5 | ||
![]() |
77cf0b678a | ||
![]() |
2dfb061063 | ||
![]() |
e4669e2581 | ||
![]() |
df47cf72d3 | ||
![]() |
ba1b34e375 | ||
![]() |
950b5ee529 | ||
![]() |
041c48de19 | ||
![]() |
599fbcee6e | ||
![]() |
ce2df8030c | ||
![]() |
47e761bbe2 | ||
![]() |
0646baa18d | ||
![]() |
38997c1b47 | ||
![]() |
acaafabc23 | ||
![]() |
6a80bdafa6 | ||
![]() |
cf30ed745c | ||
![]() |
a399fb4044 | ||
![]() |
24b946e850 | ||
![]() |
236daf48ff | ||
![]() |
4942af27dc | ||
![]() |
3adb90071b | ||
![]() |
29b4a2a08c | ||
![]() |
e1331fc0a2 | ||
![]() |
3802f8ff65 | ||
![]() |
4b0abdbe7c | ||
![]() |
81889fd7a3 | ||
![]() |
aac99c45c0 | ||
![]() |
566a6369a5 | ||
![]() |
4fdf340d04 | ||
![]() |
ddd7145153 | ||
![]() |
3f22b644b6 | ||
![]() |
639c9f579d | ||
![]() |
735b8665f1 | ||
![]() |
199fa50a9d | ||
![]() |
aac5ad8504 | ||
![]() |
349c108ebc | ||
![]() |
3b464782ef | ||
![]() |
3d97fd8d2a | ||
![]() |
c102e76146 | ||
![]() |
beee7b68bf | ||
![]() |
f47e571d92 | ||
![]() |
4b5320a8f0 | ||
![]() |
30c2c89c6b | ||
![]() |
4a1d1a0dc1 | ||
![]() |
360adc9130 | ||
![]() |
cc21abe843 | ||
![]() |
9a27555763 | ||
![]() |
aaef2fbd01 | ||
![]() |
5bb640ca17 | ||
![]() |
0e5c7a62cb | ||
![]() |
1b33e05f74 | ||
![]() |
53a04309ff | ||
![]() |
dc411651b6 | ||
![]() |
514540b90b | ||
![]() |
a5249d1f5d | ||
![]() |
21aa3f6578 | ||
![]() |
0024edbbb9 | ||
![]() |
23cb39b557 | ||
![]() |
48de321869 | ||
![]() |
c6d68009d2 | ||
![]() |
2cab267405 | ||
![]() |
6bdc0d2e5e | ||
![]() |
3eed81c1eb | ||
![]() |
b447807b36 | ||
![]() |
2771c8c32e | ||
![]() |
21a88bc2d3 | ||
![]() |
57c1838f68 | ||
![]() |
52b0254ec6 | ||
![]() |
49631542ce | ||
![]() |
4b80ffb9eb | ||
![]() |
9efa7c116d | ||
![]() |
5d9c8d59a0 | ||
![]() |
1a60201f68 | ||
![]() |
f3186abf09 | ||
![]() |
6bcc0d3c7f | ||
![]() |
57b9a57dde | ||
![]() |
28994f4b64 | ||
![]() |
588b4712bf | ||
![]() |
d3b6208057 | ||
![]() |
ef80953b1b | ||
![]() |
72db1188c7 | ||
![]() |
0858d3c544 | ||
![]() |
5c5656f981 | ||
![]() |
58a9c92d75 | ||
![]() |
a6dc4646db | ||
![]() |
8ff553e926 | ||
![]() |
848a5c61f0 | ||
![]() |
d49000e9f4 | ||
![]() |
a82145c4e6 | ||
![]() |
181edb7235 | ||
![]() |
ff2ae11ac8 | ||
![]() |
3f841f3b21 | ||
![]() |
181977ad4e | ||
![]() |
e155fe403d | ||
![]() |
bf5438d573 | ||
![]() |
0e4aaf8856 | ||
![]() |
5c44ce1637 | ||
![]() |
974fe25a11 | ||
![]() |
58bae83558 | ||
![]() |
5d309af86f | ||
![]() |
ec857d1c53 | ||
![]() |
2f84cdd708 | ||
![]() |
7cc02e84ed | ||
![]() |
87c2a5bc97 | ||
![]() |
826c2e0f4e | ||
![]() |
b5e25e13b7 | ||
![]() |
f9653114d1 | ||
![]() |
6b7e19891b | ||
![]() |
a677f14423 | ||
![]() |
dddce3f30d | ||
![]() |
be93d670a3 | ||
![]() |
68d4bb6ffe | ||
![]() |
a27471178a | ||
![]() |
66fcb0cc8f | ||
![]() |
05d0ddc281 | ||
![]() |
b1890f50b6 | ||
![]() |
b44c707e94 | ||
![]() |
4c7675939a | ||
![]() |
fa1b7de52a | ||
![]() |
666f8c8d3c | ||
![]() |
996c0b3280 | ||
![]() |
f9d428de8b | ||
![]() |
a17b3f1b84 | ||
![]() |
f39512aa63 | ||
![]() |
23ee9f64d4 | ||
![]() |
ad68739df7 | ||
![]() |
a50d8421b8 | ||
![]() |
3ea1b07906 | ||
![]() |
c3683662c2 | ||
![]() |
861865807a | ||
![]() |
18930082e2 | ||
![]() |
6a14e49479 | ||
![]() |
c530d5f016 | ||
![]() |
ac5e1a6ebd | ||
![]() |
bb6de53f28 | ||
![]() |
bfcd499cc2 | ||
![]() |
3e88ec18e2 | ||
![]() |
1fb640c313 | ||
![]() |
bece3d2bcf | ||
![]() |
307d866bb6 | ||
![]() |
95c9514a44 | ||
![]() |
768be433d6 | ||
![]() |
4d4f38fb35 | ||
![]() |
15ad07f03d | ||
![]() |
0b53c413a7 | ||
![]() |
931397c7e1 | ||
![]() |
ef2cc7ebf5 | ||
![]() |
8d3fd75ec2 | ||
![]() |
a42b254c33 | ||
![]() |
d24e1ae110 | ||
![]() |
2e7badab4e | ||
![]() |
7cf3d49f00 | ||
![]() |
25037006bf | ||
![]() |
f611eb2c2b | ||
![]() |
e12c10b087 | ||
![]() |
9527e5ded8 | ||
![]() |
23b4b20b4f | ||
![]() |
7f9ecd659c | ||
![]() |
bb31d465f2 | ||
![]() |
834468e8e7 | ||
![]() |
4720513672 | ||
![]() |
a480110d43 | ||
![]() |
0a2c95cc10 | ||
![]() |
9d2e32902d | ||
![]() |
77b6413526 | ||
![]() |
9e502099e0 | ||
![]() |
c6a7e44ae7 | ||
![]() |
1bf06312b8 | ||
![]() |
c35721abbd | ||
![]() |
7f3c417078 | ||
![]() |
69511c2783 | ||
![]() |
158a94d34c | ||
![]() |
db58bd68f5 | ||
![]() |
e65f08a2c8 | ||
![]() |
ab8f616385 | ||
![]() |
6dc6f9bbb5 | ||
![]() |
7754bb995b | ||
![]() |
d1fefce61c | ||
![]() |
c3abdab9c4 | ||
![]() |
8b13e103fd | ||
![]() |
5f94f65f4f | ||
![]() |
fc0d69616c | ||
![]() |
656f5b93d6 | ||
![]() |
436d37c079 | ||
![]() |
ed0081fcf7 | ||
![]() |
140062f8a3 | ||
![]() |
75f5fa7c06 | ||
![]() |
9152a1a266 | ||
![]() |
ade89ab795 | ||
![]() |
95cfdee8b8 | ||
![]() |
63a27cc5e2 | ||
![]() |
472face796 | ||
![]() |
8d537a6d0b | ||
![]() |
b3101d339e | ||
![]() |
85acddddba | ||
![]() |
c9d747d97f | ||
![]() |
0bba267808 | ||
![]() |
1036242064 | ||
![]() |
5fd62098bd | ||
![]() |
74cc7be922 | ||
![]() |
b3814ca89a | ||
![]() |
b75a321e4a | ||
![]() |
9caa4fec4a | ||
![]() |
a0cba1aee1 | ||
![]() |
97018ad62f | ||
![]() |
a7d17fae44 | ||
![]() |
6ce0050979 | ||
![]() |
bc035fca78 | ||
![]() |
df914a92e4 | ||
![]() |
1b939a6823 | ||
![]() |
81b6d988ec | ||
![]() |
7e9b65feca | ||
![]() |
6f098b3d21 | ||
![]() |
5ddb0488f2 | ||
![]() |
3e87314adf | ||
![]() |
f6d4a06661 | ||
![]() |
ff17fc95e6 | ||
![]() |
c5a46f1cea | ||
![]() |
0b072189c4 | ||
![]() |
5b22d1486a | ||
![]() |
9eb48c2b0d | ||
![]() |
ff0632001c | ||
![]() |
28bd09a2ea | ||
![]() |
c6aaa9b09c | ||
![]() |
20d9ec1fd2 | ||
![]() |
2c45c2d3c0 | ||
![]() |
18829e648a | ||
![]() |
a64c636a33 | ||
![]() |
5796f211c1 | ||
![]() |
ae09dec05e | ||
![]() |
afd51e0823 | ||
![]() |
0bbf826b21 | ||
![]() |
02d1900e2f | ||
![]() |
73da11b04c | ||
![]() |
4af07e3731 | ||
![]() |
7f60f85cd4 | ||
![]() |
4c66cb1854 | ||
![]() |
35b92e1511 | ||
![]() |
e5d3fe52c5 | ||
![]() |
63fe7c0a86 | ||
![]() |
c5f137c715 | ||
![]() |
66923bc0e3 | ||
![]() |
8bf7b5a323 | ||
![]() |
36d4d85849 | ||
![]() |
5f0e05f3bf | ||
![]() |
235e5511eb | ||
![]() |
6fb60ae0b1 | ||
![]() |
6b2883074b | ||
![]() |
7fe418d1b7 | ||
![]() |
f872ceb0d9 | ||
![]() |
0f10a36b40 | ||
![]() |
3c45c9170f | ||
![]() |
a0730aeb44 | ||
![]() |
e5fdc7fdd0 | ||
![]() |
015c87b5e1 | ||
![]() |
d20a49e500 | ||
![]() |
adb7331670 | ||
![]() |
084f0d27a3 | ||
![]() |
522a0beec0 | ||
![]() |
bf46bcf376 | ||
![]() |
f330c3f8c5 | ||
![]() |
77a51c1e05 | ||
![]() |
144f215705 | ||
![]() |
51b01b6b44 | ||
![]() |
09885534c6 | ||
![]() |
b9dfec38c2 | ||
![]() |
2ef8120073 | ||
![]() |
52ff2e0e63 | ||
![]() |
8cf7dce33f | ||
![]() |
9d3bb4a37a | ||
![]() |
c30437448b | ||
![]() |
7e3496f8aa | ||
![]() |
46ac79f4dc | ||
![]() |
833b14e353 | ||
![]() |
e9eca25792 | ||
![]() |
1854ad133c | ||
![]() |
2b5e723ea5 | ||
![]() |
9a18906edd | ||
![]() |
93cb7582c2 | ||
![]() |
b4529639f6 | ||
![]() |
f0a59fccf8 | ||
![]() |
46dbaf95a6 | ||
![]() |
d418b03708 | ||
![]() |
765e90ecfa | ||
![]() |
ff1e88dde6 | ||
![]() |
62ebcba647 | ||
![]() |
429e90183b | ||
![]() |
875790e862 | ||
![]() |
25edbe6805 | ||
![]() |
e148b50d6a | ||
![]() |
06d46d56cd | ||
![]() |
edd8770c67 | ||
![]() |
daedda8547 | ||
![]() |
df9d897e75 | ||
![]() |
fcd8e5e5ad | ||
![]() |
6c003f71f4 | ||
![]() |
5b704478d9 | ||
![]() |
60eb528d68 | ||
![]() |
1cf730d957 | ||
![]() |
171110b445 | ||
![]() |
22699db855 | ||
![]() |
18405b3908 | ||
![]() |
f0a55b5cbb | ||
![]() |
04a0774ee5 | ||
![]() |
3a8cfb1f45 | ||
![]() |
dcc19d17d4 | ||
![]() |
1ef69adc6f | ||
![]() |
75a4df0f32 | ||
![]() |
8ba1b5fc35 | ||
![]() |
a09471ac6c | ||
![]() |
a916eea684 | ||
![]() |
511998d8e1 | ||
![]() |
e3cf50f791 | ||
![]() |
42ba5298a7 | ||
![]() |
ee79750a22 | ||
![]() |
1787f8617f | ||
![]() |
748ca28185 | ||
![]() |
9c68d713ba | ||
![]() |
fc69678206 | ||
![]() |
aebd717039 | ||
![]() |
1ddb01ac44 | ||
![]() |
3e279cd670 | ||
![]() |
724c03630a | ||
![]() |
b00b2561e5 | ||
![]() |
c5b50fe3cf | ||
![]() |
df9884de3c | ||
![]() |
65ae7669f9 | ||
![]() |
179606feb1 | ||
![]() |
536140340e | ||
![]() |
5d293df64b | ||
![]() |
6188891a53 | ||
![]() |
9774661cfe | ||
![]() |
563bc34fb5 | ||
![]() |
9c95ab3a28 | ||
![]() |
b776c37b36 | ||
![]() |
5b3f92b70f | ||
![]() |
1562b81522 | ||
![]() |
be1016ace6 | ||
![]() |
ee27c689e1 | ||
![]() |
fdbf452ced | ||
![]() |
3d9927dee0 | ||
![]() |
1456b128d2 | ||
![]() |
166f77cb86 | ||
![]() |
5577838905 | ||
![]() |
9c15982299 | ||
![]() |
63c24122db | ||
![]() |
1396ca903d | ||
![]() |
d1fb5bdc30 | ||
![]() |
e27812bf3e | ||
![]() |
11a3cf9b99 | ||
![]() |
a90d70feae | ||
![]() |
466b34735c | ||
![]() |
7ca9116e37 | ||
![]() |
decd3e737c | ||
![]() |
f35442ad1b | ||
![]() |
2b296435b3 | ||
![]() |
19ee1dfecc | ||
![]() |
7da4596ef8 | ||
![]() |
a379ef6781 | ||
![]() |
7beb065be3 | ||
![]() |
38b9091513 | ||
![]() |
96db3c9601 | ||
![]() |
43c4fc8e33 | ||
![]() |
986ff101ce | ||
![]() |
94c83c445f | ||
![]() |
625865412f | ||
![]() |
46677e69ce | ||
![]() |
5fbca5b823 | ||
![]() |
879fab120f | ||
![]() |
391b24bc17 | ||
![]() |
d713533d26 | ||
![]() |
24f745a334 | ||
![]() |
86f3101861 | ||
![]() |
fd823c63ab | ||
![]() |
fa69892f70 | ||
![]() |
cfc53d0d26 | ||
![]() |
97c2056e4a | ||
![]() |
0ad0164171 | ||
![]() |
df0e285b6f | ||
![]() |
e92f1b8c28 | ||
![]() |
410f86c960 | ||
![]() |
85f27320e7 | ||
![]() |
9a3fac90e1 | ||
![]() |
6984f6eec4 | ||
![]() |
d05f502fc8 | ||
![]() |
ba41ab8f67 | ||
![]() |
250bb7e29d | ||
![]() |
48a26fd5df | ||
![]() |
3af26540ec | ||
![]() |
7d9de068d9 | ||
![]() |
d174917a07 | ||
![]() |
af398fc4c4 | ||
![]() |
878ef446a2 | ||
![]() |
668f6477bb | ||
![]() |
01a770cbca | ||
![]() |
23a1174aa2 | ||
![]() |
414020e75b | ||
![]() |
ed74bccad6 | ||
![]() |
0eedde445c | ||
![]() |
88bf78213f | ||
![]() |
d342461a51 | ||
![]() |
dffaaf8751 | ||
![]() |
313edadf47 | ||
![]() |
c9ce33dfe6 | ||
![]() |
0f50ac7205 | ||
![]() |
e807c08275 | ||
![]() |
893977365c | ||
![]() |
0cac45809f | ||
![]() |
489ca3c207 | ||
![]() |
313535c599 | ||
![]() |
7f1e0557c9 | ||
![]() |
0860f84a39 | ||
![]() |
2fe9e78b6d | ||
![]() |
2ba30f2022 | ||
![]() |
b3b27cab34 | ||
![]() |
694207a86d | ||
![]() |
90138c4bae | ||
![]() |
58a833e987 | ||
![]() |
86c5a569d5 | ||
![]() |
19592e8eea | ||
![]() |
8e6678d526 | ||
![]() |
e792a1e030 | ||
![]() |
f0e818a28c | ||
![]() |
69bd63b742 | ||
![]() |
b40f30f2e5 | ||
![]() |
1fbde87ec2 | ||
![]() |
f9dc34c8fa | ||
![]() |
f7186f5331 | ||
![]() |
6a680e4db0 | ||
![]() |
f6b69f412f | ||
![]() |
5aed18862d | ||
![]() |
62bf213a6e | ||
![]() |
e5c32e9b48 | ||
![]() |
b87dc37fbb | ||
![]() |
002d4cb37c | ||
![]() |
ff321fc355 | ||
![]() |
c3386dec84 | ||
![]() |
927d2761f7 | ||
![]() |
5e5f513088 | ||
![]() |
9fcf725061 | ||
![]() |
601e015f00 | ||
![]() |
3289e8403a | ||
![]() |
104a7c7d05 | ||
![]() |
7560660ec7 | ||
![]() |
40ccb4a0dd | ||
![]() |
f90288f5dc | ||
![]() |
3bf79898d9 | ||
![]() |
1d6e11ca10 | ||
![]() |
6e903ee7d5 | ||
![]() |
21fb1dff7e | ||
![]() |
da924a359c | ||
![]() |
a5066f15dc | ||
![]() |
2dca53a696 | ||
![]() |
bfbcdf8b86 | ||
![]() |
42e1d18470 | ||
![]() |
435dc72aa1 | ||
![]() |
66c380548b | ||
![]() |
13f81e9a6f | ||
![]() |
68c8796adb | ||
![]() |
4232f5342e | ||
![]() |
28c31359bf | ||
![]() |
a36e815227 | ||
![]() |
ff3d33d5e0 | ||
![]() |
d015d6b103 | ||
![]() |
0d160fbeaa | ||
![]() |
fedd7920a8 | ||
![]() |
6afac06596 | ||
![]() |
91b2b40b9a | ||
![]() |
56ecb6a3ea | ||
![]() |
64f73f624f | ||
![]() |
20b78b68a6 | ||
![]() |
d8a6d7e02f | ||
![]() |
d1cc14201b | ||
![]() |
a57ec9e669 | ||
![]() |
1a8961587c | ||
![]() |
fa13ad8849 | ||
![]() |
8b23dec322 | ||
![]() |
4e8aac4b41 | ||
![]() |
9c72b557ec | ||
![]() |
207ec1e032 | ||
![]() |
ff5d4276bc | ||
![]() |
26c9618e63 | ||
![]() |
9c306899ba | ||
![]() |
4b7e7aab33 | ||
![]() |
2921e9f868 | ||
![]() |
70b7606cb8 | ||
![]() |
0cae91d525 | ||
![]() |
2c2a28e46b | ||
![]() |
c75d484f23 | ||
![]() |
072f7fec30 | ||
![]() |
a73379495f | ||
![]() |
0b914866eb | ||
![]() |
f12186d024 | ||
![]() |
4a2835dc84 | ||
![]() |
55dc45de33 | ||
![]() |
39aa64ff68 | ||
![]() |
94bb91f2fa | ||
![]() |
f553ca95a5 | ||
![]() |
b44e8167d7 | ||
![]() |
36c1122d20 | ||
![]() |
ad13529eaa | ||
![]() |
04c8f4a5ed | ||
![]() |
850446195f | ||
![]() |
865506546f | ||
![]() |
fe72fadedd | ||
![]() |
9cf9d3ad5c | ||
![]() |
426d0e6af1 | ||
![]() |
483b442b7d | ||
![]() |
9420b0c947 | ||
![]() |
dcfb7345f0 | ||
![]() |
f9ab24a077 | ||
![]() |
f932d16ba7 | ||
![]() |
7d9acc3c36 | ||
![]() |
72f735124f | ||
![]() |
6ea5a4719a | ||
![]() |
f8c50b7f1e | ||
![]() |
feb1f1d71a | ||
![]() |
550afc27dc | ||
![]() |
e6a828572a | ||
![]() |
6ea43d8e6d | ||
![]() |
d13af4bdc4 | ||
![]() |
53a365dd2b | ||
![]() |
6726affa7e | ||
![]() |
6ecf2a6eb2 | ||
![]() |
a359e11f97 | ||
![]() |
54b2d74068 | ||
![]() |
c99aa7279b | ||
![]() |
4fa568ce8a | ||
![]() |
874698b93f | ||
![]() |
b286fc1e4a | ||
![]() |
1cf1024332 | ||
![]() |
6b391b701b | ||
![]() |
efc90f8f5a | ||
![]() |
6535ba7c24 | ||
![]() |
5c29c3d160 | ||
![]() |
742d4bff78 | ||
![]() |
7726ffa3f7 | ||
![]() |
b442d78ebb | ||
![]() |
d44edb5930 | ||
![]() |
d5633b3705 | ||
![]() |
3b68dc72e7 | ||
![]() |
51611c3934 | ||
![]() |
747b7567d7 | ||
![]() |
797891d6cf | ||
![]() |
286dc3c32b | ||
![]() |
a66ba21c3d | ||
![]() |
b139810b6a | ||
![]() |
dddc18d77c | ||
![]() |
56f56d008a | ||
![]() |
81a8a99b6e | ||
![]() |
07aa0ee7ad | ||
![]() |
b66a6bddbc | ||
![]() |
d57d90fe6b | ||
![]() |
de6c646ee8 | ||
![]() |
4839ede64f | ||
![]() |
84f5faf653 | ||
![]() |
281077bc26 | ||
![]() |
ed5fe9ae9f | ||
![]() |
1866e4ef44 | ||
![]() |
a6a07c3b3a | ||
![]() |
b2af8e640c | ||
![]() |
7a3f5d508b | ||
![]() |
7e1fd03104 | ||
![]() |
758415d326 | ||
![]() |
1660041470 | ||
![]() |
1783df883e | ||
![]() |
b2be821637 | ||
![]() |
051ff2b325 | ||
![]() |
4d6f9ffd7c | ||
![]() |
d614823013 | ||
![]() |
48aa51b739 | ||
![]() |
41c6125e1b | ||
![]() |
bb3d48f98b | ||
![]() |
b5e46e83e2 | ||
![]() |
2340910b46 | ||
![]() |
d8c4c1525d | ||
![]() |
6713ef7726 | ||
![]() |
ae7555b065 | ||
![]() |
ee6ff0cc60 | ||
![]() |
94b2352c2c | ||
![]() |
cf3f943feb | ||
![]() |
55c4d583b9 | ||
![]() |
0e1bb6ab04 | ||
![]() |
7944cff7a5 | ||
![]() |
8b08a370c5 | ||
![]() |
2d5fd2fe1c | ||
![]() |
b5e50ecb75 | ||
![]() |
e00c9d0ee0 | ||
![]() |
be9c9f045a | ||
![]() |
75fca1b9c7 | ||
![]() |
1436fb3ef4 | ||
![]() |
2bfd127218 | ||
![]() |
de5da63d5c | ||
![]() |
fb419eaa36 | ||
![]() |
cf2a363e5e | ||
![]() |
7401facc21 | ||
![]() |
579afe012b | ||
![]() |
4f856e8783 | ||
![]() |
eb059183f7 | ||
![]() |
419156f7cc | ||
![]() |
b7f7883fb7 | ||
![]() |
a5a7490bca | ||
![]() |
6724d8131c | ||
![]() |
a19bb15070 | ||
![]() |
2ee0147848 | ||
![]() |
252f1add7e | ||
![]() |
413c92c631 | ||
![]() |
36d519026f | ||
![]() |
aa54785918 | ||
![]() |
d6b386083f | ||
![]() |
82f383b64f | ||
![]() |
a15ee3ad06 | ||
![]() |
29680cb515 | ||
![]() |
884749f345 | ||
![]() |
5c63ce666c | ||
![]() |
5632d073be | ||
![]() |
f9056099f9 | ||
![]() |
7c09ec29f7 | ||
![]() |
6f0b09509e | ||
![]() |
31c53d67e2 | ||
![]() |
6a322ba3f8 | ||
![]() |
dece636d54 | ||
![]() |
b29f648148 | ||
![]() |
c91d264ff1 | ||
![]() |
487e3352e4 | ||
![]() |
34966fb182 | ||
![]() |
17a92a58b2 | ||
![]() |
60d3e5b9e0 | ||
![]() |
d193a1eb70 | ||
![]() |
1501c56bbc | ||
![]() |
6d18fb6bae | ||
![]() |
eac26a4514 | ||
![]() |
1649f30808 | ||
![]() |
82680bf43f | ||
![]() |
41da793b5a | ||
![]() |
cfb5734b85 | ||
![]() |
b72d841619 | ||
![]() |
0ef39f35ae | ||
![]() |
38d1ed76d2 | ||
![]() |
4c80cd185f | ||
![]() |
629524af04 | ||
![]() |
a245e54bd3 | ||
![]() |
52e485cce9 | ||
![]() |
02d374b65b | ||
![]() |
0de6bb0063 | ||
![]() |
9d6b379999 | ||
![]() |
c132c4e673 | ||
![]() |
6962dcd66c | ||
![]() |
2a9496fcda | ||
![]() |
82d1d30a41 | ||
![]() |
85639d0806 | ||
![]() |
3fd6ecaedb | ||
![]() |
884d3a0316 | ||
![]() |
10dbb9186d | ||
![]() |
a547798b08 | ||
![]() |
894b434875 | ||
![]() |
8db0ece459 | ||
![]() |
f56c5e3a45 | ||
![]() |
0a5fa72099 | ||
![]() |
0eaccea38f | ||
![]() |
de32c389d0 | ||
![]() |
753d2da6db | ||
![]() |
d3344da9c5 | ||
![]() |
ae0876876e | ||
![]() |
dea8e16f49 | ||
![]() |
13803bdb30 | ||
![]() |
7257e5794f | ||
![]() |
41c52487ee | ||
![]() |
0eb779185d | ||
![]() |
3d790a71a0 | ||
![]() |
cfc32d940a | ||
![]() |
59242df7d6 | ||
![]() |
fad9fbca6f | ||
![]() |
c81c92967c | ||
![]() |
fa36dcbe09 | ||
![]() |
c72bcc136c | ||
![]() |
d52f5f0b09 | ||
![]() |
4f6650fce2 | ||
![]() |
2774414f9e | ||
![]() |
c1f1dca22c | ||
![]() |
965fbc917d | ||
![]() |
2a1b63c93c | ||
![]() |
011be51232 | ||
![]() |
d1c4f3172f | ||
![]() |
14697c7ea9 | ||
![]() |
54ca8c787b | ||
![]() |
88c3bffe20 | ||
![]() |
a4f85cd02e | ||
![]() |
fd118a41fd | ||
![]() |
b0f71c5304 | ||
![]() |
a162f2ce34 | ||
![]() |
0f64702d72 | ||
![]() |
3c355f19eb | ||
![]() |
fb9f2171a9 | ||
![]() |
4efcb6d5ad | ||
![]() |
5ddc166b12 | ||
![]() |
ecd7e5bdd3 | ||
![]() |
d0a121ad06 | ||
![]() |
85a28d3c30 | ||
![]() |
5bba3388a0 | ||
![]() |
0ad31a471b | ||
![]() |
28f7abd1f8 | ||
![]() |
049a5a7493 | ||
![]() |
a9ee01c7ec | ||
![]() |
1f89b15792 | ||
![]() |
afe390d407 | ||
![]() |
6f4f2758d6 | ||
![]() |
592ee5f839 | ||
![]() |
a811c84e99 | ||
![]() |
214162adf0 | ||
![]() |
28396c8620 | ||
![]() |
72fba62e09 | ||
![]() |
5669cafc59 | ||
![]() |
0c7275da1a | ||
![]() |
e5cbf25cbd | ||
![]() |
c3cf618e84 | ||
![]() |
7780a8c187 | ||
![]() |
40f1e14bb7 | ||
![]() |
a7cd4ccd09 | ||
![]() |
6fd69b6284 | ||
![]() |
96424b6b0a | ||
![]() |
bef34d66f5 | ||
![]() |
c6049be688 | ||
![]() |
5ea653244e | ||
![]() |
596bb54ee3 | ||
![]() |
7554e87374 | ||
![]() |
6176964bdf | ||
![]() |
f77bb81def | ||
![]() |
ed4752bbc0 | ||
![]() |
30862c0a3e | ||
![]() |
7c4ffa8866 | ||
![]() |
a79f073077 | ||
![]() |
4682d7b4b8 | ||
![]() |
d2217b5c5f | ||
![]() |
0a160c4a0b | ||
![]() |
aed8255a8b | ||
![]() |
ba60659894 | ||
![]() |
1ad7b95437 | ||
![]() |
cc43ee3b3d | ||
![]() |
5a7b70c054 | ||
![]() |
e9bfa30c1d | ||
![]() |
bb83a25a52 | ||
![]() |
99c8d779dc | ||
![]() |
2c1ff5bf5d | ||
![]() |
e218a59911 | ||
![]() |
11f3c79a77 | ||
![]() |
5cfd8b9aa8 | ||
![]() |
ebce7b01c7 | ||
![]() |
9d4b104d2d | ||
![]() |
5a6fb679c9 | ||
![]() |
9102a9cd6e | ||
![]() |
573d1da0ef | ||
![]() |
2848dce968 | ||
![]() |
ba1e006585 | ||
![]() |
9108a4c69f | ||
![]() |
f42ceb1baa | ||
![]() |
5903dd2939 | ||
![]() |
55b39a3f15 | ||
![]() |
9bc69f7de9 | ||
![]() |
2aa380c5a3 | ||
![]() |
638fbcb619 | ||
![]() |
ccbbce0036 | ||
![]() |
41918eaf0a | ||
![]() |
5c344f7efa | ||
![]() |
213580ea78 | ||
![]() |
d5fd269fda | ||
![]() |
2cf4baddfb | ||
![]() |
48d496936a | ||
![]() |
e410c06a68 | ||
![]() |
f6c2d0bcaf | ||
![]() |
e2a16f96a8 | ||
![]() |
49fdc6563f | ||
![]() |
b5bbef09c5 | ||
![]() |
7a1e089725 | ||
![]() |
7de3f7aa78 | ||
![]() |
02b9a0a297 | ||
![]() |
0b9094d348 | ||
![]() |
a86cc32dff | ||
![]() |
974c857a97 | ||
![]() |
6e53fa03f5 | ||
![]() |
8c5e214131 | ||
![]() |
cf60ebd988 | ||
![]() |
9dd954bccd | ||
![]() |
a02eb8e7cb | ||
![]() |
a93ca9b8f1 | ||
![]() |
15e4ec7ffb | ||
![]() |
62df50e22b | ||
![]() |
055430d4b8 | ||
![]() |
57f27c41e0 | ||
![]() |
385328ffd5 | ||
![]() |
34d1e5e67e | ||
![]() |
4f832ac9af | ||
![]() |
b0bf989056 | ||
![]() |
fd0e8624c4 | ||
![]() |
5566668a5f | ||
![]() |
f8e6becb9e | ||
![]() |
dd28d70680 | ||
![]() |
ed8e3f237c | ||
![]() |
77c04c4cf9 | ||
![]() |
ebc8d7168a | ||
![]() |
434fa74e67 | ||
![]() |
47a4f34cdf | ||
![]() |
1317b1799c | ||
![]() |
fcae4a9f0a | ||
![]() |
d733c5bb7c | ||
![]() |
baf8254907 | ||
![]() |
802e7d4654 | ||
![]() |
616e20d467 | ||
![]() |
5c7c2cf85e | ||
![]() |
1942644434 | ||
![]() |
b67482de9b | ||
![]() |
35bb71f952 | ||
![]() |
9c91b09ab1 | ||
![]() |
06911a8d2e | ||
![]() |
e7922c1b54 | ||
![]() |
16959caa34 | ||
![]() |
0675f388b9 | ||
![]() |
b4ad9459da | ||
![]() |
8a9b1fee14 | ||
![]() |
e6eb697bb2 | ||
![]() |
4ccc782e29 | ||
![]() |
cfdd9f66d1 | ||
![]() |
035cbf84ae | ||
![]() |
31e92a8b4f | ||
![]() |
87c24e5a7c | ||
![]() |
552ff9d736 | ||
![]() |
738396c2e2 | ||
![]() |
9f18b5a096 | ||
![]() |
15c965c08c | ||
![]() |
7a8fd6b0df | ||
![]() |
3ada6f358c | ||
![]() |
f1c2854358 | ||
![]() |
87559a34f8 | ||
![]() |
9586351f37 | ||
![]() |
0f6ed642da | ||
![]() |
6d1d4ade19 | ||
![]() |
73a57e1105 | ||
![]() |
e7314d1775 | ||
![]() |
ee8f8c2930 | ||
![]() |
64e0e2d19f | ||
![]() |
6bb4dae5e0 | ||
![]() |
83e9d08853 | ||
![]() |
7dfa62516c | ||
![]() |
15e7d8ab2e | ||
![]() |
a4f77984b7 | ||
![]() |
39b279f0f2 | ||
![]() |
ac44900fc4 | ||
![]() |
548458c3e0 | ||
![]() |
986b0aa106 | ||
![]() |
01b42fb399 | ||
![]() |
f74d44152a | ||
![]() |
1557854755 | ||
![]() |
56d6c2a929 | ||
![]() |
2d4512cd1c | ||
![]() |
5402e6d3a6 | ||
![]() |
52c59e7133 | ||
![]() |
7654c2f902 | ||
![]() |
be9eca2d63 | ||
![]() |
d5ad5e46da | ||
![]() |
a486fb99a9 | ||
![]() |
2b10860c32 | ||
![]() |
a03f216f42 | ||
![]() |
7d7cbaacf1 | ||
![]() |
00b5a496dd | ||
![]() |
7e6c92dc52 | ||
![]() |
6cf3754051 | ||
![]() |
cf7616ebe5 | ||
![]() |
5b7964f8b6 | ||
![]() |
f1f38c24da | ||
![]() |
67a50becb0 | ||
![]() |
d7e94473f3 | ||
![]() |
184c896f41 | ||
![]() |
8be849cc40 | ||
![]() |
275851a755 | ||
![]() |
16182472fa | ||
![]() |
29f3c22fed | ||
![]() |
a116666d55 | ||
![]() |
c2622511ce | ||
![]() |
50243037eb | ||
![]() |
74f305cfb7 | ||
![]() |
75990fbaf4 | ||
![]() |
cc982c5a61 | ||
![]() |
2d05243c4a | ||
![]() |
2f0a582aa7 | ||
![]() |
665881471d | ||
![]() |
39211f8fbd | ||
![]() |
32ea45d403 | ||
![]() |
cd17a42234 | ||
![]() |
8e19b5938c | ||
![]() |
9e208ab744 | ||
![]() |
94bd9702e5 | ||
![]() |
3add40625d | ||
![]() |
5afae986a0 | ||
![]() |
f091d82bad | ||
![]() |
a73a7d1e7b | ||
![]() |
5c1ef2c1cf | ||
![]() |
8411255700 | ||
![]() |
c657c531b4 | ||
![]() |
ef9d8710f5 | ||
![]() |
75fc9f91b9 | ||
![]() |
ef9edfd160 | ||
![]() |
234a7925c6 | ||
![]() |
a550b5c112 | ||
![]() |
04798cbf5b | ||
![]() |
545d9eb59b | ||
![]() |
a9b67c3028 | ||
![]() |
35e79f3985 | ||
![]() |
435d5585e9 | ||
![]() |
ddfb7f2861 | ||
![]() |
6c806549ae | ||
![]() |
8957e4ec25 | ||
![]() |
2003eceba1 | ||
![]() |
8fc1462d11 | ||
![]() |
93b45e9598 | ||
![]() |
a3a14cdab2 | ||
![]() |
9ba2f99ea2 | ||
![]() |
f9db796a6e | ||
![]() |
94c7aaf7f8 | ||
![]() |
6ef6d9a905 | ||
![]() |
b44e9baaec | ||
![]() |
f9176bfdea | ||
![]() |
721044b378 | ||
![]() |
154f8570f0 | ||
![]() |
0464d31a9c | ||
![]() |
e3453553e1 | ||
![]() |
6abaa78f9e | ||
![]() |
457507d8dc | ||
![]() |
3ea1a80496 | ||
![]() |
fac4bca4f4 | ||
![]() |
662e0c9965 | ||
![]() |
80af9e6d76 | ||
![]() |
9b466db5c9 | ||
![]() |
c34427690a | ||
![]() |
d8a974bb4f | ||
![]() |
98b08676e2 | ||
![]() |
39f3a63ced | ||
![]() |
89e2084489 | ||
![]() |
70c56b7db3 | ||
![]() |
209b763302 | ||
![]() |
190b7a6076 | ||
![]() |
cce47a633a | ||
![]() |
ec2330c42b | ||
![]() |
0c215685f2 | ||
![]() |
d86ac5e3e0 | ||
![]() |
ee89b6ad03 | ||
![]() |
a5e6d6d2e8 | ||
![]() |
1eea1f5485 | ||
![]() |
da4567eea5 | ||
![]() |
9010a6573f | ||
![]() |
d8e480ab48 | ||
![]() |
0bd61f6a57 | ||
![]() |
c01cbb3a8c | ||
![]() |
0ca5c4eeff | ||
![]() |
47927608b2 | ||
![]() |
13808bf282 | ||
![]() |
c3c7964e2e | ||
![]() |
fca0221d91 | ||
![]() |
9f2d73e2f1 | ||
![]() |
fc19f2ea34 | ||
![]() |
aa0f15fbb2 | ||
![]() |
93f50b8ef7 | ||
![]() |
7b85843363 | ||
![]() |
f7f578ed44 | ||
![]() |
de92603ccf | ||
![]() |
d02fffb6b8 | ||
![]() |
922c96e3c1 | ||
![]() |
993627ec44 | ||
![]() |
01681599ff | ||
![]() |
3ce6434532 | ||
![]() |
a97e554f8f | ||
![]() |
fd5a79a685 | ||
![]() |
635921adc7 | ||
![]() |
9eb4cecbc1 | ||
![]() |
879b9a4a15 | ||
![]() |
8be4dc8fb5 | ||
![]() |
f16ea20de5 | ||
![]() |
c51b14856e | ||
![]() |
88ee71c425 | ||
![]() |
edb12da154 | ||
![]() |
d9f6846c76 | ||
![]() |
9e0747db15 | ||
![]() |
ae3d33ad58 | ||
![]() |
edb25f799d | ||
![]() |
0822674f70 | ||
![]() |
49d004736a | ||
![]() |
695f8733bb | ||
![]() |
b51af7f4bf | ||
![]() |
28ce2447ef | ||
![]() |
42e3a50274 | ||
![]() |
8ebc92c236 | ||
![]() |
b92e46df40 | ||
![]() |
be5588d5d8 | ||
![]() |
0d9fb2f927 | ||
![]() |
0e9819fba1 | ||
![]() |
aaee40aabd | ||
![]() |
5efe51b661 | ||
![]() |
50f63142db | ||
![]() |
1b65b2e0c6 | ||
![]() |
ce8742c605 | ||
![]() |
01a013b48a | ||
![]() |
3a2eeb9709 | ||
![]() |
1271c7d958 | ||
![]() |
0032f525ce | ||
![]() |
df2f91b82f | ||
![]() |
3a1ef6bef2 | ||
![]() |
28488075b9 | ||
![]() |
3cd3b2d9b7 | ||
![]() |
3d88818841 | ||
![]() |
b74cf65eca | ||
![]() |
80fcacaf8b | ||
![]() |
96fcd8443f | ||
![]() |
707c55fbe7 | ||
![]() |
c44b5551bc | ||
![]() |
bd28da0abc | ||
![]() |
410299f5a1 | ||
![]() |
f3fc958a0c | ||
![]() |
47b417db28 | ||
![]() |
5171cdd305 | ||
![]() |
65950250d9 | ||
![]() |
74ae0007d3 | ||
![]() |
977081f4af | ||
![]() |
ee70f1e55e | ||
![]() |
9c16f6dbea | ||
![]() |
c50aa34dd9 | ||
![]() |
0e479d53da | ||
![]() |
984c086296 | ||
![]() |
53e00b2b4c | ||
![]() |
bb1cb29edd | ||
![]() |
bf6879e46f | ||
![]() |
12e900e8f9 | ||
![]() |
d7fff12b71 | ||
![]() |
9051e985a0 | ||
![]() |
5361c6f243 | ||
![]() |
963aef19e0 | ||
![]() |
f95fe4192b |
38
.appveyor.yml
Normal file
38
.appveyor.yml
Normal file
@ -0,0 +1,38 @@
|
||||
version: "{branch}.{build}"
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- TOXENV: py36-no-ext
|
||||
PYTHON: "C:\\Python36-x64"
|
||||
PYTHON_VERSION: "3.6.x"
|
||||
PYTHON_ARCH: "64"
|
||||
|
||||
- TOXENV: py37-no-ext
|
||||
PYTHON: "C:\\Python37-x64"
|
||||
PYTHON_VERSION: "3.7.x"
|
||||
PYTHON_ARCH: "64"
|
||||
|
||||
- TOXENV: py38-no-ext
|
||||
PYTHON: "C:\\Python38-x64"
|
||||
PYTHON_VERSION: "3.8.x"
|
||||
PYTHON_ARCH: "64"
|
||||
|
||||
# - TOXENV: py39-no-ext
|
||||
# PYTHON: "C:\\Python39-x64\\python"
|
||||
# PYTHONPATH: "C:\\Python39-x64"
|
||||
# PYTHON_VERSION: "3.9.x"
|
||||
# PYTHON_ARCH: "64"
|
||||
|
||||
init: SET "PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||
|
||||
install:
|
||||
- pip install tox
|
||||
|
||||
build: off
|
||||
|
||||
test_script: tox
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
on_build_success: false
|
||||
on_build_status_changed: false
|
24
.coveragerc
24
.coveragerc
@ -1,7 +1,25 @@
|
||||
[run]
|
||||
branch = True
|
||||
source = sanic, tests
|
||||
omit = site-packages
|
||||
source = sanic
|
||||
omit =
|
||||
site-packages
|
||||
sanic/__main__.py
|
||||
sanic/server/legacy.py
|
||||
sanic/compat.py
|
||||
sanic/simple.py
|
||||
sanic/utils.py
|
||||
sanic/cli
|
||||
sanic/pages
|
||||
|
||||
[html]
|
||||
directory = coverage
|
||||
directory = coverage
|
||||
|
||||
[report]
|
||||
exclude_lines =
|
||||
no cov
|
||||
no qa
|
||||
noqa
|
||||
NOQA
|
||||
pragma: no cover
|
||||
TYPE_CHECKING
|
||||
skip_empty = True
|
||||
|
3
.github/CODEOWNERS
vendored
Normal file
3
.github/CODEOWNERS
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
* @sanic-org/sanic-release-managers
|
||||
/sanic/ @sanic-org/framework
|
||||
/tests/ @sanic-org/framework
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: sanic-org # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
78
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
78
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
name: 🐞 Bug report
|
||||
description: Create a report to help us improve
|
||||
labels: ["bug", "triage"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: existing
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue already exists for the bug you encountered.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is, make sure to paste any exceptions and tracebacks using markdown code-block syntax to make it easier to read.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: code
|
||||
attributes:
|
||||
label: Code snippet
|
||||
description: |
|
||||
Relevant source code, make sure to remove what is not necessary. Please try and format your code so that it is easier to read. For example:
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
|
||||
app = Sanic("Example")
|
||||
```
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A concise description of what you expected to happen.
|
||||
validations:
|
||||
required: false
|
||||
- type: dropdown
|
||||
id: running
|
||||
attributes:
|
||||
label: How do you run Sanic?
|
||||
options:
|
||||
- Sanic CLI
|
||||
- As a module
|
||||
- As a script (`app.run` or `Sanic.serve`)
|
||||
- ASGI
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: What OS?
|
||||
options:
|
||||
- Linux
|
||||
- MacOS
|
||||
- Windows
|
||||
- Other (tell us in the description)
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Sanic Version
|
||||
description: Check startup logs or try `sanic --version`
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
validations:
|
||||
required: false
|
||||
|
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions and Help
|
||||
url: https://community.sanicframework.org/c/questions-and-help
|
||||
about: Do you need help with Sanic? Ask your questions here.
|
||||
- name: Discussion and Support
|
||||
url: https://discord.gg/FARQzAEMAA
|
||||
about: For live discussion and support, checkout the Sanic Discord server.
|
34
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
34
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: 🌟 Feature request
|
||||
description: Suggest an enhancement for Sanic
|
||||
labels: ["feature request"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: existing
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue already exists for the enhancement you are proposing.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: code
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
||||
validations:
|
||||
required: false
|
||||
|
33
.github/ISSUE_TEMPLATE/rfc.yml
vendored
Normal file
33
.github/ISSUE_TEMPLATE/rfc.yml
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
name: 💡 Request for Comments
|
||||
description: Open an RFC for discussion
|
||||
labels: ["RFC"]
|
||||
body:
|
||||
- type: input
|
||||
id: compare
|
||||
attributes:
|
||||
label: Link to code
|
||||
description: If available, share a [comparison](https://github.com/sanic-org/sanic/compare) from a POC branch to main
|
||||
placeholder: https://github.com/sanic-org/sanic/compare/main...some-new-branch
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: proposal
|
||||
attributes:
|
||||
label: Proposal
|
||||
description: A thorough discussion of the proposal discussing the problem it solves, potential code, use cases, and impacts
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context that is relevant
|
||||
validations:
|
||||
required: false
|
||||
- type: checkboxes
|
||||
id: breaking
|
||||
attributes:
|
||||
label: Is this a breaking change?
|
||||
options:
|
||||
- label: "Yes"
|
||||
required: false
|
20
.github/stale.yml
vendored
Normal file
20
.github/stale.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 90
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 30
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- bug
|
||||
- urgent
|
||||
- necessary
|
||||
- help wanted
|
||||
- RFC
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. If this
|
||||
is incorrect, please respond with an update. Thank you for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
42
.github/workflows/codeql-analysis.yml
vendored
Normal file
42
.github/workflows/codeql-analysis.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- current-release
|
||||
- "*LTS"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- current-release
|
||||
- "*LTS"
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
schedule:
|
||||
- cron: '25 16 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
if: github.event.pull_request.draft == false
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'python' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
34
.github/workflows/coverage.yml
vendored
Normal file
34
.github/workflows/coverage.yml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
name: Coverage check
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- current-release
|
||||
- "*LTS"
|
||||
tags:
|
||||
- "!*" # Do not execute on tags
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- current-release
|
||||
- "*LTS"
|
||||
|
||||
jobs:
|
||||
coverage:
|
||||
name: Check coverage
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Run coverage
|
||||
uses: sanic-org/simple-tox-action@v1
|
||||
with:
|
||||
python-version: "3.11"
|
||||
tox-env: coverage
|
||||
ignore-errors: true
|
||||
- name: Run Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./coverage.xml
|
||||
fail_ci_if_error: false
|
174
.github/workflows/publish-release.yml
vendored
Normal file
174
.github/workflows/publish-release.yml
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
name: Publish release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
IS_TEST: false
|
||||
DOCKER_ORG_NAME: sanicframework
|
||||
DOCKER_IMAGE_NAME: sanic
|
||||
DOCKER_BASE_IMAGE_NAME: sanic-build
|
||||
DOCKER_IMAGE_DOCKERFILE: ./docker/Dockerfile
|
||||
DOCKER_BASE_IMAGE_DOCKERFILE: ./docker/Dockerfile-base
|
||||
|
||||
jobs:
|
||||
generate_info:
|
||||
name: Generate info
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
docker-tags: ${{ steps.generate_docker_info.outputs.tags }}
|
||||
pypi-version: ${{ steps.parse_version_tag.outputs.pypi-version }}
|
||||
steps:
|
||||
- name: Parse version tag
|
||||
id: parse_version_tag
|
||||
env:
|
||||
TAG_NAME: ${{ github.event.release.tag_name }}
|
||||
run: |
|
||||
tag_name="${{ env.TAG_NAME }}"
|
||||
|
||||
if [[ ! "${tag_name}" =~ ^v([0-9]{2})\.([0-9]{1,2})\.([0-9]+)$ ]]; then
|
||||
echo "::error::Tag name must be in the format vYY.MM.MICRO"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
year_output="year=${BASH_REMATCH[1]}"
|
||||
month_output="month=${BASH_REMATCH[2]}"
|
||||
pypi_output="pypi-version=${tag_name#v}"
|
||||
|
||||
echo "${year_output}"
|
||||
echo "${month_output}"
|
||||
echo "${pypi_output}"
|
||||
|
||||
echo "${year_output}" >> $GITHUB_OUTPUT
|
||||
echo "${month_output}" >> $GITHUB_OUTPUT
|
||||
echo "${pypi_output}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get latest release
|
||||
id: get_latest_release
|
||||
run: |
|
||||
latest_tag=$(
|
||||
curl -L \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ github.token }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/releases/latest \
|
||||
| jq -r '.tag_name'
|
||||
)
|
||||
echo "latest_tag=$latest_tag" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate Docker info
|
||||
id: generate_docker_info
|
||||
run: |
|
||||
tag_year="${{ steps.parse_version_tag.outputs.year }}"
|
||||
tag_month="${{ steps.parse_version_tag.outputs.month }}"
|
||||
latest_tag="${{ steps.get_latest_release.outputs.latest_tag }}"
|
||||
tag="${{ github.event.release.tag_name }}"
|
||||
|
||||
tags="${tag_year}.${tag_month}"
|
||||
|
||||
if [[ "${tag_month}" == "12" ]]; then
|
||||
tags+=",LTS"
|
||||
echo "::notice::Tag ${tag} is LTS version"
|
||||
else
|
||||
echo "::notice::Tag ${tag} is not LTS version"
|
||||
fi
|
||||
|
||||
if [[ "${latest_tag}" == "${{ github.event.release.tag_name }}" ]]; then
|
||||
tags+=",latest"
|
||||
echo "::notice::Tag ${tag} is marked as latest"
|
||||
else
|
||||
echo "::notice::Tag ${tag} is not marked as latest"
|
||||
fi
|
||||
|
||||
tags_output="tags=${tags}"
|
||||
|
||||
echo "${tags_output}"
|
||||
echo "${tags_output}" >> $GITHUB_OUTPUT
|
||||
|
||||
publish_package:
|
||||
name: Build and publish package
|
||||
runs-on: ubuntu-latest
|
||||
needs: generate_info
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install build twine
|
||||
|
||||
- name: Update package version
|
||||
run: |
|
||||
echo "__version__ = \"${{ needs.generate_info.outputs.pypi-version }}\"" > sanic/__version__.py
|
||||
|
||||
- name: Build a binary wheel and a source tarball
|
||||
run: python -m build --sdist --wheel --outdir dist/ .
|
||||
|
||||
- name: Publish to PyPi 🚀
|
||||
run: twine upload --non-interactive --disable-progress-bar dist/*
|
||||
env:
|
||||
TWINE_USERNAME: __token__
|
||||
TWINE_PASSWORD: ${{ env.IS_TEST == 'true' && secrets.SANIC_TEST_PYPI_API_TOKEN || secrets.SANIC_PYPI_API_TOKEN }}
|
||||
TWINE_REPOSITORY: ${{ env.IS_TEST == 'true' && 'testpypi' || 'pypi' }}
|
||||
|
||||
publish_docker:
|
||||
name: Publish Docker / Python ${{ matrix.python-version }}
|
||||
needs: [generate_info, publish_package]
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
python-version: ["3.10", "3.11"]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_ACCESS_USER }}
|
||||
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
|
||||
- name: Build and push base image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
push: ${{ env.IS_TEST == 'false' }}
|
||||
file: ${{ env.DOCKER_BASE_IMAGE_DOCKERFILE }}
|
||||
tags: ${{ env.DOCKER_ORG_NAME }}/${{ env.DOCKER_BASE_IMAGE_NAME }}:${{ matrix.python-version }}
|
||||
build-args: |
|
||||
PYTHON_VERSION=${{ matrix.python-version }}
|
||||
|
||||
- name: Parse tags for this Python version
|
||||
id: parse_tags
|
||||
run: |
|
||||
IFS=',' read -ra tags <<< "${{ needs.generate_info.outputs.docker-tags }}"
|
||||
tag_args=""
|
||||
|
||||
for tag in "${tags[@]}"; do
|
||||
tag_args+=",${{ env.DOCKER_ORG_NAME }}/${{ env.DOCKER_IMAGE_NAME }}:${tag}-py${{ matrix.python-version }}"
|
||||
done
|
||||
|
||||
tag_args_output="tag_args=${tag_args:1}"
|
||||
|
||||
echo "${tag_args_output}"
|
||||
echo "${tag_args_output}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build and push Sanic image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
push: ${{ env.IS_TEST == 'false' }}
|
||||
file: ${{ env.DOCKER_IMAGE_DOCKERFILE }}
|
||||
tags: ${{ steps.parse_tags.outputs.tag_args }}
|
||||
build-args: |
|
||||
BASE_IMAGE_ORG=${{ env.DOCKER_ORG_NAME }}
|
||||
BASE_IMAGE_NAME=${{ env.DOCKER_BASE_IMAGE_NAME }}
|
||||
BASE_IMAGE_TAG=${{ matrix.python-version }}
|
||||
SANIC_PYPI_VERSION=${{ needs.generate_info.outputs.pypi-version }}
|
56
.github/workflows/tests.yml
vendored
Normal file
56
.github/workflows/tests.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- current-release
|
||||
- "*LTS"
|
||||
tags:
|
||||
- "!*"
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- current-release
|
||||
- "*LTS"
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
jobs:
|
||||
run_tests:
|
||||
name: "${{ matrix.config.platform == 'windows-latest' && 'Windows' || 'Linux' }} / Python ${{ matrix.config.python-version }} / tox -e ${{ matrix.config.tox-env }}"
|
||||
if: github.event.pull_request.draft == false
|
||||
runs-on: ${{ matrix.config.platform || 'ubuntu-latest' }}
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
config:
|
||||
- { python-version: "3.8", tox-env: security }
|
||||
- { python-version: "3.9", tox-env: security }
|
||||
- { python-version: "3.10", tox-env: security }
|
||||
- { python-version: "3.11", tox-env: security }
|
||||
- { python-version: "3.10", tox-env: lint }
|
||||
# - { python-version: "3.10", tox-env: docs }
|
||||
- { python-version: "3.8", tox-env: type-checking }
|
||||
- { python-version: "3.9", tox-env: type-checking }
|
||||
- { python-version: "3.10", tox-env: type-checking }
|
||||
- { python-version: "3.11", tox-env: type-checking }
|
||||
- { python-version: "3.8", tox-env: py38, max-attempts: 3 }
|
||||
- { python-version: "3.8", tox-env: py38-no-ext, max-attempts: 3 }
|
||||
- { python-version: "3.9", tox-env: py39, max-attempts: 3 }
|
||||
- { python-version: "3.9", tox-env: py39-no-ext, max-attempts: 3 }
|
||||
- { python-version: "3.10", tox-env: py310, max-attempts: 3 }
|
||||
- { python-version: "3.10", tox-env: py310-no-ext, max-attempts: 3 }
|
||||
- { python-version: "3.11", tox-env: py311, max-attempts: 3 }
|
||||
- { python-version: "3.11", tox-env: py311-no-ext, max-attempts: 3 }
|
||||
- { python-version: "3.8", tox-env: py38-no-ext, platform: windows-latest, ignore-errors: true }
|
||||
- { python-version: "3.9", tox-env: py39-no-ext, platform: windows-latest, ignore-errors: true }
|
||||
- { python-version: "3.10", tox-env: py310-no-ext, platform: windows-latest, ignore-errors: true }
|
||||
- { python-version: "3.11", tox-env: py310-no-ext, platform: windows-latest, ignore-errors: true }
|
||||
steps:
|
||||
- name: Run tests
|
||||
uses: sanic-org/simple-tox-action@v1
|
||||
with:
|
||||
python-version: ${{ matrix.config.python-version }}
|
||||
tox-env: ${{ matrix.config.tox-env }}
|
||||
max-attempts: ${{ matrix.config.max-attempts || 1 }}
|
||||
ignore-errors: ${{ matrix.config.ignore-errors || false }}
|
17
.gitignore
vendored
17
.gitignore
vendored
@ -1,11 +1,26 @@
|
||||
*~
|
||||
*.egg-info
|
||||
*.egg
|
||||
*.eggs
|
||||
*.pyc
|
||||
.coverage
|
||||
.coverage.*
|
||||
coverage
|
||||
coverage.xml
|
||||
.tox
|
||||
settings.py
|
||||
*.pyc
|
||||
.idea/*
|
||||
.cache/*
|
||||
.mypy_cache/
|
||||
.python-version
|
||||
docs/_build/
|
||||
docs/_api/
|
||||
build/*
|
||||
.DS_Store
|
||||
dist/*
|
||||
pip-wheel-metadata/
|
||||
.pytest_cache/*
|
||||
.venv/*
|
||||
venv/*
|
||||
.vscode/*
|
||||
guide/node_modules/
|
||||
|
18
.travis.yml
18
.travis.yml
@ -1,18 +0,0 @@
|
||||
language: python
|
||||
python:
|
||||
- '3.5'
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
- pip install -r requirements-dev.txt
|
||||
- python setup.py install
|
||||
- pip install flake8
|
||||
- pip install pytest
|
||||
before_script: flake8 sanic
|
||||
script: py.test -v tests
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: channelcat
|
||||
password:
|
||||
secure: jH4+Di2/qcBwWVhI5/3NYd/JuDDgf5/cF85h+oQnAjgwP6me3th9RS0PHL2gjKJrmyRgwrW7a3eSAityo5sQSlBloQCNrtCE30rkDiwtgoIxDW72NR/nE8nUkS9Utgy87eS+3B4NrO7ag4GTqO5ET8SQ4/MCiQwyUQATLXj2s2eTpQvqJeZG6YgoeFAOYvlR580yznXoOwldWlkiymJiWSdR/01lthtWCi40sYC/QoU7psODJ/tPcsqgQtQKyUVsci7mKvp3Y8ImkoO/POM01jYNsS9qLh5pKTNCEYxtyzC77whenCNHn7WReVidd56g1ADosbNo4yY/1D3VAvwjUnkQ0SzdBQfT7IIzccEuC0j1NXKPN97OX0a6XzyUMYJ1XiU3juTJOPxdYBPbsDM3imQiwrOh1faIf0HCgNTN+Lxe5l8obCH7kffNcVUhs2zI0+2t4MS5tjb/OVuYD/TFn+bM33DqzLctTOK/pGn6xefzZcdzb191LPo99Lof+4fo6jNUpb0UmcBu5ZJzxh0lGe8FPIK3UAG/hrYDDgjx8s8RtUJjcEUQz0659XffYx7DLlgHO7cWyfjrHD3yrLzDbYr5mAS4FR+4D917V7UL+on4SsKHN00UuMGPguqSYo/xYyPLnJU5XK0du4MIpsNMB8TtrJOIewOOfD32+AisPQ8=
|
||||
on:
|
||||
tags: true
|
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,17 +0,0 @@
|
||||
Version 0.1
|
||||
-----------
|
||||
- 0.1.5
|
||||
- Cookies
|
||||
- Blueprint listeners and ordering
|
||||
- Faster Router
|
||||
- Fix: Incomplete file reads on medium+ sized post requests
|
||||
- Breaking: after_start and before_stop now pass sanic as their first argument
|
||||
- 0.1.4
|
||||
- Multiprocessing
|
||||
- 0.1.3
|
||||
- Blueprint support
|
||||
- Faster Response processing
|
||||
- 0.1.1 - 0.1.2
|
||||
- Struggling to update pypi via CI
|
||||
- 0.1.0
|
||||
- Released to public
|
1159
CHANGELOG.rst
Normal file
1159
CHANGELOG.rst
Normal file
File diff suppressed because it is too large
Load Diff
74
CODE_OF_CONDUCT.md
Normal file
74
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,74 @@
|
||||
# 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, gender identity and expression, level of experience,
|
||||
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 adam@sanicframework.org. 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 [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
240
CONTRIBUTING.rst
Normal file
240
CONTRIBUTING.rst
Normal file
@ -0,0 +1,240 @@
|
||||
Thank you for your interest! Sanic is always looking for contributors. If you
|
||||
don't feel comfortable contributing code, adding docstrings to the source files,
|
||||
or helping with the `Sanic User Guide <https://github.com/sanic-org/sanic-guide>`_
|
||||
by providing documentation or implementation examples would be appreciated!
|
||||
|
||||
We are committed to providing a friendly, safe and welcoming environment for all,
|
||||
regardless of gender, sexual orientation, disability, ethnicity, religion,
|
||||
or similar personal characteristic.
|
||||
Our `code of conduct <https://github.com/sanic-org/sanic/blob/master/CONDUCT.md>`_ sets the standards for behavior.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
To develop on Sanic (and mainly to just run the tests) it is highly recommend to
|
||||
install from sources.
|
||||
|
||||
So assume you have already cloned the repo and are in the working directory with
|
||||
a virtual environment already set up, then run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install -e ".[dev]"
|
||||
|
||||
Dependency Changes
|
||||
------------------
|
||||
|
||||
``Sanic`` doesn't use ``requirements*.txt`` files to manage any kind of dependencies related to it in order to simplify the
|
||||
effort required in managing the dependencies. Please make sure you have read and understood the following section of
|
||||
the document that explains the way ``sanic`` manages dependencies inside the ``setup.py`` file.
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Dependency Type
|
||||
- Usage
|
||||
- Installation
|
||||
* - requirements
|
||||
- Bare minimum dependencies required for sanic to function
|
||||
- ``pip3 install -e .``
|
||||
* - tests_require / extras_require['test']
|
||||
- Dependencies required to run the Unit Tests for ``sanic``
|
||||
- ``pip3 install -e '.[test]'``
|
||||
* - extras_require['dev']
|
||||
- Additional Development requirements to add contributing
|
||||
- ``pip3 install -e '.[dev]'``
|
||||
* - extras_require['docs']
|
||||
- Dependencies required to enable building and enhancing sanic documentation
|
||||
- ``pip3 install -e '.[docs]'``
|
||||
|
||||
|
||||
Running all tests
|
||||
-----------------
|
||||
|
||||
To run the tests for Sanic it is recommended to use tox like so:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tox
|
||||
|
||||
See it's that simple!
|
||||
|
||||
``tox.ini`` contains different environments. Running ``tox`` without any arguments will
|
||||
run all unittests, perform lint and other checks.
|
||||
|
||||
Run unittests
|
||||
-------------
|
||||
|
||||
``tox`` environment -> ``[testenv]``
|
||||
|
||||
To execute only unittests, run ``tox`` with environment like so:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tox -e py37 -v -- tests/test_config.py
|
||||
# or
|
||||
tox -e py310 -v -- tests/test_config.py
|
||||
|
||||
Run lint checks
|
||||
---------------
|
||||
|
||||
``tox`` environment -> ``[testenv:lint]``
|
||||
|
||||
Permform ``flake8``\ , ``black`` and ``isort`` checks.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tox -e lint
|
||||
|
||||
Run type annotation checks
|
||||
--------------------------
|
||||
|
||||
``tox`` environment -> ``[testenv:type-checking]``
|
||||
|
||||
Permform ``mypy`` checks.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tox -e type-checking
|
||||
|
||||
Run other checks
|
||||
----------------
|
||||
|
||||
``tox`` environment -> ``[testenv:check]``
|
||||
|
||||
Perform other checks.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tox -e check
|
||||
|
||||
Run Static Analysis
|
||||
-------------------
|
||||
|
||||
``tox`` environment -> ``[testenv:security]``
|
||||
|
||||
Perform static analysis security scan
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tox -e security
|
||||
|
||||
Run Documentation sanity check
|
||||
------------------------------
|
||||
|
||||
``tox`` environment -> ``[testenv:docs]``
|
||||
|
||||
Perform sanity check on documentation
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
tox -e docs
|
||||
|
||||
|
||||
Code Style
|
||||
----------
|
||||
|
||||
To maintain the code consistency, Sanic uses following tools.
|
||||
|
||||
|
||||
#. `isort <https://github.com/timothycrosley/isort>`_
|
||||
#. `black <https://github.com/python/black>`_
|
||||
#. `flake8 <https://github.com/PyCQA/flake8>`_
|
||||
#. `slotscheck <https://github.com/ariebovenberg/slotscheck>`_
|
||||
|
||||
isort
|
||||
*****
|
||||
|
||||
``isort`` sorts Python imports. It divides imports into three
|
||||
categories sorted each in alphabetical order.
|
||||
|
||||
|
||||
#. built-in
|
||||
#. third-party
|
||||
#. project-specific
|
||||
|
||||
black
|
||||
*****
|
||||
|
||||
``black`` is a Python code formatter.
|
||||
|
||||
flake8
|
||||
******
|
||||
|
||||
``flake8`` is a Python style guide that wraps following tools into one.
|
||||
|
||||
|
||||
#. PyFlakes
|
||||
#. pycodestyle
|
||||
#. Ned Batchelder's McCabe script
|
||||
|
||||
slotscheck
|
||||
**********
|
||||
|
||||
``slotscheck`` ensures that there are no problems with ``__slots__``
|
||||
(e.g. overlaps, or missing slots in base classes).
|
||||
|
||||
``isort``\ , ``black``\ , ``flake8`` and ``slotscheck`` checks are performed during ``tox`` lint checks.
|
||||
|
||||
The **easiest** way to make your code conform is to run the following before committing.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make pretty
|
||||
|
||||
Refer `tox <https://tox.readthedocs.io/en/latest/index.html>`_ documentation for more details.
|
||||
|
||||
Pull requests
|
||||
-------------
|
||||
|
||||
So the pull request approval rules are pretty simple:
|
||||
|
||||
#. All pull requests must pass unit tests.
|
||||
#. All pull requests must be reviewed and approved by at least one current member of the Core Developer team.
|
||||
#. All pull requests must pass flake8 checks.
|
||||
#. All pull requests must match ``isort`` and ``black`` requirements.
|
||||
#. All pull requests must be **PROPERLY** type annotated, unless exemption is given.
|
||||
#. All pull requests must be consistent with the existing code.
|
||||
#. If you decide to remove/change anything from any common interface a deprecation message should accompany it in accordance with our `deprecation policy <https://sanicframework.org/en/guide/project/policies.html#deprecation>`_.
|
||||
#. If you implement a new feature you should have at least one unit test to accompany it.
|
||||
#. An example must be one of the following:
|
||||
|
||||
* Example of how to use Sanic
|
||||
* Example of how to use Sanic extensions
|
||||
* Example of how to use Sanic and asynchronous library
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Sanic's API documentation is built using `sphinx <http://www.sphinx-doc.org/en/1.5.1/>`_ with module references
|
||||
automatically generated using ``sphinx-apidoc``.
|
||||
|
||||
The User Guide is in the `sanic-guide <https://github.com/sanic-org/sanic-guide>`_ repository.
|
||||
|
||||
To generate the documentation from scratch:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sphinx-apidoc -fo docs/_api/ sanic
|
||||
sphinx-build -b html docs docs/_build
|
||||
|
||||
# There is a simple make command provided to ease the work required in generating
|
||||
# the documentation
|
||||
make docs
|
||||
|
||||
The HTML documentation will be created in the ``docs/_build`` folder.
|
||||
|
||||
You can run the following to have a live development server with the API documents
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make docs-serve
|
||||
|
||||
Refer to the User Guide repo for documentation on how to contribute there.
|
||||
|
||||
.. warning::
|
||||
One of the main goals of Sanic is speed. Code that lowers the performance of
|
||||
Sanic without significant gains in usability, security, or features may not be
|
||||
merged. Please don't let this intimidate you! If you have any concerns about an
|
||||
idea, open an issue for discussion and help.
|
4
LICENSE
4
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) [year] [fullname]
|
||||
Copyright (c) 2016-present Sanic Community
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
|
15
MANIFEST.in
Normal file
15
MANIFEST.in
Normal file
@ -0,0 +1,15 @@
|
||||
# Non Code related contents
|
||||
include LICENSE
|
||||
include README.rst
|
||||
include pyproject.toml
|
||||
|
||||
# Setup
|
||||
include setup.py
|
||||
include Makefile
|
||||
|
||||
# Tests
|
||||
include .coveragerc
|
||||
graft tests
|
||||
|
||||
global-exclude __pycache__
|
||||
global-exclude *.py[co]
|
105
Makefile
Normal file
105
Makefile
Normal file
@ -0,0 +1,105 @@
|
||||
.PHONY: help test test-coverage install docker-test black fix-import beautify
|
||||
|
||||
.DEFAULT: help
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo "test"
|
||||
@echo " Run Sanic Unit Tests"
|
||||
@echo "test-coverage"
|
||||
@echo " Run Sanic Unit Tests with Coverage"
|
||||
@echo "install"
|
||||
@echo " Install Sanic"
|
||||
@echo "docker-test"
|
||||
@echo " Run Sanic Unit Tests using Docker"
|
||||
@echo "black"
|
||||
@echo " Analyze and fix linting issues using Black"
|
||||
@echo "fix-import"
|
||||
@echo " Analyze and fix import order using isort"
|
||||
@echo "beautify [sort_imports=1] [include_tests=1]"
|
||||
@echo " Analyze and fix linting issue using black and optionally fix import sort using isort"
|
||||
@echo ""
|
||||
@echo "docs"
|
||||
@echo " Generate Sanic documentation"
|
||||
@echo ""
|
||||
@echo "clean-docs"
|
||||
@echo " Clean Sanic documentation"
|
||||
@echo ""
|
||||
@echo "docs-test"
|
||||
@echo " Test Sanic Documentation for errors"
|
||||
@echo ""
|
||||
@echo "changelog"
|
||||
@echo " Generate changelog for Sanic to prepare for new release"
|
||||
@echo ""
|
||||
@echo "release"
|
||||
@echo " Prepare Sanic for a new changes by version bump and changelog"
|
||||
@echo ""
|
||||
|
||||
|
||||
clean:
|
||||
find . ! -path "./.eggs/*" -name "*.pyc" -exec rm {} \;
|
||||
find . ! -path "./.eggs/*" -name "*.pyo" -exec rm {} \;
|
||||
find . ! -path "./.eggs/*" -name ".coverage" -exec rm {} \;
|
||||
rm -rf build/* > /dev/null 2>&1
|
||||
rm -rf dist/* > /dev/null 2>&1
|
||||
|
||||
test: clean
|
||||
python setup.py test
|
||||
|
||||
test-coverage: clean
|
||||
python setup.py test --pytest-args="--cov sanic --cov-report term --cov-append "
|
||||
|
||||
view-coverage:
|
||||
sanic ./coverage --simple
|
||||
|
||||
install:
|
||||
python setup.py install
|
||||
|
||||
docker-test: clean
|
||||
docker build -t sanic/test-image -f docker/Dockerfile .
|
||||
docker run -t sanic/test-image tox
|
||||
|
||||
beautify: black
|
||||
ifdef sort_imports
|
||||
ifdef include_tests
|
||||
$(warning It is suggested that you do not run sort import on tests)
|
||||
isort -rc sanic tests
|
||||
else
|
||||
$(info Sorting Imports)
|
||||
isort -rc sanic tests
|
||||
endif
|
||||
endif
|
||||
|
||||
black:
|
||||
black sanic tests
|
||||
|
||||
isort:
|
||||
isort sanic tests
|
||||
|
||||
pretty: black isort
|
||||
|
||||
docs-clean:
|
||||
cd docs && make clean
|
||||
|
||||
docs: docs-clean
|
||||
cd docs && make html
|
||||
|
||||
docs-test: docs-clean
|
||||
cd docs && make dummy
|
||||
|
||||
docs-serve:
|
||||
sphinx-autobuild docs docs/_build/html --port 9999 --watch ./
|
||||
|
||||
changelog:
|
||||
python scripts/changelog.py
|
||||
|
||||
guide-serve:
|
||||
cd guide && sanic server:app -r -R ./content -R ./style
|
||||
|
||||
release:
|
||||
ifdef version
|
||||
python scripts/release.py --release-version ${version} --generate-changelog
|
||||
else
|
||||
python scripts/release.py --generate-changelog
|
||||
endif
|
||||
|
87
README.md
87
README.md
@ -1,87 +0,0 @@
|
||||
# Sanic
|
||||
|
||||
[](https://travis-ci.org/channelcat/sanic)
|
||||
[](https://pypi.python.org/pypi/sanic/)
|
||||
[](https://pypi.python.org/pypi/sanic/)
|
||||
|
||||
Sanic is a Flask-like Python 3.5+ web server that's written to go fast. It's based on the work done by the amazing folks at magicstack, and was inspired by this article: https://magic.io/blog/uvloop-blazing-fast-python-networking/.
|
||||
|
||||
On top of being Flask-like, Sanic supports async request handlers. This means you can use the new shiny async/await syntax from Python 3.5, making your code non-blocking and speedy.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
All tests were run on an AWS medium instance running ubuntu, using 1 process. Each script delivered a small JSON response and was tested with wrk using 100 connections. Pypy was tested for Falcon and Flask but did not speed up requests.
|
||||
|
||||
|
||||
|
||||
| Server | Implementation | Requests/sec | Avg Latency |
|
||||
| ------- | ------------------- | ------------:| -----------:|
|
||||
| Sanic | Python 3.5 + uvloop | 33,342 | 2.96ms |
|
||||
| Wheezy | gunicorn + meinheld | 20,244 | 4.94ms |
|
||||
| Falcon | gunicorn + meinheld | 18,972 | 5.27ms |
|
||||
| Bottle | gunicorn + meinheld | 13,596 | 7.36ms |
|
||||
| Flask | gunicorn + meinheld | 4,988 | 20.08ms |
|
||||
| Kyoukai | Python 3.5 + uvloop | 3,889 | 27.44ms |
|
||||
| Aiohttp | Python 3.5 + uvloop | 2,979 | 33.42ms |
|
||||
| Tornado | Python 3.5 | 2,138 | 46.66ms |
|
||||
|
||||
## Hello World
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
app = Sanic(__name__)
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
return json({ "hello": "world" })
|
||||
|
||||
app.run(host="0.0.0.0", port=8000)
|
||||
```
|
||||
|
||||
## Installation
|
||||
* `python -m pip install sanic`
|
||||
|
||||
## Documentation
|
||||
* [Getting started](docs/getting_started.md)
|
||||
* [Request Data](docs/request_data.md)
|
||||
* [Routing](docs/routing.md)
|
||||
* [Middleware](docs/middleware.md)
|
||||
* [Exceptions](docs/exceptions.md)
|
||||
* [Blueprints](docs/blueprints.md)
|
||||
* [Cookies](docs/cookies.md)
|
||||
* [Deploying](docs/deploying.md)
|
||||
* [Contributing](docs/contributing.md)
|
||||
* [License](LICENSE)
|
||||
|
||||
## TODO:
|
||||
* Streamed file processing
|
||||
* File output
|
||||
* Examples of integrations with 3rd-party modules
|
||||
* RESTful router
|
||||
|
||||
## Limitations:
|
||||
* No wheels for uvloop and httptools on Windows :(
|
||||
|
||||
## Final Thoughts:
|
||||
|
||||
▄▄▄▄▄
|
||||
▀▀▀██████▄▄▄ _______________
|
||||
▄▄▄▄▄ █████████▄ / \
|
||||
▀▀▀▀█████▌ ▀▐▄ ▀▐█ | Gotta go fast! |
|
||||
▀▀█████▄▄ ▀██████▄██ | _________________/
|
||||
▀▄▄▄▄▄ ▀▀█▄▀█════█▀ |/
|
||||
▀▀▀▄ ▀▀███ ▀ ▄▄
|
||||
▄███▀▀██▄████████▄ ▄▀▀▀▀▀▀█▌
|
||||
██▀▄▄▄██▀▄███▀ ▀▀████ ▄██
|
||||
▄▀▀▀▄██▄▀▀▌████▒▒▒▒▒▒███ ▌▄▄▀
|
||||
▌ ▐▀████▐███▒▒▒▒▒▐██▌
|
||||
▀▄▄▄▄▀ ▀▀████▒▒▒▒▄██▀
|
||||
▀▀█████████▀
|
||||
▄▄██▀██████▀█
|
||||
▄██▀ ▀▀▀ █
|
||||
▄█ ▐▌
|
||||
▄▄▄▄█▌ ▀█▄▄▄▄▀▀▄
|
||||
▌ ▐ ▀▀▄▄▄▀
|
||||
▀▀▄▄▀
|
163
README.rst
Normal file
163
README.rst
Normal file
@ -0,0 +1,163 @@
|
||||
.. image:: https://raw.githubusercontent.com/sanic-org/sanic-assets/master/png/sanic-framework-logo-400x97.png
|
||||
:alt: Sanic | Build fast. Run fast.
|
||||
|
||||
Sanic | Build fast. Run fast.
|
||||
=============================
|
||||
|
||||
.. start-badges
|
||||
|
||||
.. list-table::
|
||||
:widths: 15 85
|
||||
:stub-columns: 1
|
||||
|
||||
* - Build
|
||||
- | |Tests|
|
||||
* - Docs
|
||||
- | |UserGuide| |Documentation|
|
||||
* - Package
|
||||
- | |PyPI| |PyPI version| |Wheel| |Supported implementations| |Code style black|
|
||||
* - Support
|
||||
- | |Forums| |Discord| |Awesome|
|
||||
* - Stats
|
||||
- | |Monthly Downloads| |Weekly Downloads| |Conda downloads|
|
||||
|
||||
.. |UserGuide| image:: https://img.shields.io/badge/user%20guide-sanic-ff0068
|
||||
:target: https://sanicframework.org/
|
||||
.. |Forums| image:: https://img.shields.io/badge/forums-community-ff0068.svg
|
||||
:target: https://community.sanicframework.org/
|
||||
.. |Discord| image:: https://img.shields.io/discord/812221182594121728?logo=discord
|
||||
:target: https://discord.gg/FARQzAEMAA
|
||||
.. |Tests| image:: https://github.com/sanic-org/sanic/actions/workflows/tests.yml/badge.svg?branch=main
|
||||
:target: https://github.com/sanic-org/sanic/actions/workflows/tests.yml
|
||||
.. |Documentation| image:: https://readthedocs.org/projects/sanic/badge/?version=latest
|
||||
:target: http://sanic.readthedocs.io/en/latest/?badge=latest
|
||||
.. |PyPI| image:: https://img.shields.io/pypi/v/sanic.svg
|
||||
:target: https://pypi.python.org/pypi/sanic/
|
||||
.. |PyPI version| image:: https://img.shields.io/pypi/pyversions/sanic.svg
|
||||
:target: https://pypi.python.org/pypi/sanic/
|
||||
.. |Code style black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/ambv/black
|
||||
.. |Wheel| image:: https://img.shields.io/pypi/wheel/sanic.svg
|
||||
:alt: PyPI Wheel
|
||||
:target: https://pypi.python.org/pypi/sanic
|
||||
.. |Supported implementations| image:: https://img.shields.io/pypi/implementation/sanic.svg
|
||||
:alt: Supported implementations
|
||||
:target: https://pypi.python.org/pypi/sanic
|
||||
.. |Awesome| image:: https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg
|
||||
:alt: Awesome Sanic List
|
||||
:target: https://github.com/mekicha/awesome-sanic
|
||||
.. |Monthly Downloads| image:: https://img.shields.io/pypi/dm/sanic.svg
|
||||
:alt: Downloads
|
||||
:target: https://pepy.tech/project/sanic
|
||||
.. |Weekly Downloads| image:: https://img.shields.io/pypi/dw/sanic.svg
|
||||
:alt: Downloads
|
||||
:target: https://pepy.tech/project/sanic
|
||||
.. |Conda downloads| image:: https://img.shields.io/conda/dn/conda-forge/sanic.svg
|
||||
:alt: Downloads
|
||||
:target: https://anaconda.org/conda-forge/sanic
|
||||
.. |Linode| image:: https://www.linode.com/wp-content/uploads/2021/01/Linode-Logo-Black.svg
|
||||
:alt: Linode
|
||||
:target: https://www.linode.com
|
||||
:width: 200px
|
||||
|
||||
.. end-badges
|
||||
|
||||
Sanic is a **Python 3.8+** web server and web framework that's written to go fast. It allows the usage of the ``async/await`` syntax added in Python 3.5, which makes your code non-blocking and speedy.
|
||||
|
||||
Sanic is also ASGI compliant, so you can deploy it with an `alternative ASGI webserver <https://sanicframework.org/en/guide/deployment/running.html#asgi>`_.
|
||||
|
||||
`Source code on GitHub <https://github.com/sanic-org/sanic/>`_ | `Help and discussion board <https://community.sanicframework.org/>`_ | `User Guide <https://sanicframework.org>`_ | `Chat on Discord <https://discord.gg/FARQzAEMAA>`_
|
||||
|
||||
The project is maintained by the community, for the community. **Contributions are welcome!**
|
||||
|
||||
The goal of the project is to provide a simple way to get up and running a highly performant HTTP server that is easy to build, to expand, and ultimately to scale.
|
||||
|
||||
Sponsor
|
||||
-------
|
||||
|
||||
Check out `open collective <https://opencollective.com/sanic-org>`_ to learn more about helping to fund Sanic.
|
||||
|
||||
Thanks to `Linode <https://www.linode.com>`_ for their contribution towards the development and community of Sanic.
|
||||
|
||||
|Linode|
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
``pip3 install sanic``
|
||||
|
||||
Sanic makes use of ``uvloop`` and ``ujson`` to help with performance. If you do not want to use those packages, simply add an environmental variable ``SANIC_NO_UVLOOP=true`` or ``SANIC_NO_UJSON=true`` at install time.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
$ export SANIC_NO_UVLOOP=true
|
||||
$ export SANIC_NO_UJSON=true
|
||||
$ pip3 install --no-binary :all: sanic
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
If you are running on a clean install of Fedora 28 or above, please make sure you have the ``redhat-rpm-config`` package installed in case if you want to
|
||||
use ``sanic`` with ``ujson`` dependency.
|
||||
|
||||
|
||||
Hello World Example
|
||||
-------------------
|
||||
|
||||
.. code:: python
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
app = Sanic("my-hello-world-app")
|
||||
|
||||
@app.route('/')
|
||||
async def test(request):
|
||||
return json({'hello': 'world'})
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
|
||||
Sanic can now be easily run using ``sanic hello.app``.
|
||||
|
||||
.. code::
|
||||
|
||||
[2018-12-30 11:37:41 +0200] [13564] [INFO] Goin' Fast @ http://127.0.0.1:8000
|
||||
[2018-12-30 11:37:41 +0200] [13564] [INFO] Starting worker [13564]
|
||||
|
||||
And, we can verify it is working: ``curl localhost:8000 -i``
|
||||
|
||||
.. code::
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Connection: keep-alive
|
||||
Keep-Alive: 5
|
||||
Content-Length: 17
|
||||
Content-Type: application/json
|
||||
|
||||
{"hello":"world"}
|
||||
|
||||
**Now, let's go build something fast!**
|
||||
|
||||
Minimum Python version is 3.8. If you need Python 3.7 support, please use v22.12LTS.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
`User Guide <https://sanic.dev>`__ and `API Documentation <http://sanic.readthedocs.io/>`__.
|
||||
|
||||
Changelog
|
||||
---------
|
||||
|
||||
`Release Changelogs <https://sanic.readthedocs.io/en/stable/sanic/changelog.html>`__.
|
||||
|
||||
|
||||
Questions and Discussion
|
||||
------------------------
|
||||
|
||||
`Ask a question or join the conversation <https://community.sanicframework.org/>`__.
|
||||
|
||||
Contribution
|
||||
------------
|
||||
|
||||
We are always happy to have new contributions. We have `marked issues good for anyone looking to get started <https://github.com/sanic-org/sanic/issues?q=is%3Aopen+is%3Aissue+label%3Abeginner>`_, and welcome `questions on the forums <https://community.sanicframework.org/>`_. Please take a look at our `Contribution guidelines <https://github.com/sanic-org/sanic/blob/master/CONTRIBUTING.rst>`_.
|
45
SECURITY.md
Normal file
45
SECURITY.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Sanic releases long term support release once a year in December. LTS releases receive bug and security updates for **24 months**. Interim releases throughout the year occur every three months, and are supported until the subsequent interim release.
|
||||
|
||||
|
||||
| Version | LTS | Supported |
|
||||
| ------- | ------------- | ----------------------- |
|
||||
| 22.12 | until 2024-12 | :white_check_mark: |
|
||||
| 22.9 | | :x: |
|
||||
| 22.6 | | :x: |
|
||||
| 22.3 | | :x: |
|
||||
| 21.12 | until 2023-12 | :ballot_box_with_check: |
|
||||
| 21.9 | | :x: |
|
||||
| 21.6 | | :x: |
|
||||
| 21.3 | | :x: |
|
||||
| 20.12 | | :x: |
|
||||
| 20.9 | | :x: |
|
||||
| 20.6 | | :x: |
|
||||
| 20.3 | | :x: |
|
||||
| 19.12 | | :x: |
|
||||
| 19.9 | | :x: |
|
||||
| 19.6 | | :x: |
|
||||
| 19.3 | | :x: |
|
||||
| 18.12 | | :x: |
|
||||
| 0.8.3 | | :x: |
|
||||
| 0.7.0 | | :x: |
|
||||
| 0.6.0 | | :x: |
|
||||
| 0.5.4 | | :x: |
|
||||
| 0.4.1 | | :x: |
|
||||
| 0.3.1 | | :x: |
|
||||
| 0.2.0 | | :x: |
|
||||
| 0.1.9 | | :x: |
|
||||
|
||||
:ballot_box_with_check: = security/bug fixes
|
||||
:white_check_mark: = full support
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you discover a security vulnerability, we ask that you **do not** create an issue on GitHub. Instead, please [send a message to the core-devs](https://community.sanicframework.org/g/core-devs) on the community forums. Once logged in, you can send a message to the core-devs by clicking the message button.
|
||||
|
||||
Alternatively, you can send a private message to Adam Hopkins on Discord. Find him on the [Sanic discord server](https://discord.gg/FARQzAEMAA).
|
||||
|
||||
This will help to not publicize the issue until the team can address it and resolve it.
|
2
changelogs/.gitignore
vendored
Normal file
2
changelogs/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Except this file
|
||||
!.gitignore
|
1
changelogs/1892.removal.rst
Normal file
1
changelogs/1892.removal.rst
Normal file
@ -0,0 +1 @@
|
||||
Remove [version] section.
|
3
changelogs/1904.feature.rst
Normal file
3
changelogs/1904.feature.rst
Normal file
@ -0,0 +1,3 @@
|
||||
Adds WEBSOCKET_PING_TIMEOUT and WEBSOCKET_PING_INTERVAL configuration values
|
||||
|
||||
Allows setting the ping_interval and ping_timeout arguments when initializing `WebSocketCommonProtocol`.
|
1
changelogs/1970.misc.rst
Normal file
1
changelogs/1970.misc.rst
Normal file
@ -0,0 +1 @@
|
||||
Adds py.typed file to expose type information to other packages.
|
28
codecov.yml
Normal file
28
codecov.yml
Normal file
@ -0,0 +1,28 @@
|
||||
coverage:
|
||||
status:
|
||||
patch:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 0.75
|
||||
informational: true
|
||||
project:
|
||||
default:
|
||||
target: auto
|
||||
threshold: 0.5
|
||||
precision: 3
|
||||
codecov:
|
||||
require_ci_to_pass: false
|
||||
ignore:
|
||||
- "sanic/__main__.py"
|
||||
- "sanic/compat.py"
|
||||
- "sanic/simple.py"
|
||||
- "sanic/utils.py"
|
||||
- "sanic/cli/"
|
||||
- "sanic/pages/"
|
||||
- ".github/"
|
||||
- "changelogs/"
|
||||
- "docker/"
|
||||
- "docs/"
|
||||
- "examples/"
|
||||
- "scripts/"
|
||||
- "tests/"
|
13
docker/Dockerfile
Normal file
13
docker/Dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
ARG BASE_IMAGE_ORG
|
||||
ARG BASE_IMAGE_NAME
|
||||
ARG BASE_IMAGE_TAG
|
||||
|
||||
FROM ${BASE_IMAGE_ORG}/${BASE_IMAGE_NAME}:${BASE_IMAGE_TAG}
|
||||
|
||||
RUN apk update
|
||||
RUN update-ca-certificates
|
||||
|
||||
ARG SANIC_PYPI_VERSION
|
||||
|
||||
RUN pip install -U pip && pip install sanic==${SANIC_PYPI_VERSION}
|
||||
RUN apk del build-base
|
9
docker/Dockerfile-base
Normal file
9
docker/Dockerfile-base
Normal file
@ -0,0 +1,9 @@
|
||||
ARG PYTHON_VERSION
|
||||
|
||||
FROM python:${PYTHON_VERSION}-alpine
|
||||
RUN apk update
|
||||
RUN apk add --no-cache --update build-base \
|
||||
ca-certificates \
|
||||
openssl
|
||||
RUN update-ca-certificates
|
||||
RUN rm -rf /var/cache/apk/*
|
225
docs/Makefile
Normal file
225
docs/Makefile
Normal file
@ -0,0 +1,225 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " applehelp to make an Apple Help Book"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " epub3 to make an epub3"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " xml to make Docutils-native XML files"
|
||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
@echo " coverage to run coverage check of the documentation (if enabled)"
|
||||
@echo " dummy to check syntax errors of document sources"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)/*
|
||||
|
||||
.PHONY: html
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
.PHONY: dirhtml
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
.PHONY: singlehtml
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
.PHONY: pickle
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
.PHONY: json
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
.PHONY: htmlhelp
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
.PHONY: qthelp
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/aiographite.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/aiographite.qhc"
|
||||
|
||||
.PHONY: applehelp
|
||||
applehelp:
|
||||
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
|
||||
@echo
|
||||
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
|
||||
@echo "N.B. You won't be able to view it unless you put it in" \
|
||||
"~/Library/Documentation/Help or install it in your application" \
|
||||
"bundle."
|
||||
|
||||
.PHONY: devhelp
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/aiographite"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/aiographite"
|
||||
@echo "# devhelp"
|
||||
|
||||
.PHONY: epub
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
.PHONY: epub3
|
||||
epub3:
|
||||
$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
|
||||
@echo
|
||||
@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
|
||||
|
||||
.PHONY: latex
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
.PHONY: latexpdf
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
.PHONY: latexpdfja
|
||||
latexpdfja:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
.PHONY: text
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
.PHONY: man
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
.PHONY: texinfo
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
.PHONY: info
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
.PHONY: gettext
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
.PHONY: changes
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
.PHONY: linkcheck
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
.PHONY: doctest
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
|
||||
@echo "Testing of coverage in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/coverage/python.txt."
|
||||
|
||||
.PHONY: xml
|
||||
xml:
|
||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||
@echo
|
||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||
|
||||
.PHONY: pseudoxml
|
||||
pseudoxml:
|
||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||
@echo
|
||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||
|
||||
.PHONY: dummy
|
||||
dummy:
|
||||
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
|
||||
@echo
|
||||
@echo "Build finished. Dummy builder generates no files."
|
0
docs/_static/.gitkeep
vendored
Normal file
0
docs/_static/.gitkeep
vendored
Normal file
13
docs/_static/custom.css
vendored
Normal file
13
docs/_static/custom.css
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
.wy-side-nav-search,
|
||||
.wy-nav-top {
|
||||
background: #444444;
|
||||
}
|
||||
|
||||
#changelog section {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
#changelog section h2,
|
||||
#changelog section h3 {
|
||||
margin-left: -3rem;
|
||||
}
|
BIN
docs/_static/sanic-framework-logo-white-400x97.png
vendored
Normal file
BIN
docs/_static/sanic-framework-logo-white-400x97.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -1,105 +0,0 @@
|
||||
# Blueprints
|
||||
|
||||
Blueprints are objects that can be used for sub-routing within an application.
|
||||
Instead of adding routes to the application object, blueprints define similar
|
||||
methods for adding routes, which are then registered with the application in a
|
||||
flexible and pluggable manner.
|
||||
|
||||
## Why?
|
||||
|
||||
Blueprints are especially useful for larger applications, where your application
|
||||
logic can be broken down into several groups or areas of responsibility.
|
||||
|
||||
It is also useful for API versioning, where one blueprint may point at
|
||||
`/v1/<routes>`, and another pointing at `/v2/<routes>`.
|
||||
|
||||
|
||||
## My First Blueprint
|
||||
|
||||
The following shows a very simple blueprint that registers a handler-function at
|
||||
the root `/` of your application.
|
||||
|
||||
Suppose you save this file as `my_blueprint.py`, this can be imported in your
|
||||
main application later.
|
||||
|
||||
```python
|
||||
from sanic.response import json
|
||||
from sanic import Blueprint
|
||||
|
||||
bp = Blueprint('my_blueprint')
|
||||
|
||||
@bp.route('/')
|
||||
async def bp_root(request):
|
||||
return json({'my': 'blueprint'})
|
||||
|
||||
```
|
||||
|
||||
## Registering Blueprints
|
||||
Blueprints must be registered with the application.
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from my_blueprint import bp
|
||||
|
||||
app = Sanic(__name__)
|
||||
app.register_blueprint(bp)
|
||||
|
||||
app.run(host='0.0.0.0', port=8000, debug=True)
|
||||
```
|
||||
|
||||
This will add the blueprint to the application and register any routes defined
|
||||
by that blueprint.
|
||||
In this example, the registered routes in the `app.router` will look like:
|
||||
|
||||
```python
|
||||
[Route(handler=<function bp_root at 0x7f908382f9d8>, methods=None, pattern=re.compile('^/$'), parameters=[])]
|
||||
```
|
||||
|
||||
## Middleware
|
||||
Using blueprints allows you to also register middleware globally.
|
||||
|
||||
```python
|
||||
@bp.middleware
|
||||
async def halt_request(request):
|
||||
print("I am a spy")
|
||||
|
||||
@bp.middleware('request')
|
||||
async def halt_request(request):
|
||||
return text('I halted the request')
|
||||
|
||||
@bp.middleware('response')
|
||||
async def halt_response(request, response):
|
||||
return text('I halted the response')
|
||||
```
|
||||
|
||||
## Exceptions
|
||||
Exceptions can also be applied exclusively to blueprints globally.
|
||||
|
||||
```python
|
||||
@bp.exception(NotFound)
|
||||
def ignore_404s(request, exception):
|
||||
return text("Yep, I totally found the page: {}".format(request.url))
|
||||
```
|
||||
|
||||
## Start and Stop
|
||||
Blueprints and run functions during the start and stop process of the server.
|
||||
If running in multiprocessor mode (more than 1 worker), these are triggered after the workers fork
|
||||
Available events are:
|
||||
|
||||
* before_server_start - Executed before the server begins to accept connections
|
||||
* after_server_start - Executed after the server begins to accept connections
|
||||
* before_server_stop - Executed before the server stops accepting connections
|
||||
* after_server_stop - Executed after the server is stopped and all requests are complete
|
||||
|
||||
```python
|
||||
bp = Blueprint('my_blueprint')
|
||||
|
||||
@bp.listen('before_server_start')
|
||||
async def setup_connection():
|
||||
global database
|
||||
database = mysql.connect(host='127.0.0.1'...)
|
||||
|
||||
@bp.listen('after_server_stop')
|
||||
async def close_connection():
|
||||
await database.close()
|
||||
```
|
169
docs/conf.py
Normal file
169
docs/conf.py
Normal file
@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Sanic documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun Dec 25 18:07:21 2016.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
# Add support for auto-doc
|
||||
|
||||
|
||||
# Ensure that sanic is present in the path, to allow sphinx-apidoc to
|
||||
# autogenerate documentation from docstrings
|
||||
root_directory = os.path.dirname(os.getcwd())
|
||||
sys.path.insert(0, root_directory)
|
||||
|
||||
import sanic
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
extensions = [
|
||||
"sphinx.ext.autodoc",
|
||||
"m2r2",
|
||||
"enum_tools.autoenum",
|
||||
]
|
||||
|
||||
templates_path = ["_templates"]
|
||||
|
||||
# Enable support for both Restructured Text and Markdown
|
||||
source_suffix = [".rst", ".md"]
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = "Sanic"
|
||||
copyright = "2021, Sanic Community Organization"
|
||||
author = "Sanic Community Organization"
|
||||
|
||||
html_logo = "./_static/sanic-framework-logo-white-400x97.png"
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = sanic.__version__
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = sanic.__version__
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = "en"
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
#
|
||||
# modules.rst is generated by sphinx-apidoc but is unused. This suppresses
|
||||
# a warning about it.
|
||||
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "modules.rst"]
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = "sphinx"
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ["_static"]
|
||||
html_css_files = ["custom.css"]
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = "Sanicdoc"
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(
|
||||
master_doc,
|
||||
"Sanic.tex",
|
||||
"Sanic Documentation",
|
||||
"Sanic contributors",
|
||||
"manual",
|
||||
),
|
||||
]
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [(master_doc, "sanic", "Sanic Documentation", [author], 1)]
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(
|
||||
master_doc,
|
||||
"Sanic",
|
||||
"Sanic Documentation",
|
||||
author,
|
||||
"Sanic",
|
||||
"One line description of project.",
|
||||
"Miscellaneous",
|
||||
),
|
||||
]
|
||||
|
||||
# -- Options for Epub output ----------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
epub_author = author
|
||||
epub_publisher = author
|
||||
epub_copyright = copyright
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ["search.html"]
|
||||
|
||||
# -- Custom Settings -------------------------------------------------------
|
||||
|
||||
suppress_warnings = ["image.nonlocal_uri"]
|
||||
|
||||
|
||||
autodoc_typehints = "description"
|
||||
autodoc_default_options = {
|
||||
"member-order": "groupwise",
|
||||
}
|
||||
|
||||
html_theme_options = {
|
||||
"style_external_links": False,
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
# How to contribute to Sanic
|
||||
|
||||
Thank you for your interest!
|
||||
|
||||
## Running tests
|
||||
* `python -m pip install pytest`
|
||||
* `python -m pytest tests`
|
||||
|
||||
## Warning
|
||||
One of the main goals of Sanic is speed. Code that lowers the performance of Sanic without significant gains in usability, security, or features may not be merged.
|
@ -1,50 +0,0 @@
|
||||
# Cookies
|
||||
|
||||
## Request
|
||||
|
||||
Request cookies can be accessed via the request.cookie dictionary
|
||||
|
||||
### Example
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.response import text
|
||||
|
||||
@app.route("/cookie")
|
||||
async def test(request):
|
||||
test_cookie = request.cookies.get('test')
|
||||
return text("Test cookie set to: {}".format(test_cookie))
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
Response cookies can be set like dictionary values and
|
||||
have the following parameters available:
|
||||
|
||||
* expires - datetime - Time for cookie to expire on the client's browser
|
||||
* path - string - The Path attribute specifies the subset of URLs to
|
||||
which this cookie applies
|
||||
* comment - string - Cookie comment (metadata)
|
||||
* domain - string - Specifies the domain for which the
|
||||
cookie is valid. An explicitly specified domain must always
|
||||
start with a dot.
|
||||
* max-age - number - Number of seconds the cookie should live for
|
||||
* secure - boolean - Specifies whether the cookie will only be sent via
|
||||
HTTPS
|
||||
* httponly - boolean - Specifies whether the cookie cannot be read
|
||||
by javascript
|
||||
|
||||
### Example
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.response import text
|
||||
|
||||
@app.route("/cookie")
|
||||
async def test(request):
|
||||
response = text("There's a cookie up in this response")
|
||||
response.cookies['test'] = 'It worked!'
|
||||
response.cookies['test']['domain'] = '.gotta-go-fast.com'
|
||||
response.cookies['test']['httponly'] = True
|
||||
return response
|
||||
```
|
@ -1,35 +0,0 @@
|
||||
# Deploying
|
||||
|
||||
When it comes to deploying Sanic, there's not much to it, but there are
|
||||
a few things to take note of.
|
||||
|
||||
## Workers
|
||||
|
||||
By default, Sanic listens in the main process using only 1 CPU core.
|
||||
To crank up the juice, just specify the number of workers in the run
|
||||
arguments like so:
|
||||
|
||||
```python
|
||||
app.run(host='0.0.0.0', port=1337, workers=4)
|
||||
```
|
||||
|
||||
Sanic will automatically spin up multiple processes and route
|
||||
traffic between them. We recommend as many workers as you have
|
||||
available cores.
|
||||
|
||||
## Running via Command
|
||||
|
||||
If you like using command line arguments, you can launch a sanic server
|
||||
by executing the module. For example, if you initialized sanic as
|
||||
app in a file named server.py, you could run the server like so:
|
||||
|
||||
`python -m sanic server.app --host=0.0.0.0 --port=1337 --workers=4`
|
||||
|
||||
With this way of running sanic, it is not necessary to run app.run in
|
||||
your python file. If you do, just make sure you wrap it in name == main
|
||||
like so:
|
||||
|
||||
```python
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=1337, workers=4)
|
||||
```
|
@ -1,28 +0,0 @@
|
||||
# Exceptions
|
||||
|
||||
Exceptions can be thrown from within request handlers and will automatically be handled by Sanic. Exceptions take a message as their first argument, and can also take a status_code to be passed back in the HTTP response. Check sanic.exceptions for the full list of exceptions to throw.
|
||||
|
||||
## Throwing an exception
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.exceptions import ServerError
|
||||
|
||||
@app.route('/killme')
|
||||
def i_am_ready_to_die(request):
|
||||
raise ServerError("Something bad happened")
|
||||
```
|
||||
|
||||
## Handling Exceptions
|
||||
|
||||
Just use the @exception decorator. The decorator expects a list of exceptions to handle as arguments. You can pass SanicException to catch them all! The exception handler must expect a request and exception object as arguments.
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.response import text
|
||||
from sanic.exceptions import NotFound
|
||||
|
||||
@app.exception(NotFound)
|
||||
def ignore_404s(request, exception):
|
||||
return text("Yep, I totally found the page: {}".format(request.url))
|
||||
```
|
@ -1,25 +0,0 @@
|
||||
# Getting Started
|
||||
|
||||
Make sure you have pip and python 3.5 before starting
|
||||
|
||||
## Benchmarks
|
||||
* Install Sanic
|
||||
* `python3 -m pip install sanic`
|
||||
* Edit main.py to include:
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
app = Sanic(__name__)
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
return json({ "hello": "world" })
|
||||
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
||||
```
|
||||
* Run `python3 main.py`
|
||||
|
||||
You now have a working Sanic server! To continue on, check out:
|
||||
* [Request Data](request_data.md)
|
||||
* [Routing](routing.md)
|
468
docs/index.html
Normal file
468
docs/index.html
Normal file
@ -0,0 +1,468 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils 0.15.2: http://docutils.sourceforge.net/" />
|
||||
<title>index.rst</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger (goodger@python.org)
|
||||
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
|
||||
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
.subscript {
|
||||
vertical-align: sub;
|
||||
font-size: smaller }
|
||||
|
||||
.superscript {
|
||||
vertical-align: super;
|
||||
font-size: smaller }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title, .code .error {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left, .figure.align-left, object.align-left, table.align-left {
|
||||
clear: left ;
|
||||
float: left ;
|
||||
margin-right: 1em }
|
||||
|
||||
img.align-right, .figure.align-right, object.align-right, table.align-right {
|
||||
clear: right ;
|
||||
float: right ;
|
||||
margin-left: 1em }
|
||||
|
||||
img.align-center, .figure.align-center, object.align-center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
table.align-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.align-left {
|
||||
text-align: left }
|
||||
|
||||
.align-center {
|
||||
clear: both ;
|
||||
text-align: center }
|
||||
|
||||
.align-right {
|
||||
text-align: right }
|
||||
|
||||
/* reset inner alignment in figures */
|
||||
div.align-right {
|
||||
text-align: inherit }
|
||||
|
||||
/* div.align-center * { */
|
||||
/* text-align: left } */
|
||||
|
||||
.align-top {
|
||||
vertical-align: top }
|
||||
|
||||
.align-middle {
|
||||
vertical-align: middle }
|
||||
|
||||
.align-bottom {
|
||||
vertical-align: bottom }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font: inherit }
|
||||
|
||||
pre.literal-block, pre.doctest-block, pre.math, pre.code {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
pre.code .ln { color: grey; } /* line numbers */
|
||||
pre.code, code { background-color: #eeeeee }
|
||||
pre.code .comment, code .comment { color: #5C6576 }
|
||||
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
|
||||
pre.code .literal.string, code .literal.string { color: #0C5404 }
|
||||
pre.code .name.builtin, code .name.builtin { color: #352B84 }
|
||||
pre.code .deleted, code .deleted { background-color: #DEB0A1}
|
||||
pre.code .inserted, code .inserted { background-color: #A3D289}
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
/* "booktabs" style (no vertical lines) */
|
||||
table.docutils.booktabs {
|
||||
border: 0px;
|
||||
border-top: 2px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.docutils.booktabs * {
|
||||
border: 0px;
|
||||
}
|
||||
table.docutils.booktabs th {
|
||||
border-bottom: thin solid;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document">
|
||||
|
||||
|
||||
<div class="section" id="sanic">
|
||||
<h1>Sanic</h1>
|
||||
<p>Sanic is a Python 3.6+ web server and web framework that's written to go fast. It allows the usage of the async/await syntax added in Python 3.5, which makes your code non-blocking and speedy.</p>
|
||||
<p>The goal of the project is to provide a simple way to get up and running a highly performant HTTP server that is easy to build, to expand, and ultimately to scale.</p>
|
||||
<p>Sanic is developed <a class="reference external" href="https://github.com/channelcat/sanic/">on GitHub</a>. Contributions are welcome!</p>
|
||||
<div class="section" id="sanic-aspires-to-be-simple">
|
||||
<h2>Sanic aspires to be simple</h2>
|
||||
<pre class="code python literal-block">
|
||||
<span class="keyword namespace">from</span> <span class="name namespace">sanic</span> <span class="keyword namespace">import</span> <span class="name">Sanic</span>
|
||||
<span class="keyword namespace">from</span> <span class="name namespace">sanic.response</span> <span class="keyword namespace">import</span> <span class="name">json</span>
|
||||
|
||||
<span class="name">app</span> <span class="operator">=</span> <span class="name">Sanic</span><span class="punctuation">()</span>
|
||||
|
||||
<span class="name decorator">@app.route</span><span class="punctuation">(</span><span class="literal string double">"/"</span><span class="punctuation">)</span>
|
||||
<span class="name">async</span> <span class="keyword">def</span> <span class="name function">test</span><span class="punctuation">(</span><span class="name">request</span><span class="punctuation">):</span>
|
||||
<span class="keyword">return</span> <span class="name">json</span><span class="punctuation">({</span><span class="literal string double">"hello"</span><span class="punctuation">:</span> <span class="literal string double">"world"</span><span class="punctuation">})</span>
|
||||
|
||||
<span class="keyword">if</span> <span class="name variable magic">__name__</span> <span class="operator">==</span> <span class="literal string double">"__main__"</span><span class="punctuation">:</span>
|
||||
<span class="name">app</span><span class="operator">.</span><span class="name">run</span><span class="punctuation">(</span><span class="name">host</span><span class="operator">=</span><span class="literal string double">"0.0.0.0"</span><span class="punctuation">,</span> <span class="name">port</span><span class="operator">=</span><span class="literal number integer">8000</span><span class="punctuation">)</span>
|
||||
</pre>
|
||||
<div class="admonition note">
|
||||
<p class="first admonition-title">Note</p>
|
||||
<p class="last">Sanic does not support Python 3.5 from version 19.6 and forward. However, version 18.12LTS is supported thru
|
||||
December 2020. Official Python support for version 3.5 is set to expire in September 2020.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="guides">
|
||||
<h1>Guides</h1>
|
||||
<div class="system-message">
|
||||
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">E:/OneDrive/GitHub/sanic/docs/index.rst</tt>, line 6)</p>
|
||||
<p>Unknown directive type "toctree".</p>
|
||||
<pre class="literal-block">
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
sanic/getting_started
|
||||
sanic/config
|
||||
sanic/logging
|
||||
sanic/request_data
|
||||
sanic/response
|
||||
sanic/cookies
|
||||
sanic/routing
|
||||
sanic/blueprints
|
||||
sanic/static_files
|
||||
sanic/versioning
|
||||
sanic/exceptions
|
||||
sanic/middleware
|
||||
sanic/websocket
|
||||
sanic/decorators
|
||||
sanic/streaming
|
||||
sanic/class_based_views
|
||||
sanic/custom_protocol
|
||||
sanic/sockets
|
||||
sanic/ssl
|
||||
sanic/debug_mode
|
||||
sanic/testing
|
||||
sanic/deploying
|
||||
sanic/extensions
|
||||
sanic/examples
|
||||
sanic/changelog
|
||||
sanic/contributing
|
||||
sanic/api_reference
|
||||
sanic/asyncio_python37
|
||||
|
||||
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="module-documentation">
|
||||
<h1>Module Documentation</h1>
|
||||
<div class="system-message">
|
||||
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">E:/OneDrive/GitHub/sanic/docs/index.rst</tt>, line 42)</p>
|
||||
<p>Unknown directive type "toctree".</p>
|
||||
<pre class="literal-block">
|
||||
.. toctree::
|
||||
|
||||
</pre>
|
||||
</div>
|
||||
<ul>
|
||||
<li><p class="first"><a href="#id1"><span class="problematic" id="id2">:ref:`genindex`</span></a></p>
|
||||
<div class="system-message" id="id1">
|
||||
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">E:/OneDrive/GitHub/sanic/docs/index.rst</tt>, line 44); <em><a href="#id2">backlink</a></em></p>
|
||||
<p>Unknown interpreted text role "ref".</p>
|
||||
</div>
|
||||
</li>
|
||||
<li><p class="first"><a href="#id3"><span class="problematic" id="id4">:ref:`modindex`</span></a></p>
|
||||
<div class="system-message" id="id3">
|
||||
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">E:/OneDrive/GitHub/sanic/docs/index.rst</tt>, line 45); <em><a href="#id4">backlink</a></em></p>
|
||||
<p>Unknown interpreted text role "ref".</p>
|
||||
</div>
|
||||
</li>
|
||||
<li><p class="first"><a href="#id5"><span class="problematic" id="id6">:ref:`search`</span></a></p>
|
||||
<div class="system-message" id="id5">
|
||||
<p class="system-message-title">System Message: ERROR/3 (<tt class="docutils">E:/OneDrive/GitHub/sanic/docs/index.rst</tt>, line 46); <em><a href="#id6">backlink</a></em></p>
|
||||
<p>Unknown interpreted text role "ref".</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
29
docs/index.rst
Normal file
29
docs/index.rst
Normal file
@ -0,0 +1,29 @@
|
||||
.. include:: ../README.rst
|
||||
|
||||
User Guide
|
||||
==========
|
||||
|
||||
To learn about using Sanic, checkout the `User Guide <https://sanicframework.org/guide/>`__.
|
||||
|
||||
API
|
||||
===
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
👥 User Guide <https://sanicframework.org/guide/>
|
||||
sanic/api_reference
|
||||
💻 Source code <https://github.com/sanic-org/sanic/>
|
||||
sanic/changelog
|
||||
sanic/contributing
|
||||
❓ Support <https://community.sanicframework.org/>
|
||||
💬 Chat <https://discord.gg/FARQzAEMAA>
|
||||
|
||||
|
||||
Module Documentation
|
||||
====================
|
||||
|
||||
.. toctree::
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
281
docs/make.bat
Normal file
281
docs/make.bat
Normal file
@ -0,0 +1,281 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set BUILDDIR=_build
|
||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||
if NOT "%PAPER%" == "" (
|
||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
if "%1" == "help" (
|
||||
:help
|
||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||
echo. html to make standalone HTML files
|
||||
echo. dirhtml to make HTML files named index.html in directories
|
||||
echo. singlehtml to make a single large HTML file
|
||||
echo. pickle to make pickle files
|
||||
echo. json to make JSON files
|
||||
echo. htmlhelp to make HTML files and a HTML help project
|
||||
echo. qthelp to make HTML files and a qthelp project
|
||||
echo. devhelp to make HTML files and a Devhelp project
|
||||
echo. epub to make an epub
|
||||
echo. epub3 to make an epub3
|
||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||
echo. text to make text files
|
||||
echo. man to make manual pages
|
||||
echo. texinfo to make Texinfo files
|
||||
echo. gettext to make PO message catalogs
|
||||
echo. changes to make an overview over all changed/added/deprecated items
|
||||
echo. xml to make Docutils-native XML files
|
||||
echo. pseudoxml to make pseudoxml-XML files for display purposes
|
||||
echo. linkcheck to check all external links for integrity
|
||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||
echo. coverage to run coverage check of the documentation if enabled
|
||||
echo. dummy to check syntax errors of document sources
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "clean" (
|
||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||
del /q /s %BUILDDIR%\*
|
||||
goto end
|
||||
)
|
||||
|
||||
|
||||
REM Check if sphinx-build is available and fallback to Python version if any
|
||||
%SPHINXBUILD% 1>NUL 2>NUL
|
||||
if errorlevel 9009 goto sphinx_python
|
||||
goto sphinx_ok
|
||||
|
||||
:sphinx_python
|
||||
|
||||
set SPHINXBUILD=python -m sphinx.__init__
|
||||
%SPHINXBUILD% 2> nul
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:sphinx_ok
|
||||
|
||||
|
||||
if "%1" == "html" (
|
||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dirhtml" (
|
||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "singlehtml" (
|
||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pickle" (
|
||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the pickle files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "json" (
|
||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can process the JSON files.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "htmlhelp" (
|
||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "qthelp" (
|
||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\aiographite.qhcp
|
||||
echo.To view the help file:
|
||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\aiographite.ghc
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "devhelp" (
|
||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub" (
|
||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "epub3" (
|
||||
%SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The epub3 file is in %BUILDDIR%/epub3.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latex" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdf" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf
|
||||
cd %~dp0
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "latexpdfja" (
|
||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||
cd %BUILDDIR%/latex
|
||||
make all-pdf-ja
|
||||
cd %~dp0
|
||||
echo.
|
||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "text" (
|
||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "man" (
|
||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "texinfo" (
|
||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "gettext" (
|
||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "changes" (
|
||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.The overview file is in %BUILDDIR%/changes.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "linkcheck" (
|
||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Link check complete; look for any errors in the above output ^
|
||||
or in %BUILDDIR%/linkcheck/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "doctest" (
|
||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of doctests in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/doctest/output.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "coverage" (
|
||||
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Testing of coverage in the sources finished, look at the ^
|
||||
results in %BUILDDIR%/coverage/python.txt.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "xml" (
|
||||
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The XML files are in %BUILDDIR%/xml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "pseudoxml" (
|
||||
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%1" == "dummy" (
|
||||
%SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy
|
||||
if errorlevel 1 exit /b 1
|
||||
echo.
|
||||
echo.Build finished. Dummy builder generates no files.
|
||||
goto end
|
||||
)
|
||||
|
||||
:end
|
@ -1,29 +0,0 @@
|
||||
# Middleware
|
||||
|
||||
Middleware can be executed before or after requests. It is executed in the order it was registered. If middleware returns a response object, the request will stop processing and a response will be returned.
|
||||
|
||||
Middleware is registered via the middleware decorator, and can either be added as 'request' or 'response' middleware, based on the argument provided in the decorator. Response middleware receives both the request and the response as arguments.
|
||||
|
||||
## Examples
|
||||
|
||||
```python
|
||||
app = Sanic(__name__)
|
||||
|
||||
@app.middleware
|
||||
async def halt_request(request):
|
||||
print("I am a spy")
|
||||
|
||||
@app.middleware('request')
|
||||
async def halt_request(request):
|
||||
return text('I halted the request')
|
||||
|
||||
@app.middleware('response')
|
||||
async def halt_response(request, response):
|
||||
return text('I halted the response')
|
||||
|
||||
@app.route('/')
|
||||
async def handler(request):
|
||||
return text('I would like to speak now please')
|
||||
|
||||
app.run(host="0.0.0.0", port=8000)
|
||||
```
|
@ -1,49 +0,0 @@
|
||||
# Request Data
|
||||
|
||||
## Properties
|
||||
|
||||
The following request variables are accessible as properties:
|
||||
|
||||
`request.files` (dictionary of File objects) - List of files that have a name, body, and type
|
||||
`request.json` (any) - JSON body
|
||||
`request.args` (dict) - Query String variables. Use getlist to get multiple of the same name
|
||||
`request.form` (dict) - Posted form variables. Use getlist to get multiple of the same name
|
||||
`request.body` (bytes) - Posted raw body. To get the raw data, regardless of content type
|
||||
|
||||
See request.py for more information
|
||||
|
||||
## Examples
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.response import json, text
|
||||
|
||||
@app.route("/json")
|
||||
def post_json(request):
|
||||
return json({ "received": True, "message": request.json })
|
||||
|
||||
@app.route("/form")
|
||||
def post_json(request):
|
||||
return json({ "received": True, "form_data": request.form, "test": request.form.get('test') })
|
||||
|
||||
@app.route("/files")
|
||||
def post_json(request):
|
||||
test_file = request.files.get('test')
|
||||
|
||||
file_parameters = {
|
||||
'body': test_file.body,
|
||||
'name': test_file.name,
|
||||
'type': test_file.type,
|
||||
}
|
||||
|
||||
return json({ "received": True, "file_names": request.files.keys(), "test_file_parameters": file_parameters })
|
||||
|
||||
@app.route("/query_string")
|
||||
def query_string(request):
|
||||
return json({ "parsed": True, "args": request.args, "url": request.url, "query_string": request.query_string })
|
||||
|
||||
|
||||
@app.route("/users", methods=["POST",])
|
||||
def create_user(request):
|
||||
return text("You are trying to create a user with the following POST: %s" % request.body)
|
||||
```
|
@ -1,32 +0,0 @@
|
||||
# Routing
|
||||
|
||||
Sanic comes with a basic router that supports request parameters. To specify a parameter, surround it with carrots like so: `<PARAM>`. Request parameters will be passed to the request handler functions as keyword arguments. To specify a type, add a :type after the parameter name, in the carrots. If the parameter does not match the type supplied, Sanic will throw a NotFound exception, resulting in a 404 page not found error.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
```python
|
||||
from sanic import Sanic
|
||||
from sanic.response import text
|
||||
|
||||
@app.route('/tag/<tag>')
|
||||
async def tag_handler(request, tag):
|
||||
return text('Tag - {}'.format(tag))
|
||||
|
||||
@app.route('/number/<integer_arg:int>')
|
||||
async def integer_handler(request, integer_arg):
|
||||
return text('Integer - {}'.format(integer_arg))
|
||||
|
||||
@app.route('/number/<number_arg:number>')
|
||||
async def number_handler(request, number_arg):
|
||||
return text('Number - {}'.format(number_arg))
|
||||
|
||||
@app.route('/person/<name:[A-z]>')
|
||||
async def person_handler(request, name):
|
||||
return text('Person - {}'.format(name))
|
||||
|
||||
@app.route('/folder/<folder_id:[A-z0-9]{0,4}>')
|
||||
async def folder_handler(request, folder_id):
|
||||
return text('Folder - {}'.format(folder_id))
|
||||
|
||||
```
|
33
docs/sanic/api/app.rst
Normal file
33
docs/sanic/api/app.rst
Normal file
@ -0,0 +1,33 @@
|
||||
Application
|
||||
===========
|
||||
|
||||
sanic.app
|
||||
---------
|
||||
|
||||
.. automodule:: sanic.app
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
sanic.config
|
||||
------------
|
||||
|
||||
.. automodule:: sanic.config
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
sanic.application.constants
|
||||
---------------------------
|
||||
|
||||
.. automodule:: sanic.application.constants
|
||||
:exclude-members: StrEnum
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
sanic.application.state
|
||||
-----------------------
|
||||
|
||||
.. automodule:: sanic.application.state
|
||||
:members:
|
||||
:show-inheritance:
|
17
docs/sanic/api/blueprints.rst
Normal file
17
docs/sanic/api/blueprints.rst
Normal file
@ -0,0 +1,17 @@
|
||||
Blueprints
|
||||
==========
|
||||
|
||||
sanic.blueprints
|
||||
----------------
|
||||
|
||||
.. automodule:: sanic.blueprints
|
||||
:members:
|
||||
:show-inheritance:
|
||||
:inherited-members:
|
||||
|
||||
sanic.blueprint_group
|
||||
---------------------
|
||||
|
||||
.. automodule:: sanic.blueprint_group
|
||||
:members:
|
||||
:special-members:
|
48
docs/sanic/api/core.rst
Normal file
48
docs/sanic/api/core.rst
Normal file
@ -0,0 +1,48 @@
|
||||
Core
|
||||
====
|
||||
|
||||
sanic.cookies
|
||||
-------------
|
||||
|
||||
.. automodule:: sanic.cookies
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
sanic.handlers
|
||||
--------------
|
||||
|
||||
.. automodule:: sanic.handlers
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
sanic.headers
|
||||
--------------
|
||||
|
||||
.. automodule:: sanic.headers
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
sanic.request
|
||||
-------------
|
||||
|
||||
.. automodule:: sanic.request
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
sanic.response
|
||||
--------------
|
||||
|
||||
.. automodule:: sanic.response
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
sanic.views
|
||||
-----------
|
||||
|
||||
.. automodule:: sanic.views
|
||||
:members:
|
||||
:show-inheritance:
|
16
docs/sanic/api/exceptions.rst
Normal file
16
docs/sanic/api/exceptions.rst
Normal file
@ -0,0 +1,16 @@
|
||||
Exceptions
|
||||
==========
|
||||
|
||||
sanic.errorpages
|
||||
----------------
|
||||
|
||||
.. automodule:: sanic.errorpages
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
sanic.exceptions
|
||||
----------------
|
||||
|
||||
.. automodule:: sanic.exceptions
|
||||
:members:
|
||||
:show-inheritance:
|
18
docs/sanic/api/router.rst
Normal file
18
docs/sanic/api/router.rst
Normal file
@ -0,0 +1,18 @@
|
||||
Routing
|
||||
=======
|
||||
|
||||
sanic_routing models
|
||||
--------------------
|
||||
|
||||
.. autoclass:: sanic_routing.route::Route
|
||||
:members:
|
||||
|
||||
.. autoclass:: sanic_routing.group::RouteGroup
|
||||
:members:
|
||||
|
||||
sanic.router
|
||||
------------
|
||||
|
||||
.. automodule:: sanic.router
|
||||
:members:
|
||||
:show-inheritance:
|
18
docs/sanic/api/server.rst
Normal file
18
docs/sanic/api/server.rst
Normal file
@ -0,0 +1,18 @@
|
||||
Sanic Server
|
||||
============
|
||||
|
||||
sanic.http
|
||||
----------
|
||||
|
||||
.. automodule:: sanic.http
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
sanic.server
|
||||
------------
|
||||
|
||||
.. automodule:: sanic.server
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
16
docs/sanic/api/utility.rst
Normal file
16
docs/sanic/api/utility.rst
Normal file
@ -0,0 +1,16 @@
|
||||
Utility
|
||||
=======
|
||||
|
||||
sanic.compat
|
||||
------------
|
||||
|
||||
.. automodule:: sanic.compat
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
sanic.log
|
||||
---------
|
||||
|
||||
.. automodule:: sanic.log
|
||||
:members:
|
||||
:show-inheritance:
|
13
docs/sanic/api_reference.rst
Normal file
13
docs/sanic/api_reference.rst
Normal file
@ -0,0 +1,13 @@
|
||||
📑 API Reference
|
||||
================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
api/app
|
||||
api/blueprints
|
||||
api/core
|
||||
api/exceptions
|
||||
api/router
|
||||
api/server
|
||||
api/utility
|
16
docs/sanic/changelog.rst
Normal file
16
docs/sanic/changelog.rst
Normal file
@ -0,0 +1,16 @@
|
||||
📜 Changelog
|
||||
============
|
||||
|
||||
| 🔶 Current release
|
||||
| 🔷 In support release
|
||||
|
|
||||
|
||||
.. mdinclude:: ./releases/23/23.6.md
|
||||
.. mdinclude:: ./releases/23/23.3.md
|
||||
.. mdinclude:: ./releases/22/22.12.md
|
||||
.. mdinclude:: ./releases/22/22.9.md
|
||||
.. mdinclude:: ./releases/22/22.6.md
|
||||
.. mdinclude:: ./releases/22/22.3.md
|
||||
.. mdinclude:: ./releases/21/21.12.md
|
||||
.. mdinclude:: ./releases/21/21.9.md
|
||||
.. include:: ../../CHANGELOG.rst
|
4
docs/sanic/contributing.rst
Normal file
4
docs/sanic/contributing.rst
Normal file
@ -0,0 +1,4 @@
|
||||
♥️ Contributing
|
||||
===============
|
||||
|
||||
.. include:: ../../CONTRIBUTING.rst
|
66
docs/sanic/releases/21/21.12.md
Normal file
66
docs/sanic/releases/21/21.12.md
Normal file
@ -0,0 +1,66 @@
|
||||
## Version 21.12.1 🔷
|
||||
|
||||
_Current LTS version_
|
||||
|
||||
- [#2349](https://github.com/sanic-org/sanic/pull/2349) Only display MOTD on startup
|
||||
- [#2354](https://github.com/sanic-org/sanic/pull/2354) Ignore name argument in Python 3.7
|
||||
- [#2355](https://github.com/sanic-org/sanic/pull/2355) Add config.update support for all config values
|
||||
|
||||
## Version 21.12.0 🔹
|
||||
|
||||
### Features
|
||||
- [#2260](https://github.com/sanic-org/sanic/pull/2260) Allow early Blueprint registrations to still apply later added objects
|
||||
- [#2262](https://github.com/sanic-org/sanic/pull/2262) Noisy exceptions - force logging of all exceptions
|
||||
- [#2264](https://github.com/sanic-org/sanic/pull/2264) Optional `uvloop` by configuration
|
||||
- [#2270](https://github.com/sanic-org/sanic/pull/2270) Vhost support using multiple TLS certificates
|
||||
- [#2277](https://github.com/sanic-org/sanic/pull/2277) Change signal routing for increased consistency
|
||||
- *BREAKING CHANGE*: If you were manually routing signals there is a breaking change. The signal router's `get` is no longer 100% determinative. There is now an additional step to loop thru the returned signals for proper matching on the requirements. If signals are being dispatched using `app.dispatch` or `bp.dispatch`, there is no change.
|
||||
- [#2290](https://github.com/sanic-org/sanic/pull/2290) Add contextual exceptions
|
||||
- [#2291](https://github.com/sanic-org/sanic/pull/2291) Increase join concat performance
|
||||
- [#2295](https://github.com/sanic-org/sanic/pull/2295), [#2316](https://github.com/sanic-org/sanic/pull/2316), [#2331](https://github.com/sanic-org/sanic/pull/2331) Restructure of CLI and application state with new displays and more command parity with `app.run`
|
||||
- [#2302](https://github.com/sanic-org/sanic/pull/2302) Add route context at definition time
|
||||
- [#2304](https://github.com/sanic-org/sanic/pull/2304) Named tasks and new API for managing background tasks
|
||||
- [#2307](https://github.com/sanic-org/sanic/pull/2307) On app auto-reload, provide insight of changed files
|
||||
- [#2308](https://github.com/sanic-org/sanic/pull/2308) Auto extend application with [Sanic Extensions](https://sanicframework.org/en/plugins/sanic-ext/getting-started.html) if it is installed, and provide first class support for accessing the extensions
|
||||
- [#2309](https://github.com/sanic-org/sanic/pull/2309) Builtin signals changed to `Enum`
|
||||
- [#2313](https://github.com/sanic-org/sanic/pull/2313) Support additional config implementation use case
|
||||
- [#2321](https://github.com/sanic-org/sanic/pull/2321) Refactor environment variable hydration logic
|
||||
- [#2327](https://github.com/sanic-org/sanic/pull/2327) Prevent sending multiple or mixed responses on a single request
|
||||
- [#2330](https://github.com/sanic-org/sanic/pull/2330) Custom type casting on environment variables
|
||||
- [#2332](https://github.com/sanic-org/sanic/pull/2332) Make all deprecation notices consistent
|
||||
- [#2335](https://github.com/sanic-org/sanic/pull/2335) Allow underscore to start instance names
|
||||
|
||||
### Bugfixes
|
||||
- [#2273](https://github.com/sanic-org/sanic/pull/2273) Replace assignation by typing for `websocket_handshake`
|
||||
- [#2285](https://github.com/sanic-org/sanic/pull/2285) Fix IPv6 display in startup logs
|
||||
- [#2299](https://github.com/sanic-org/sanic/pull/2299) Dispatch `http.lifecyle.response` from exception handler
|
||||
|
||||
### Deprecations and Removals
|
||||
- [#2306](https://github.com/sanic-org/sanic/pull/2306) Removal of deprecated items
|
||||
- `Sanic` and `Blueprint` may no longer have arbitrary properties attached to them
|
||||
- `Sanic` and `Blueprint` forced to have compliant names
|
||||
- alphanumeric + `_` + `-`
|
||||
- must start with letter or `_`
|
||||
- `load_env` keyword argument of `Sanic`
|
||||
- `sanic.exceptions.abort`
|
||||
- `sanic.views.CompositionView`
|
||||
- `sanic.response.StreamingHTTPResponse`
|
||||
- *NOTE:* the `stream()` response method (where you pass a callable streaming function) has been deprecated and will be removed in v22.6. You should upgrade all streaming responses to the new style: https://sanicframework.org/en/guide/advanced/streaming.html#response-streaming
|
||||
- [#2320](https://github.com/sanic-org/sanic/pull/2320) Remove app instance from Config for error handler setting
|
||||
|
||||
### Developer infrastructure
|
||||
- [#2251](https://github.com/sanic-org/sanic/pull/2251) Change dev install command
|
||||
- [#2286](https://github.com/sanic-org/sanic/pull/2286) Change codeclimate complexity threshold from 5 to 10
|
||||
- [#2287](https://github.com/sanic-org/sanic/pull/2287) Update host test function names so they are not overwritten
|
||||
- [#2292](https://github.com/sanic-org/sanic/pull/2292) Fail CI on error
|
||||
- [#2311](https://github.com/sanic-org/sanic/pull/2311), [#2324](https://github.com/sanic-org/sanic/pull/2324) Do not run tests for draft PRs
|
||||
- [#2336](https://github.com/sanic-org/sanic/pull/2336) Remove paths from coverage checks
|
||||
- [#2338](https://github.com/sanic-org/sanic/pull/2338) Cleanup ports on tests
|
||||
|
||||
### Improved Documentation
|
||||
- [#2269](https://github.com/sanic-org/sanic/pull/2269), [#2329](https://github.com/sanic-org/sanic/pull/2329), [#2333](https://github.com/sanic-org/sanic/pull/2333) Cleanup typos and fix language
|
||||
|
||||
### Miscellaneous
|
||||
- [#2257](https://github.com/sanic-org/sanic/pull/2257), [#2294](https://github.com/sanic-org/sanic/pull/2294), [#2341](https://github.com/sanic-org/sanic/pull/2341) Add Python 3.10 support
|
||||
- [#2279](https://github.com/sanic-org/sanic/pull/2279), [#2317](https://github.com/sanic-org/sanic/pull/2317), [#2322](https://github.com/sanic-org/sanic/pull/2322) Add/correct missing type annotations
|
||||
- [#2305](https://github.com/sanic-org/sanic/pull/2305) Fix examples to use modern implementations
|
50
docs/sanic/releases/21/21.9.md
Normal file
50
docs/sanic/releases/21/21.9.md
Normal file
@ -0,0 +1,50 @@
|
||||
## Version 21.9.3
|
||||
*Rerelease of v21.9.2 with some cleanup*
|
||||
|
||||
## Version 21.9.2
|
||||
- [#2268](https://github.com/sanic-org/sanic/pull/2268) Make HTTP connections start in IDLE stage, avoiding delays and error messages
|
||||
- [#2310](https://github.com/sanic-org/sanic/pull/2310) More consistent config setting with post-FALLBACK_ERROR_FORMAT apply
|
||||
|
||||
## Version 21.9.1
|
||||
- [#2259](https://github.com/sanic-org/sanic/pull/2259) Allow non-conforming ErrorHandlers
|
||||
|
||||
## Version 21.9.0
|
||||
|
||||
### Features
|
||||
- [#2158](https://github.com/sanic-org/sanic/pull/2158), [#2248](https://github.com/sanic-org/sanic/pull/2248) Complete overhaul of I/O to websockets
|
||||
- [#2160](https://github.com/sanic-org/sanic/pull/2160) Add new 17 signals into server and request lifecycles
|
||||
- [#2162](https://github.com/sanic-org/sanic/pull/2162) Smarter `auto` fallback formatting upon exception
|
||||
- [#2184](https://github.com/sanic-org/sanic/pull/2184) Introduce implementation for copying a Blueprint
|
||||
- [#2200](https://github.com/sanic-org/sanic/pull/2200) Accept header parsing
|
||||
- [#2207](https://github.com/sanic-org/sanic/pull/2207) Log remote address if available
|
||||
- [#2209](https://github.com/sanic-org/sanic/pull/2209) Add convenience methods to BP groups
|
||||
- [#2216](https://github.com/sanic-org/sanic/pull/2216) Add default messages to SanicExceptions
|
||||
- [#2225](https://github.com/sanic-org/sanic/pull/2225) Type annotation convenience for annotated handlers with path parameters
|
||||
- [#2236](https://github.com/sanic-org/sanic/pull/2236) Allow Falsey (but not-None) responses from route handlers
|
||||
- [#2238](https://github.com/sanic-org/sanic/pull/2238) Add `exception` decorator to Blueprint Groups
|
||||
- [#2244](https://github.com/sanic-org/sanic/pull/2244) Explicit static directive for serving file or dir (ex: `static(..., resource_type="file")`)
|
||||
- [#2245](https://github.com/sanic-org/sanic/pull/2245) Close HTTP loop when connection task cancelled
|
||||
|
||||
### Bugfixes
|
||||
- [#2188](https://github.com/sanic-org/sanic/pull/2188) Fix the handling of the end of a chunked request
|
||||
- [#2195](https://github.com/sanic-org/sanic/pull/2195) Resolve unexpected error handling on static requests
|
||||
- [#2208](https://github.com/sanic-org/sanic/pull/2208) Make blueprint-based exceptions attach and trigger in a more intuitive manner
|
||||
- [#2211](https://github.com/sanic-org/sanic/pull/2211) Fixed for handling exceptions of asgi app call
|
||||
- [#2213](https://github.com/sanic-org/sanic/pull/2213) Fix bug where ws exceptions not being logged
|
||||
- [#2231](https://github.com/sanic-org/sanic/pull/2231) Cleaner closing of tasks by using `abort()` in strategic places to avoid dangling sockets
|
||||
- [#2247](https://github.com/sanic-org/sanic/pull/2247) Fix logging of auto-reload status in debug mode
|
||||
- [#2246](https://github.com/sanic-org/sanic/pull/2246) Account for BP with exception handler but no routes
|
||||
|
||||
### Developer infrastructure
|
||||
- [#2194](https://github.com/sanic-org/sanic/pull/2194) HTTP unit tests with raw client
|
||||
- [#2199](https://github.com/sanic-org/sanic/pull/2199) Switch to codeclimate
|
||||
- [#2214](https://github.com/sanic-org/sanic/pull/2214) Try Reopening Windows Tests
|
||||
- [#2229](https://github.com/sanic-org/sanic/pull/2229) Refactor `HttpProtocol` into a base class
|
||||
- [#2230](https://github.com/sanic-org/sanic/pull/2230) Refactor `server.py` into multi-file module
|
||||
|
||||
### Miscellaneous
|
||||
- [#2173](https://github.com/sanic-org/sanic/pull/2173) Remove Duplicated Dependencies and PEP 517 Support
|
||||
- [#2193](https://github.com/sanic-org/sanic/pull/2193), [#2196](https://github.com/sanic-org/sanic/pull/2196), [#2217](https://github.com/sanic-org/sanic/pull/2217) Type annotation changes
|
||||
|
||||
|
||||
|
55
docs/sanic/releases/22/22.12.md
Normal file
55
docs/sanic/releases/22/22.12.md
Normal file
@ -0,0 +1,55 @@
|
||||
## Version 22.12.0 🔷
|
||||
|
||||
_Current version_
|
||||
|
||||
### Features
|
||||
|
||||
- [#2569](https://github.com/sanic-org/sanic/pull/2569) Add `JSONResponse` class with some convenient methods when updating a response object
|
||||
- [#2598](https://github.com/sanic-org/sanic/pull/2598) Change `uvloop` requirement to `>=0.15.0`
|
||||
- [#2609](https://github.com/sanic-org/sanic/pull/2609) Add compatibility with `websockets` v11.0
|
||||
- [#2610](https://github.com/sanic-org/sanic/pull/2610) Kill server early on worker error
|
||||
- Raise deadlock timeout to 30s
|
||||
- [#2617](https://github.com/sanic-org/sanic/pull/2617) Scale number of running server workers
|
||||
- [#2621](https://github.com/sanic-org/sanic/pull/2621) [#2634](https://github.com/sanic-org/sanic/pull/2634) Send `SIGKILL` on subsequent `ctrl+c` to force worker exit
|
||||
- [#2622](https://github.com/sanic-org/sanic/pull/2622) Add API to restart all workers from the multiplexer
|
||||
- [#2624](https://github.com/sanic-org/sanic/pull/2624) Default to `spawn` for all subprocesses unless specifically set:
|
||||
```python
|
||||
from sanic import Sanic
|
||||
|
||||
Sanic.start_method = "fork"
|
||||
```
|
||||
- [#2625](https://github.com/sanic-org/sanic/pull/2625) Filename normalisation of form-data/multipart file uploads
|
||||
- [#2626](https://github.com/sanic-org/sanic/pull/2626) Move to HTTP Inspector:
|
||||
- Remote access to inspect running Sanic instances
|
||||
- TLS support for encrypted calls to Inspector
|
||||
- Authentication to Inspector with API key
|
||||
- Ability to extend Inspector with custom commands
|
||||
- [#2632](https://github.com/sanic-org/sanic/pull/2632) Control order of restart operations
|
||||
- [#2633](https://github.com/sanic-org/sanic/pull/2633) Move reload interval to class variable
|
||||
- [#2636](https://github.com/sanic-org/sanic/pull/2636) Add `priority` to `register_middleware` method
|
||||
- [#2639](https://github.com/sanic-org/sanic/pull/2639) Add `unquote` to `add_route` method
|
||||
- [#2640](https://github.com/sanic-org/sanic/pull/2640) ASGI websockets to receive `text` or `bytes`
|
||||
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#2607](https://github.com/sanic-org/sanic/pull/2607) Force socket shutdown before close to allow rebinding
|
||||
- [#2590](https://github.com/sanic-org/sanic/pull/2590) Use actual `StrEnum` in Python 3.11+
|
||||
- [#2615](https://github.com/sanic-org/sanic/pull/2615) Ensure middleware executes only once per request timeout
|
||||
- [#2627](https://github.com/sanic-org/sanic/pull/2627) Crash ASGI application on lifespan failure
|
||||
- [#2635](https://github.com/sanic-org/sanic/pull/2635) Resolve error with low-level server creation on Windows
|
||||
|
||||
|
||||
### Deprecations and Removals
|
||||
|
||||
- [#2608](https://github.com/sanic-org/sanic/pull/2608) [#2630](https://github.com/sanic-org/sanic/pull/2630) Signal conditions and triggers saved on `signal.extra`
|
||||
- [#2626](https://github.com/sanic-org/sanic/pull/2626) Move to HTTP Inspector
|
||||
- 🚨 *BREAKING CHANGE*: Moves the Inspector to a Sanic app from a simple TCP socket with a custom protocol
|
||||
- *DEPRECATE*: The `--inspect*` commands have been deprecated in favor of `inspect ...` commands
|
||||
- [#2628](https://github.com/sanic-org/sanic/pull/2628) Replace deprecated `distutils.strtobool`
|
||||
|
||||
|
||||
### Developer infrastructure
|
||||
|
||||
- [#2612](https://github.com/sanic-org/sanic/pull/2612) Add CI testing for Python 3.11
|
||||
|
52
docs/sanic/releases/22/22.3.md
Normal file
52
docs/sanic/releases/22/22.3.md
Normal file
@ -0,0 +1,52 @@
|
||||
## Version 22.3.0
|
||||
|
||||
### Features
|
||||
- [#2347](https://github.com/sanic-org/sanic/pull/2347) API for multi-application server
|
||||
- 🚨 *BREAKING CHANGE*: The old `sanic.worker.GunicornWorker` has been **removed**. To run Sanic with `gunicorn`, you should use it thru `uvicorn` [as described in their docs](https://www.uvicorn.org/#running-with-gunicorn).
|
||||
- 🧁 *SIDE EFFECT*: Named background tasks are now supported, even in Python 3.7
|
||||
- [#2357](https://github.com/sanic-org/sanic/pull/2357) Parse `Authorization` header as `Request.credentials`
|
||||
- [#2361](https://github.com/sanic-org/sanic/pull/2361) Add config option to skip `Touchup` step in application startup
|
||||
- [#2372](https://github.com/sanic-org/sanic/pull/2372) Updates to CLI help messaging
|
||||
- [#2382](https://github.com/sanic-org/sanic/pull/2382) Downgrade warnings to backwater debug messages
|
||||
- [#2396](https://github.com/sanic-org/sanic/pull/2396) Allow for `multidict` v0.6
|
||||
- [#2401](https://github.com/sanic-org/sanic/pull/2401) Upgrade CLI catching for alternative application run types
|
||||
- [#2402](https://github.com/sanic-org/sanic/pull/2402) Conditionally inject CLI arguments into factory
|
||||
- [#2413](https://github.com/sanic-org/sanic/pull/2413) Add new start and stop event listeners to reloader process
|
||||
- [#2414](https://github.com/sanic-org/sanic/pull/2414) Remove loop as required listener arg
|
||||
- [#2415](https://github.com/sanic-org/sanic/pull/2415) Better exception for bad URL parsing
|
||||
- [sanic-routing#47](https://github.com/sanic-org/sanic-routing/pull/47) Add a new extention parameter type: `<file:ext>`, `<file:ext=jpg>`, `<file:ext=jpg|png|gif|svg>`, `<file=int:ext>`, `<file=int:ext=jpg|png|gif|svg>`, `<file=float:ext=tar.gz>`
|
||||
- 👶 *BETA FEATURE*: This feature will not work with `path` type matching, and is being released as a beta feature only.
|
||||
- [sanic-routing#57](https://github.com/sanic-org/sanic-routing/pull/57) Change `register_pattern` to accept a `str` or `Pattern`
|
||||
- [sanic-routing#58](https://github.com/sanic-org/sanic-routing/pull/58) Default matching on non-empty strings only, and new `strorempty` pattern type
|
||||
- 🚨 *BREAKING CHANGE*: Previously a route with a dynamic string parameter (`/<foo>` or `/<foo:str>`) would match on any string, including empty strings. It will now **only** match a non-empty string. To retain the old behavior, you should use the new parameter type: `/<foo:strorempty>`.
|
||||
|
||||
### Bugfixes
|
||||
- [#2373](https://github.com/sanic-org/sanic/pull/2373) Remove `error_logger` on websockets
|
||||
- [#2381](https://github.com/sanic-org/sanic/pull/2381) Fix newly assigned `None` in task registry
|
||||
- [sanic-routing#52](https://github.com/sanic-org/sanic-routing/pull/52) Add type casting to regex route matching
|
||||
- [sanic-routing#60](https://github.com/sanic-org/sanic-routing/pull/60) Add requirements check on regex routes (this resolves, for example, multiple static directories with differing `host` values)
|
||||
|
||||
### Deprecations and Removals
|
||||
- [#2362](https://github.com/sanic-org/sanic/pull/2362) 22.3 Deprecations and changes
|
||||
1. `debug=True` and `--debug` do _NOT_ automatically run `auto_reload`
|
||||
2. Default error render is with plain text (browsers still get HTML by default because `auto` looks at headers)
|
||||
3. `config` is required for `ErrorHandler.finalize`
|
||||
4. `ErrorHandler.lookup` requires two positional args
|
||||
5. Unused websocket protocol args removed
|
||||
- [#2344](https://github.com/sanic-org/sanic/pull/2344) Deprecate loading of lowercase environment variables
|
||||
|
||||
### Developer infrastructure
|
||||
- [#2363](https://github.com/sanic-org/sanic/pull/2363) Revert code coverage back to Codecov
|
||||
- [#2405](https://github.com/sanic-org/sanic/pull/2405) Upgrade tests for `sanic-routing` changes
|
||||
- [sanic-testing#35](https://github.com/sanic-org/sanic-testing/pull/35) Allow for httpx v0.22
|
||||
|
||||
### Improved Documentation
|
||||
- [#2350](https://github.com/sanic-org/sanic/pull/2350) Fix link in README for ASGI
|
||||
- [#2398](https://github.com/sanic-org/sanic/pull/2398) Document middleware on_request and on_response
|
||||
- [#2409](https://github.com/sanic-org/sanic/pull/2409) Add missing documentation for `Request.respond`
|
||||
|
||||
### Miscellaneous
|
||||
- [#2376](https://github.com/sanic-org/sanic/pull/2376) Fix typing for `ListenerMixin.listener`
|
||||
- [#2383](https://github.com/sanic-org/sanic/pull/2383) Clear deprecation warning in `asyncio.wait`
|
||||
- [#2387](https://github.com/sanic-org/sanic/pull/2387) Cleanup `__slots__` implementations
|
||||
- [#2390](https://github.com/sanic-org/sanic/pull/2390) Clear deprecation warning in `asyncio.get_event_loop`
|
54
docs/sanic/releases/22/22.6.md
Normal file
54
docs/sanic/releases/22/22.6.md
Normal file
@ -0,0 +1,54 @@
|
||||
## Version 22.6.2
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#2522](https://github.com/sanic-org/sanic/pull/2522) Always show server location in ASGI
|
||||
|
||||
## Version 22.6.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#2477](https://github.com/sanic-org/sanic/pull/2477) Sanic static directory fails when folder name ends with ".."
|
||||
|
||||
|
||||
## Version 22.6.0
|
||||
|
||||
### Features
|
||||
- [#2378](https://github.com/sanic-org/sanic/pull/2378) Introduce HTTP/3 and autogeneration of TLS certificates in `DEBUG` mode
|
||||
- 👶 *EARLY RELEASE FEATURE*: Serving Sanic over HTTP/3 is an early release feature. It does not yet fully cover the HTTP/3 spec, but instead aims for feature parity with Sanic's existing HTTP/1.1 server. Websockets, WebTransport, push responses are examples of some features not yet implemented.
|
||||
- 📦 *EXTRA REQUIREMENT*: Not all HTTP clients are capable of interfacing with HTTP/3 servers. You may need to install a [HTTP/3 capable client](https://curl.se/docs/http3.html).
|
||||
- 📦 *EXTRA REQUIREMENT*: In order to use TLS autogeneration, you must install either [mkcert](https://github.com/FiloSottile/mkcert) or [trustme](https://github.com/python-trio/trustme).
|
||||
- [#2416](https://github.com/sanic-org/sanic/pull/2416) Add message to `task.cancel`
|
||||
- [#2420](https://github.com/sanic-org/sanic/pull/2420) Add exception aliases for more consistent naming with standard HTTP response types (`BadRequest`, `MethodNotAllowed`, `RangeNotSatisfiable`)
|
||||
- [#2432](https://github.com/sanic-org/sanic/pull/2432) Expose ASGI `scope` as a property on the `Request` object
|
||||
- [#2438](https://github.com/sanic-org/sanic/pull/2438) Easier access to websocket class for annotation: `from sanic import Websocket`
|
||||
- [#2439](https://github.com/sanic-org/sanic/pull/2439) New API for reading form values with options: `Request.get_form`
|
||||
- [#2445](https://github.com/sanic-org/sanic/pull/2445) Add custom `loads` function
|
||||
- [#2447](https://github.com/sanic-org/sanic/pull/2447), [#2486](https://github.com/sanic-org/sanic/pull/2486) Improved API to support setting cache control headers
|
||||
- [#2453](https://github.com/sanic-org/sanic/pull/2453) Move verbosity filtering to logger
|
||||
- [#2475](https://github.com/sanic-org/sanic/pull/2475) Expose getter for current request using `Request.get_current()`
|
||||
|
||||
### Bugfixes
|
||||
- [#2448](https://github.com/sanic-org/sanic/pull/2448) Fix to allow running with `pythonw.exe` or places where there is no `sys.stdout`
|
||||
- [#2451](https://github.com/sanic-org/sanic/pull/2451) Trigger `http.lifecycle.request` signal in ASGI mode
|
||||
- [#2455](https://github.com/sanic-org/sanic/pull/2455) Resolve typing of stacked route definitions
|
||||
- [#2463](https://github.com/sanic-org/sanic/pull/2463) Properly catch websocket CancelledError in websocket handler in Python 3.7
|
||||
|
||||
### Deprecations and Removals
|
||||
- [#2487](https://github.com/sanic-org/sanic/pull/2487) v22.6 deprecations and changes
|
||||
1. Optional application registry
|
||||
1. Execution of custom handlers after some part of response was sent
|
||||
1. Configuring fallback handlers on the `ErrorHandler`
|
||||
1. Custom `LOGO` setting
|
||||
1. `sanic.response.stream`
|
||||
1. `AsyncioServer.init`
|
||||
|
||||
### Developer infrastructure
|
||||
- [#2449](https://github.com/sanic-org/sanic/pull/2449) Clean up `black` and `isort` config
|
||||
- [#2479](https://github.com/sanic-org/sanic/pull/2479) Fix some flappy tests
|
||||
|
||||
### Improved Documentation
|
||||
- [#2461](https://github.com/sanic-org/sanic/pull/2461) Update example to match current application naming standards
|
||||
- [#2466](https://github.com/sanic-org/sanic/pull/2466) Better type annotation for `Extend`
|
||||
- [#2485](https://github.com/sanic-org/sanic/pull/2485) Improved help messages in CLI
|
||||
|
74
docs/sanic/releases/22/22.9.md
Normal file
74
docs/sanic/releases/22/22.9.md
Normal file
@ -0,0 +1,74 @@
|
||||
## Version 22.9.1
|
||||
|
||||
### Features
|
||||
|
||||
- [#2585](https://github.com/sanic-org/sanic/pull/2585) Improved error message when no applications have been registered
|
||||
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#2578](https://github.com/sanic-org/sanic/pull/2578) Add certificate loader for in process certificate creation
|
||||
- [#2591](https://github.com/sanic-org/sanic/pull/2591) Do not use sentinel identity for `spawn` compatibility
|
||||
- [#2592](https://github.com/sanic-org/sanic/pull/2592) Fix properties in nested blueprint groups
|
||||
- [#2595](https://github.com/sanic-org/sanic/pull/2595) Introduce sleep interval on new worker reloader
|
||||
|
||||
|
||||
### Deprecations and Removals
|
||||
|
||||
|
||||
### Developer infrastructure
|
||||
|
||||
- [#2588](https://github.com/sanic-org/sanic/pull/2588) Markdown templates on issue forms
|
||||
|
||||
|
||||
### Improved Documentation
|
||||
|
||||
- [#2556](https://github.com/sanic-org/sanic/pull/2556) v22.9 documentation
|
||||
- [#2582](https://github.com/sanic-org/sanic/pull/2582) Cleanup documentation on Windows support
|
||||
|
||||
|
||||
## Version 22.9.0
|
||||
|
||||
### Features
|
||||
|
||||
- [#2445](https://github.com/sanic-org/sanic/pull/2445) Add custom loads function
|
||||
- [#2490](https://github.com/sanic-org/sanic/pull/2490) Make `WebsocketImplProtocol` async iterable
|
||||
- [#2499](https://github.com/sanic-org/sanic/pull/2499) Sanic Server WorkerManager refactor
|
||||
- [#2506](https://github.com/sanic-org/sanic/pull/2506) Use `pathlib` for path resolution (for static file serving)
|
||||
- [#2508](https://github.com/sanic-org/sanic/pull/2508) Use `path.parts` instead of `match` (for static file serving)
|
||||
- [#2513](https://github.com/sanic-org/sanic/pull/2513) Better request cancel handling
|
||||
- [#2516](https://github.com/sanic-org/sanic/pull/2516) Add request properties for HTTP method info:
|
||||
- `request.is_safe`
|
||||
- `request.is_idempotent`
|
||||
- `request.is_cacheable`
|
||||
- *See* [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) *for more information about when these apply*
|
||||
- [#2522](https://github.com/sanic-org/sanic/pull/2522) Always show server location in ASGI
|
||||
- [#2526](https://github.com/sanic-org/sanic/pull/2526) Cache control support for static files for returning 304 when appropriate
|
||||
- [#2533](https://github.com/sanic-org/sanic/pull/2533) Refactor `_static_request_handler`
|
||||
- [#2540](https://github.com/sanic-org/sanic/pull/2540) Add signals before and after handler execution
|
||||
- `http.handler.before`
|
||||
- `http.handler.after`
|
||||
- [#2542](https://github.com/sanic-org/sanic/pull/2542) Add *[redacted]* to CLI :)
|
||||
- [#2546](https://github.com/sanic-org/sanic/pull/2546) Add deprecation warning filter
|
||||
- [#2550](https://github.com/sanic-org/sanic/pull/2550) Middleware priority and performance enhancements
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- [#2495](https://github.com/sanic-org/sanic/pull/2495) Prevent directory traversion with static files
|
||||
- [#2515](https://github.com/sanic-org/sanic/pull/2515) Do not apply double slash to paths in certain static dirs in Blueprints
|
||||
|
||||
### Deprecations and Removals
|
||||
|
||||
- [#2525](https://github.com/sanic-org/sanic/pull/2525) Warn on duplicate route names, will be prevented outright in v23.3
|
||||
- [#2537](https://github.com/sanic-org/sanic/pull/2537) Raise warning and deprecation notice on duplicate exceptions, will be prevented outright in v23.3
|
||||
|
||||
### Developer infrastructure
|
||||
|
||||
- [#2504](https://github.com/sanic-org/sanic/pull/2504) Cleanup test suite
|
||||
- [#2505](https://github.com/sanic-org/sanic/pull/2505) Replace Unsupported Python Version Number from the Contributing Doc
|
||||
- [#2530](https://github.com/sanic-org/sanic/pull/2530) Do not include tests folder in installed package resolver
|
||||
|
||||
### Improved Documentation
|
||||
|
||||
- [#2502](https://github.com/sanic-org/sanic/pull/2502) Fix a few typos
|
||||
- [#2517](https://github.com/sanic-org/sanic/pull/2517) [#2536](https://github.com/sanic-org/sanic/pull/2536) Add some type hints
|
53
docs/sanic/releases/23/23.3.md
Normal file
53
docs/sanic/releases/23/23.3.md
Normal file
@ -0,0 +1,53 @@
|
||||
## Version 23.3.0
|
||||
|
||||
### Features
|
||||
- [#2545](https://github.com/sanic-org/sanic/pull/2545) Standardize init of exceptions for more consistent control of HTTP responses using exceptions
|
||||
- [#2606](https://github.com/sanic-org/sanic/pull/2606) Decode headers as UTF-8 also in ASGI
|
||||
- [#2646](https://github.com/sanic-org/sanic/pull/2646) Separate ASGI request and lifespan callables
|
||||
- [#2659](https://github.com/sanic-org/sanic/pull/2659) Use ``FALLBACK_ERROR_FORMAT`` for handlers that return ``empty()``
|
||||
- [#2662](https://github.com/sanic-org/sanic/pull/2662) Add basic file browser (HTML page) and auto-index serving
|
||||
- [#2667](https://github.com/sanic-org/sanic/pull/2667) Nicer traceback formatting (HTML page)
|
||||
- [#2668](https://github.com/sanic-org/sanic/pull/2668) Smarter error page rendering format selection; more reliant upon header and "common sense" defaults
|
||||
- [#2680](https://github.com/sanic-org/sanic/pull/2680) Check the status of socket before shutting down with ``SHUT_RDWR``
|
||||
- [#2687](https://github.com/sanic-org/sanic/pull/2687) Refresh ``Request.accept`` functionality to be more performant and spec-compliant
|
||||
- [#2696](https://github.com/sanic-org/sanic/pull/2696) Add header accessors as properties
|
||||
```
|
||||
Example-Field: Foo, Bar
|
||||
Example-Field: Baz
|
||||
```
|
||||
```python
|
||||
request.headers.example_field == "Foo, Bar,Baz"
|
||||
```
|
||||
- [#2700](https://github.com/sanic-org/sanic/pull/2700) Simpler CLI targets
|
||||
|
||||
```sh
|
||||
$ sanic path.to.module:app # global app instance
|
||||
$ sanic path.to.module:create_app # factory pattern
|
||||
$ sanic ./path/to/directory/ # simple serve
|
||||
```
|
||||
- [#2701](https://github.com/sanic-org/sanic/pull/2701) API to define a number of workers in managed processes
|
||||
- [#2704](https://github.com/sanic-org/sanic/pull/2704) Add convenience for dynamic changes to routing
|
||||
- [#2706](https://github.com/sanic-org/sanic/pull/2706) Add convenience methods for cookie creation and deletion
|
||||
|
||||
```python
|
||||
response = text("...")
|
||||
response.add_cookie("test", "It worked!", domain=".yummy-yummy-cookie.com")
|
||||
```
|
||||
- [#2707](https://github.com/sanic-org/sanic/pull/2707) Simplified ``parse_content_header`` escaping to be RFC-compliant and remove outdated FF hack
|
||||
- [#2710](https://github.com/sanic-org/sanic/pull/2710) Stricter charset handling and escaping of request URLs
|
||||
- [#2711](https://github.com/sanic-org/sanic/pull/2711) Consume body on ``DELETE`` by default
|
||||
- [#2719](https://github.com/sanic-org/sanic/pull/2719) Allow ``password`` to be passed to TLS context
|
||||
- [#2720](https://github.com/sanic-org/sanic/pull/2720) Skip middleware on ``RequestCancelled``
|
||||
- [#2721](https://github.com/sanic-org/sanic/pull/2721) Change access logging format to ``%s``
|
||||
- [#2722](https://github.com/sanic-org/sanic/pull/2722) Add ``CertLoader`` as application option for directly controlling ``SSLContext`` objects
|
||||
- [#2725](https://github.com/sanic-org/sanic/pull/2725) Worker sync state tolerance on race condition
|
||||
|
||||
### Bugfixes
|
||||
- [#2651](https://github.com/sanic-org/sanic/pull/2651) ASGI websocket to pass thru bytes as is
|
||||
- [#2697](https://github.com/sanic-org/sanic/pull/2697) Fix comparison between datetime aware and naive in ``file`` when using ``If-Modified-Since``
|
||||
|
||||
### Deprecations and Removals
|
||||
- [#2666](https://github.com/sanic-org/sanic/pull/2666) Remove deprecated ``__blueprintname__`` property
|
||||
|
||||
### Improved Documentation
|
||||
- [#2712](https://github.com/sanic-org/sanic/pull/2712) Improved example using ``'https'`` to create the redirect
|
33
docs/sanic/releases/23/23.6.md
Normal file
33
docs/sanic/releases/23/23.6.md
Normal file
@ -0,0 +1,33 @@
|
||||
## Version 23.6.0 🔶
|
||||
|
||||
### Features
|
||||
- [#2670](https://github.com/sanic-org/sanic/pull/2670) Increase `KEEP_ALIVE_TIMEOUT` default to 120 seconds
|
||||
- [#2716](https://github.com/sanic-org/sanic/pull/2716) Adding allow route overwrite option in blueprint
|
||||
- [#2724](https://github.com/sanic-org/sanic/pull/2724) and [#2792](https://github.com/sanic-org/sanic/pull/2792) Add a new exception signal for ALL exceptions raised anywhere in application
|
||||
- [#2727](https://github.com/sanic-org/sanic/pull/2727) Add name prefixing to BP groups
|
||||
- [#2754](https://github.com/sanic-org/sanic/pull/2754) Update request type on middleware types
|
||||
- [#2770](https://github.com/sanic-org/sanic/pull/2770) Better exception message on startup time application induced import error
|
||||
- [#2776](https://github.com/sanic-org/sanic/pull/2776) Set multiprocessing start method early
|
||||
- [#2785](https://github.com/sanic-org/sanic/pull/2785) Add custom typing to config and ctx objects
|
||||
- [#2790](https://github.com/sanic-org/sanic/pull/2790) Add `request.client_ip`
|
||||
|
||||
### Bugfixes
|
||||
- [#2728](https://github.com/sanic-org/sanic/pull/2728) Fix traversals for intended results
|
||||
- [#2729](https://github.com/sanic-org/sanic/pull/2729) Handle case when headers argument of ResponseStream constructor is None
|
||||
- [#2737](https://github.com/sanic-org/sanic/pull/2737) Fix type annotation for `JSONREsponse` default content type
|
||||
- [#2740](https://github.com/sanic-org/sanic/pull/2740) Use Sanic's serializer for JSON responses in the Inspector
|
||||
- [#2760](https://github.com/sanic-org/sanic/pull/2760) Support for `Request.get_current` in ASGI mode
|
||||
- [#2773](https://github.com/sanic-org/sanic/pull/2773) Alow Blueprint routes to explicitly define error_format
|
||||
- [#2774](https://github.com/sanic-org/sanic/pull/2774) Resolve headers on different renderers
|
||||
- [#2782](https://github.com/sanic-org/sanic/pull/2782) Resolve pypy compatibility issues
|
||||
|
||||
### Deprecations and Removals
|
||||
- [#2777](https://github.com/sanic-org/sanic/pull/2777) Remove Python 3.7 support
|
||||
|
||||
### Developer infrastructure
|
||||
- [#2766](https://github.com/sanic-org/sanic/pull/2766) Unpin setuptools version
|
||||
- [#2779](https://github.com/sanic-org/sanic/pull/2779) Run keep alive tests in loop to get available port
|
||||
|
||||
### Improved Documentation
|
||||
- [#2741](https://github.com/sanic-org/sanic/pull/2741) Better documentation examples about running Sanic
|
||||
From that list, the items to highlight in the release notes:
|
@ -1,11 +1,8 @@
|
||||
FROM python:3.5
|
||||
MAINTAINER Channel Cat <channelcat@gmail.com>
|
||||
FROM sanicframework/sanic:LTS
|
||||
|
||||
ADD . /code
|
||||
RUN pip3 install git+https://github.com/channelcat/sanic
|
||||
RUN mkdir /srv
|
||||
COPY . /srv
|
||||
|
||||
EXPOSE 8000
|
||||
WORKDIR /srv
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
CMD ["python", "simple_server.py"]
|
||||
CMD ["sanic", "simple_server.app"]
|
||||
|
19
examples/add_task_sanic.py
Normal file
19
examples/add_task_sanic.py
Normal file
@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import asyncio
|
||||
|
||||
from sanic import Sanic
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
async def notify_server_started_after_five_seconds():
|
||||
await asyncio.sleep(5)
|
||||
print("Server successfully started!")
|
||||
|
||||
|
||||
app.add_task(notify_server_started_after_five_seconds())
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
29
examples/amending_request_object.py
Normal file
29
examples/amending_request_object.py
Normal file
@ -0,0 +1,29 @@
|
||||
from random import randint
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.response import text
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.middleware("request")
|
||||
def append_request(request):
|
||||
request.ctx.num = randint(0, 100)
|
||||
|
||||
|
||||
@app.get("/pop")
|
||||
def pop_handler(request):
|
||||
return text(request.ctx.num)
|
||||
|
||||
|
||||
@app.get("/key_exist")
|
||||
def key_exist_handler(request):
|
||||
# Check the key is exist or not
|
||||
if hasattr(request.ctx, "num"):
|
||||
return text("num exist in request")
|
||||
|
||||
return text("num does not exist in request")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
44
examples/authorized_sanic.py
Normal file
44
examples/authorized_sanic.py
Normal file
@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from functools import wraps
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
def check_request_for_authorization_status(request):
|
||||
# Note: Define your check, for instance cookie, session.
|
||||
flag = True
|
||||
return flag
|
||||
|
||||
|
||||
def authorized(f):
|
||||
@wraps(f)
|
||||
async def decorated_function(request, *args, **kwargs):
|
||||
# run some method that checks the request
|
||||
# for the client's authorization status
|
||||
is_authorized = check_request_for_authorization_status(request)
|
||||
|
||||
if is_authorized:
|
||||
# the user is authorized.
|
||||
# run the handler method and return the response
|
||||
response = await f(request, *args, **kwargs)
|
||||
return response
|
||||
else:
|
||||
# the user is not authorized.
|
||||
return json({"status": "not_authorized"}, 403)
|
||||
|
||||
return decorated_function
|
||||
|
||||
|
||||
@app.route("/")
|
||||
@authorized
|
||||
async def test(request):
|
||||
return json({"status": "authorized"})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
54
examples/blueprint_middlware_execution_order.py
Normal file
54
examples/blueprint_middlware_execution_order.py
Normal file
@ -0,0 +1,54 @@
|
||||
from sanic import Blueprint, Sanic
|
||||
from sanic.response import text
|
||||
|
||||
|
||||
"""
|
||||
Demonstrates that blueprint request middleware are executed in the order they
|
||||
are added. And blueprint response middleware are executed in _reverse_ order.
|
||||
On a valid request, it should print "1 2 3 6 5 4" to terminal
|
||||
"""
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
bp = Blueprint("bp_example")
|
||||
|
||||
|
||||
@bp.on_request
|
||||
def request_middleware_1(request):
|
||||
print("1")
|
||||
|
||||
|
||||
@bp.on_request
|
||||
def request_middleware_2(request):
|
||||
print("2")
|
||||
|
||||
|
||||
@bp.on_request
|
||||
def request_middleware_3(request):
|
||||
print("3")
|
||||
|
||||
|
||||
@bp.on_response
|
||||
def resp_middleware_4(request, response):
|
||||
print("4")
|
||||
|
||||
|
||||
@bp.on_response
|
||||
def resp_middleware_5(request, response):
|
||||
print("5")
|
||||
|
||||
|
||||
@bp.on_response
|
||||
def resp_middleware_6(request, response):
|
||||
print("6")
|
||||
|
||||
|
||||
@bp.route("/")
|
||||
def pop_handler(request):
|
||||
return text("hello world")
|
||||
|
||||
|
||||
app.blueprint(bp, url_prefix="/bp")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000, debug=True, auto_reload=False)
|
@ -1,24 +1,41 @@
|
||||
from sanic import Sanic
|
||||
from sanic import Blueprint
|
||||
from sanic.response import json, text
|
||||
from sanic import Blueprint, Sanic
|
||||
from sanic.response import file, json
|
||||
|
||||
|
||||
app = Sanic(__name__)
|
||||
blueprint = Blueprint('name', url_prefix='/my_blueprint')
|
||||
blueprint2 = Blueprint('name', url_prefix='/my_blueprint2')
|
||||
app = Sanic("Example")
|
||||
blueprint = Blueprint("bp_example", url_prefix="/my_blueprint")
|
||||
blueprint2 = Blueprint("bp_example2", url_prefix="/my_blueprint2")
|
||||
blueprint3 = Blueprint("bp_example3", url_prefix="/my_blueprint3")
|
||||
|
||||
|
||||
@blueprint.route('/foo')
|
||||
@blueprint.route("/foo")
|
||||
async def foo(request):
|
||||
return json({'msg': 'hi from blueprint'})
|
||||
return json({"msg": "hi from blueprint"})
|
||||
|
||||
|
||||
@blueprint2.route('/foo')
|
||||
@blueprint2.route("/foo")
|
||||
async def foo2(request):
|
||||
return json({'msg': 'hi from blueprint2'})
|
||||
return json({"msg": "hi from blueprint2"})
|
||||
|
||||
|
||||
app.register_blueprint(blueprint)
|
||||
app.register_blueprint(blueprint2)
|
||||
@blueprint3.route("/foo")
|
||||
async def index(request):
|
||||
return await file("websocket.html")
|
||||
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
||||
|
||||
@app.websocket("/feed")
|
||||
async def foo3(request, ws):
|
||||
while True:
|
||||
data = "hello!"
|
||||
print("Sending: " + data)
|
||||
await ws.send(data)
|
||||
data = await ws.recv()
|
||||
print("Received: " + data)
|
||||
|
||||
|
||||
app.blueprint(blueprint)
|
||||
app.blueprint(blueprint2)
|
||||
app.blueprint(blueprint3)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=9999, debug=True)
|
||||
|
22
examples/delayed_response.py
Normal file
22
examples/delayed_response.py
Normal file
@ -0,0 +1,22 @@
|
||||
from asyncio import sleep
|
||||
|
||||
from sanic import Sanic, response
|
||||
|
||||
|
||||
app = Sanic("DelayedResponseApp", strict_slashes=True)
|
||||
app.config.AUTO_EXTEND = False
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def handler(request):
|
||||
return response.redirect("/sleep/3")
|
||||
|
||||
|
||||
@app.get("/sleep/<t:float>")
|
||||
async def handler2(request, t=0.3):
|
||||
await sleep(t)
|
||||
return response.text(f"Slept {t:.1f} seconds.\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
55
examples/exception_monitoring.py
Normal file
55
examples/exception_monitoring.py
Normal file
@ -0,0 +1,55 @@
|
||||
"""
|
||||
Example intercepting uncaught exceptions using Sanic's error handler framework.
|
||||
This may be useful for developers wishing to use Sentry, Airbrake, etc.
|
||||
or a custom system to log and monitor unexpected errors in production.
|
||||
First we create our own class inheriting from Handler in sanic.exceptions,
|
||||
and pass in an instance of it when we create our Sanic instance. Inside this
|
||||
class' default handler, we can do anything including sending exceptions to
|
||||
an external service.
|
||||
"""
|
||||
from sanic.exceptions import SanicException
|
||||
from sanic.handlers import ErrorHandler
|
||||
|
||||
|
||||
"""
|
||||
Imports and code relevant for our CustomHandler class
|
||||
(Ordinarily this would be in a separate file)
|
||||
"""
|
||||
|
||||
|
||||
class CustomHandler(ErrorHandler):
|
||||
def default(self, request, exception):
|
||||
# Here, we have access to the exception object
|
||||
# and can do anything with it (log, send to external service, etc)
|
||||
|
||||
# Some exceptions are trivial and built into Sanic (404s, etc)
|
||||
if not isinstance(exception, SanicException):
|
||||
print(exception)
|
||||
|
||||
# Then, we must finish handling the exception by returning
|
||||
# our response to the client
|
||||
# For this we can just call the super class' default handler
|
||||
return super().default(request, exception)
|
||||
|
||||
|
||||
"""
|
||||
This is an ordinary Sanic server, with the exception that we set the
|
||||
server's error_handler to an instance of our CustomHandler
|
||||
"""
|
||||
|
||||
from sanic import Sanic
|
||||
|
||||
|
||||
handler = CustomHandler()
|
||||
app = Sanic("Example", error_handler=handler)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
# Here, something occurs which causes an unexpected exception
|
||||
# This exception will flow to our custom handler.
|
||||
raise SanicException("You Broke It!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
13
examples/hello_world.py
Normal file
13
examples/hello_world.py
Normal file
@ -0,0 +1,13 @@
|
||||
from sanic import Sanic, response
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
return response.json({"test": True})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
73
examples/http_redirect.py
Normal file
73
examples/http_redirect.py
Normal file
@ -0,0 +1,73 @@
|
||||
from sanic import Sanic, response, text
|
||||
from sanic.handlers import ErrorHandler
|
||||
from sanic.server.async_server import AsyncioServer
|
||||
|
||||
|
||||
HTTP_PORT = 9999
|
||||
HTTPS_PORT = 8888
|
||||
|
||||
http = Sanic("http")
|
||||
http.config.SERVER_NAME = f"localhost:{HTTP_PORT}"
|
||||
https = Sanic("https")
|
||||
https.config.SERVER_NAME = f"localhost:{HTTPS_PORT}"
|
||||
|
||||
|
||||
@https.get("/foo")
|
||||
def foo(request):
|
||||
return text("foo")
|
||||
|
||||
|
||||
@https.get("/bar")
|
||||
def bar(request):
|
||||
return text("bar")
|
||||
|
||||
|
||||
@http.get("/<path:path>")
|
||||
def proxy(request, path):
|
||||
url = request.app.url_for(
|
||||
"proxy",
|
||||
path=path,
|
||||
_server=https.config.SERVER_NAME,
|
||||
_external=True,
|
||||
_scheme="https",
|
||||
)
|
||||
return response.redirect(url)
|
||||
|
||||
|
||||
@https.main_process_start
|
||||
async def start(app, _):
|
||||
http_server = await http.create_server(
|
||||
port=HTTP_PORT, return_asyncio_server=True
|
||||
)
|
||||
app.add_task(runner(http, http_server))
|
||||
app.ctx.http_server = http_server
|
||||
app.ctx.http = http
|
||||
|
||||
|
||||
@https.main_process_stop
|
||||
async def stop(app, _):
|
||||
await app.ctx.http_server.before_stop()
|
||||
await app.ctx.http_server.close()
|
||||
for connection in app.ctx.http_server.connections:
|
||||
connection.close_if_idle()
|
||||
await app.ctx.http_server.after_stop()
|
||||
app.ctx.http = False
|
||||
|
||||
|
||||
async def runner(app: Sanic, app_server: AsyncioServer):
|
||||
app.is_running = True
|
||||
try:
|
||||
app.signalize()
|
||||
app.finalize()
|
||||
ErrorHandler.finalize(app.error_handler)
|
||||
app_server.init = True
|
||||
|
||||
await app_server.before_start()
|
||||
await app_server.after_start()
|
||||
await app_server.serve_forever()
|
||||
finally:
|
||||
app.is_running = False
|
||||
app.is_stopping = True
|
||||
|
||||
if __name__ == "__main__":
|
||||
https.run(port=HTTPS_PORT, debug=True)
|
43
examples/limit_concurrency.py
Normal file
43
examples/limit_concurrency.py
Normal file
@ -0,0 +1,43 @@
|
||||
import asyncio
|
||||
|
||||
import httpx
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
sem = None
|
||||
|
||||
|
||||
@app.before_server_start
|
||||
def init(sanic, _):
|
||||
global sem
|
||||
concurrency_per_worker = 4
|
||||
sem = asyncio.Semaphore(concurrency_per_worker)
|
||||
|
||||
|
||||
async def bounded_fetch(session, url):
|
||||
"""
|
||||
Use session object to perform 'get' request on url
|
||||
"""
|
||||
async with sem:
|
||||
response = await session.get(url)
|
||||
return response.json()
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
"""
|
||||
Download and serve example JSON
|
||||
"""
|
||||
url = "https://api.github.com/repos/sanic-org/sanic"
|
||||
|
||||
async with httpx.AsyncClient() as session:
|
||||
response = await bounded_fetch(session, url)
|
||||
return json(response)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000, workers=2)
|
74
examples/log_request_id.py
Normal file
74
examples/log_request_id.py
Normal file
@ -0,0 +1,74 @@
|
||||
import logging
|
||||
|
||||
from contextvars import ContextVar
|
||||
|
||||
from sanic import Sanic, response
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RequestIdFilter(logging.Filter):
|
||||
def filter(self, record):
|
||||
try:
|
||||
record.request_id = app.ctx.request_id.get(None) or "n/a"
|
||||
except AttributeError:
|
||||
record.request_id = "n/a"
|
||||
return True
|
||||
|
||||
|
||||
LOG_SETTINGS = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": False,
|
||||
"handlers": {
|
||||
"console": {
|
||||
"class": "logging.StreamHandler",
|
||||
"level": "DEBUG",
|
||||
"formatter": "default",
|
||||
"filters": ["requestid"],
|
||||
},
|
||||
},
|
||||
"filters": {
|
||||
"requestid": {
|
||||
"()": RequestIdFilter,
|
||||
},
|
||||
},
|
||||
"formatters": {
|
||||
"default": {
|
||||
"format": "%(asctime)s %(levelname)s %(name)s:%(lineno)d %(request_id)s | %(message)s",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"": {"level": "DEBUG", "handlers": ["console"], "propagate": True},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
app = Sanic("Example", log_config=LOG_SETTINGS)
|
||||
|
||||
|
||||
@app.on_request
|
||||
async def set_request_id(request):
|
||||
request.app.ctx.request_id.set(request.id)
|
||||
log.info(f"Setting {request.id=}")
|
||||
|
||||
|
||||
@app.on_response
|
||||
async def set_request_header(request, response):
|
||||
response.headers["X-Request-ID"] = request.id
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
log.debug("X-Request-ID: %s", request.id)
|
||||
log.info("Hello from test!")
|
||||
return response.json({"test": True})
|
||||
|
||||
|
||||
@app.before_server_start
|
||||
def setup(app, loop):
|
||||
app.ctx.request_id = ContextVar("request_id")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(port=9999, debug=True)
|
60
examples/logdna_example.py
Normal file
60
examples/logdna_example.py
Normal file
@ -0,0 +1,60 @@
|
||||
import logging
|
||||
import socket
|
||||
|
||||
from os import getenv
|
||||
from platform import node
|
||||
from uuid import getnode as get_mac
|
||||
|
||||
from logdna import LogDNAHandler
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.request import Request
|
||||
from sanic.response import json
|
||||
|
||||
|
||||
log = logging.getLogger("logdna")
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
|
||||
def get_my_ip_address(remote_server="google.com"):
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
|
||||
s.connect((remote_server, 80))
|
||||
return s.getsockname()[0]
|
||||
|
||||
|
||||
def get_mac_address():
|
||||
h = iter(hex(get_mac())[2:].zfill(12))
|
||||
return ":".join(i + next(h) for i in h)
|
||||
|
||||
|
||||
logdna_options = {
|
||||
"app": __name__,
|
||||
"index_meta": True,
|
||||
"hostname": node(),
|
||||
"ip": get_my_ip_address(),
|
||||
"mac": get_mac_address(),
|
||||
}
|
||||
|
||||
logdna_handler = LogDNAHandler(
|
||||
getenv("LOGDNA_API_KEY"), options=logdna_options
|
||||
)
|
||||
|
||||
logdna = logging.getLogger(__name__)
|
||||
logdna.setLevel(logging.INFO)
|
||||
logdna.addHandler(logdna_handler)
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.middleware
|
||||
def log_request(request: Request):
|
||||
logdna.info("I was Here with a new Request to URL: {}".format(request.url))
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def default(request):
|
||||
return json({"response": "I was here"})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=getenv("PORT", 8080))
|
30
examples/modify_header_example.py
Normal file
30
examples/modify_header_example.py
Normal file
@ -0,0 +1,30 @@
|
||||
"""
|
||||
Modify header or status in response
|
||||
"""
|
||||
|
||||
from sanic import Sanic, response
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def handle_request(request):
|
||||
return response.json(
|
||||
{"message": "Hello world!"},
|
||||
headers={"X-Served-By": "sanic"},
|
||||
status=200,
|
||||
)
|
||||
|
||||
|
||||
@app.route("/unauthorized")
|
||||
def handle_request(request):
|
||||
return response.json(
|
||||
{"message": "You are not authorized"},
|
||||
headers={"X-Served-By": "sanic"},
|
||||
status=404,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
24
examples/override_logging.py
Normal file
24
examples/override_logging.py
Normal file
@ -0,0 +1,24 @@
|
||||
import logging
|
||||
|
||||
from sanic import Sanic, text
|
||||
|
||||
|
||||
logging_format = "[%(asctime)s] %(process)d-%(levelname)s "
|
||||
logging_format += "%(module)s::%(funcName)s():l%(lineno)d: "
|
||||
logging_format += "%(message)s"
|
||||
|
||||
logging.basicConfig(format=logging_format, level=logging.DEBUG)
|
||||
log = logging.getLogger()
|
||||
|
||||
# Set logger to override default basicConfig
|
||||
app = Sanic("app")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def test(request):
|
||||
log.info("received request; responding with 'hey'")
|
||||
return text("hey")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
53
examples/pytest_xdist.py
Normal file
53
examples/pytest_xdist.py
Normal file
@ -0,0 +1,53 @@
|
||||
"""pytest-xdist example for sanic server
|
||||
|
||||
Install testing tools:
|
||||
|
||||
$ pip install pytest pytest-xdist
|
||||
|
||||
Run with xdist params:
|
||||
|
||||
$ pytest examples/pytest_xdist.py -n 8 # 8 workers
|
||||
"""
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from sanic_testing import SanicTestClient
|
||||
from sanic_testing.testing import PORT as PORT_BASE
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.response import text
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def test_port(worker_id):
|
||||
m = re.search(r"[0-9]+", worker_id)
|
||||
if m:
|
||||
num_id = m.group(0)
|
||||
else:
|
||||
num_id = 0
|
||||
port = PORT_BASE + int(num_id)
|
||||
return port
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def app():
|
||||
app = Sanic("Example")
|
||||
|
||||
@app.route("/")
|
||||
async def index(request):
|
||||
return text("OK")
|
||||
|
||||
return app
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def client(app, test_port):
|
||||
return SanicTestClient(app, test_port)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("run_id", range(100))
|
||||
def test_index(client, run_id):
|
||||
request, response = client._sanic_endpoint_test("get", "/")
|
||||
assert response.status == 200
|
||||
assert response.text == "OK"
|
33
examples/raygun_example.py
Normal file
33
examples/raygun_example.py
Normal file
@ -0,0 +1,33 @@
|
||||
from os import getenv
|
||||
|
||||
from raygun4py.raygunprovider import RaygunSender
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.exceptions import SanicException
|
||||
from sanic.handlers import ErrorHandler
|
||||
|
||||
|
||||
class RaygunExceptionReporter(ErrorHandler):
|
||||
def __init__(self, raygun_api_key=None):
|
||||
super().__init__()
|
||||
if raygun_api_key is None:
|
||||
raygun_api_key = getenv("RAYGUN_API_KEY")
|
||||
|
||||
self.sender = RaygunSender(raygun_api_key)
|
||||
|
||||
def default(self, request, exception):
|
||||
self.sender.send_exception(exception=exception)
|
||||
return super().default(request, exception)
|
||||
|
||||
|
||||
raygun_error_reporter = RaygunExceptionReporter()
|
||||
app = Sanic("Example", error_handler=raygun_error_reporter)
|
||||
|
||||
|
||||
@app.route("/raise")
|
||||
async def test(request):
|
||||
raise SanicException("You Broke It!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=getenv("PORT", 8080))
|
18
examples/redirect_example.py
Normal file
18
examples/redirect_example.py
Normal file
@ -0,0 +1,18 @@
|
||||
from sanic import Sanic, response
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def handle_request(request):
|
||||
return response.redirect("/redirect")
|
||||
|
||||
|
||||
@app.route("/redirect")
|
||||
async def test(request):
|
||||
return response.json({"Redirected": True})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
10
examples/request_stream/client.py
Normal file
10
examples/request_stream/client.py
Normal file
@ -0,0 +1,10 @@
|
||||
import requests
|
||||
|
||||
# Warning: This is a heavy process.
|
||||
|
||||
data = ""
|
||||
for i in range(1, 250000):
|
||||
data += str(i)
|
||||
|
||||
r = requests.post("http://0.0.0.0:8000/stream", data=data)
|
||||
print(r.text)
|
63
examples/request_stream/server.py
Normal file
63
examples/request_stream/server.py
Normal file
@ -0,0 +1,63 @@
|
||||
from sanic import Sanic
|
||||
from sanic.blueprints import Blueprint
|
||||
from sanic.response import stream, text
|
||||
from sanic.views import HTTPMethodView
|
||||
from sanic.views import stream as stream_decorator
|
||||
|
||||
|
||||
bp = Blueprint("bp_example")
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
class SimpleView(HTTPMethodView):
|
||||
@stream_decorator
|
||||
async def post(self, request):
|
||||
result = ""
|
||||
while True:
|
||||
body = await request.stream.get()
|
||||
if body is None:
|
||||
break
|
||||
result += body.decode("utf-8")
|
||||
return text(result)
|
||||
|
||||
|
||||
@app.post("/stream", stream=True)
|
||||
async def handler(request):
|
||||
async def streaming(response):
|
||||
while True:
|
||||
body = await request.stream.get()
|
||||
if body is None:
|
||||
break
|
||||
body = body.decode("utf-8").replace("1", "A")
|
||||
await response.write(body)
|
||||
|
||||
return stream(streaming)
|
||||
|
||||
|
||||
@bp.put("/bp_stream", stream=True)
|
||||
async def bp_handler(request):
|
||||
result = ""
|
||||
while True:
|
||||
body = await request.stream.get()
|
||||
if body is None:
|
||||
break
|
||||
result += body.decode("utf-8").replace("1", "A")
|
||||
return text(result)
|
||||
|
||||
|
||||
async def post_handler(request):
|
||||
result = ""
|
||||
while True:
|
||||
body = await request.stream.get()
|
||||
if body is None:
|
||||
break
|
||||
result += body.decode("utf-8")
|
||||
return text(result)
|
||||
|
||||
|
||||
app.blueprint(bp)
|
||||
app.add_route(SimpleView.as_view(), "/method_view")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
24
examples/request_timeout.py
Normal file
24
examples/request_timeout.py
Normal file
@ -0,0 +1,24 @@
|
||||
import asyncio
|
||||
|
||||
from sanic import Sanic, response
|
||||
from sanic.config import Config
|
||||
from sanic.exceptions import RequestTimeout
|
||||
|
||||
|
||||
Config.REQUEST_TIMEOUT = 1
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
await asyncio.sleep(3)
|
||||
return response.text("Hello, world!")
|
||||
|
||||
|
||||
@app.exception(RequestTimeout)
|
||||
def timeout(request, exception):
|
||||
return response.text("RequestTimeout from error_handler.", 408)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000)
|
28
examples/rollbar_example.py
Normal file
28
examples/rollbar_example.py
Normal file
@ -0,0 +1,28 @@
|
||||
from os import getenv
|
||||
|
||||
import rollbar
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.exceptions import SanicException
|
||||
from sanic.handlers import ErrorHandler
|
||||
|
||||
|
||||
rollbar.init(getenv("ROLLBAR_API_KEY"))
|
||||
|
||||
|
||||
class RollbarExceptionHandler(ErrorHandler):
|
||||
def default(self, request, exception):
|
||||
rollbar.report_message(str(exception))
|
||||
return super().default(request, exception)
|
||||
|
||||
|
||||
app = Sanic("Example", error_handler=RollbarExceptionHandler())
|
||||
|
||||
|
||||
@app.route("/raise")
|
||||
def create_error(request):
|
||||
raise SanicException("I was here and I don't like where I am")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=getenv("PORT", 8080))
|
89
examples/run_asgi.py
Normal file
89
examples/run_asgi.py
Normal file
@ -0,0 +1,89 @@
|
||||
"""
|
||||
1. Create a simple Sanic app
|
||||
0. Run with an ASGI server:
|
||||
$ uvicorn run_asgi:app
|
||||
or
|
||||
$ hypercorn run_asgi:app
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from sanic import Sanic, response
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.route("/text")
|
||||
def handler_text(request):
|
||||
return response.text("Hello")
|
||||
|
||||
|
||||
@app.route("/json")
|
||||
def handler_json(request):
|
||||
return response.json({"foo": "bar"})
|
||||
|
||||
|
||||
@app.websocket("/ws")
|
||||
async def handler_ws(request, ws):
|
||||
name = "<someone>"
|
||||
while True:
|
||||
data = f"Hello {name}"
|
||||
await ws.send(data)
|
||||
name = await ws.recv()
|
||||
|
||||
if not name:
|
||||
break
|
||||
|
||||
|
||||
@app.route("/file")
|
||||
async def handler_file(request):
|
||||
return await response.file(Path("../") / "setup.py")
|
||||
|
||||
|
||||
@app.route("/file_stream")
|
||||
async def handler_file_stream(request):
|
||||
return await response.file_stream(
|
||||
Path("../") / "setup.py", chunk_size=1024
|
||||
)
|
||||
|
||||
|
||||
@app.post("/stream", stream=True)
|
||||
async def handler_stream(request):
|
||||
while True:
|
||||
body = await request.stream.read()
|
||||
if body is None:
|
||||
break
|
||||
body = body.decode("utf-8").replace("1", "A")
|
||||
await response.write(body)
|
||||
return response.stream(body)
|
||||
|
||||
|
||||
@app.before_server_start
|
||||
async def listener_before_server_start(*args, **kwargs):
|
||||
print("before_server_start")
|
||||
|
||||
|
||||
@app.after_server_start
|
||||
async def listener_after_server_start(*args, **kwargs):
|
||||
print("after_server_start")
|
||||
|
||||
|
||||
@app.before_server_stop
|
||||
async def listener_before_server_stop(*args, **kwargs):
|
||||
print("before_server_stop")
|
||||
|
||||
|
||||
@app.after_server_stop
|
||||
async def listener_after_server_stop(*args, **kwargs):
|
||||
print("after_server_stop")
|
||||
|
||||
|
||||
@app.on_request
|
||||
async def print_on_request(request):
|
||||
print("print_on_request")
|
||||
|
||||
|
||||
@app.on_response
|
||||
async def print_on_response(request, response):
|
||||
print("print_on_response")
|
30
examples/run_async.py
Normal file
30
examples/run_async.py
Normal file
@ -0,0 +1,30 @@
|
||||
import asyncio
|
||||
|
||||
import uvloop
|
||||
|
||||
from sanic import Sanic, response
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
return response.json({"answer": "42"})
|
||||
|
||||
|
||||
async def main():
|
||||
server = await app.create_server(
|
||||
port=8000, host="0.0.0.0", return_asyncio_server=True
|
||||
)
|
||||
|
||||
if server is None:
|
||||
return
|
||||
|
||||
await server.startup()
|
||||
await server.serve_forever()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.set_event_loop(uvloop.new_event_loop())
|
||||
asyncio.run(main())
|
68
examples/run_async_advanced.py
Normal file
68
examples/run_async_advanced.py
Normal file
@ -0,0 +1,68 @@
|
||||
import asyncio
|
||||
|
||||
from signal import SIGINT, signal
|
||||
|
||||
import uvloop
|
||||
|
||||
from sanic import Sanic, response
|
||||
from sanic.server import AsyncioServer
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
@app.before_server_start
|
||||
async def before_server_start(app, loop):
|
||||
print("Async Server starting")
|
||||
|
||||
|
||||
@app.after_server_start
|
||||
async def after_server_start(app, loop):
|
||||
print("Async Server started")
|
||||
|
||||
|
||||
@app.before_server_stop
|
||||
async def before_server_stop(app, loop):
|
||||
print("Async Server stopping")
|
||||
|
||||
|
||||
@app.after_server_stop
|
||||
async def after_server_stop(app, loop):
|
||||
print("Async Server stopped")
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
return response.json({"answer": "42"})
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.set_event_loop(uvloop.new_event_loop())
|
||||
serv_coro = app.create_server(
|
||||
host="0.0.0.0", port=8000, return_asyncio_server=True
|
||||
)
|
||||
loop = asyncio.get_event_loop()
|
||||
serv_task = asyncio.ensure_future(serv_coro, loop=loop)
|
||||
signal(SIGINT, lambda s, f: loop.stop())
|
||||
server: AsyncioServer = loop.run_until_complete(serv_task)
|
||||
loop.run_until_complete(server.startup())
|
||||
|
||||
# When using app.run(), this actually triggers before the serv_coro.
|
||||
# But, in this example, we are using the convenience method, even if it is
|
||||
# out of order.
|
||||
loop.run_until_complete(server.before_start())
|
||||
loop.run_until_complete(server.after_start())
|
||||
try:
|
||||
loop.run_forever()
|
||||
except KeyboardInterrupt:
|
||||
loop.stop()
|
||||
finally:
|
||||
loop.run_until_complete(server.before_stop())
|
||||
|
||||
# Wait for server to close
|
||||
close_task = server.close()
|
||||
loop.run_until_complete(close_task)
|
||||
|
||||
# Complete all tasks on the loop
|
||||
for connection in server.connections:
|
||||
connection.close_if_idle()
|
||||
loop.run_until_complete(server.after_stop())
|
@ -1,80 +0,0 @@
|
||||
## You need the following additional packages for this example
|
||||
# aiopg
|
||||
# peewee_async
|
||||
# peewee
|
||||
|
||||
|
||||
## sanic imports
|
||||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
## peewee_async related imports
|
||||
import uvloop
|
||||
import peewee
|
||||
from peewee_async import Manager, PostgresqlDatabase
|
||||
|
||||
# we instantiate a custom loop so we can pass it to our db manager
|
||||
loop = uvloop.new_event_loop()
|
||||
|
||||
database = PostgresqlDatabase(database='test',
|
||||
host='127.0.0.1',
|
||||
user='postgres',
|
||||
password='mysecretpassword')
|
||||
|
||||
objects = Manager(database, loop=loop)
|
||||
|
||||
## from peewee_async docs:
|
||||
# Also there’s no need to connect and re-connect before executing async queries
|
||||
# with manager! It’s all automatic. But you can run Manager.connect() or
|
||||
# Manager.close() when you need it.
|
||||
|
||||
|
||||
# let's create a simple key value store:
|
||||
class KeyValue(peewee.Model):
|
||||
key = peewee.CharField(max_length=40, unique=True)
|
||||
text = peewee.TextField(default='')
|
||||
|
||||
class Meta:
|
||||
database = database
|
||||
|
||||
# create table synchronously
|
||||
KeyValue.create_table(True)
|
||||
|
||||
# OPTIONAL: close synchronous connection
|
||||
database.close()
|
||||
|
||||
# OPTIONAL: disable any future syncronous calls
|
||||
objects.database.allow_sync = False # this will raise AssertionError on ANY sync call
|
||||
|
||||
|
||||
app = Sanic('peewee_example')
|
||||
|
||||
@app.route('/post/<key>/<value>')
|
||||
async def post(request, key, value):
|
||||
"""
|
||||
Save get parameters to database
|
||||
"""
|
||||
obj = await objects.create(KeyValue, key=key, text=value)
|
||||
return json({'object_id': obj.id})
|
||||
|
||||
|
||||
@app.route('/get')
|
||||
async def get(request):
|
||||
"""
|
||||
Load all objects from database
|
||||
"""
|
||||
all_objects = await objects.execute(KeyValue.select())
|
||||
serialized_obj = []
|
||||
for obj in all_objects:
|
||||
serialized_obj.append({
|
||||
'id': obj.id,
|
||||
'key': obj.key,
|
||||
'value': obj.text}
|
||||
)
|
||||
|
||||
return json({'objects': serialized_obj})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host='0.0.0.0', port=8000, loop=loop)
|
||||
|
31
examples/sentry_example.py
Normal file
31
examples/sentry_example.py
Normal file
@ -0,0 +1,31 @@
|
||||
from os import getenv
|
||||
|
||||
from sentry_sdk import init as sentry_init
|
||||
from sentry_sdk.integrations.sanic import SanicIntegration
|
||||
|
||||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
|
||||
sentry_init(
|
||||
dsn=getenv("SENTRY_DSN"),
|
||||
integrations=[SanicIntegration()],
|
||||
)
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@app.route("/working")
|
||||
async def working_path(request):
|
||||
return json({"response": "Working API Response"})
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@app.route("/raise-error")
|
||||
async def raise_error(request):
|
||||
raise Exception("Testing Sentry Integration")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=getenv("PORT", 8080))
|
41
examples/simple_async_view.py
Normal file
41
examples/simple_async_view.py
Normal file
@ -0,0 +1,41 @@
|
||||
from sanic import Sanic
|
||||
from sanic.response import text
|
||||
from sanic.views import HTTPMethodView
|
||||
|
||||
|
||||
app = Sanic("some_name")
|
||||
|
||||
|
||||
class SimpleView(HTTPMethodView):
|
||||
def get(self, request):
|
||||
return text("I am get method")
|
||||
|
||||
def post(self, request):
|
||||
return text("I am post method")
|
||||
|
||||
def put(self, request):
|
||||
return text("I am put method")
|
||||
|
||||
def patch(self, request):
|
||||
return text("I am patch method")
|
||||
|
||||
def delete(self, request):
|
||||
return text("I am delete method")
|
||||
|
||||
|
||||
class SimpleAsyncView(HTTPMethodView):
|
||||
async def get(self, request):
|
||||
return text("I am async get method")
|
||||
|
||||
async def post(self, request):
|
||||
return text("I am async post method")
|
||||
|
||||
async def put(self, request):
|
||||
return text("I am async put method")
|
||||
|
||||
|
||||
app.add_route(SimpleView.as_view(), "/")
|
||||
app.add_route(SimpleAsyncView.as_view(), "/async")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
@ -1,12 +0,0 @@
|
||||
from sanic import Sanic
|
||||
from sanic.response import json
|
||||
|
||||
app = Sanic(__name__)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
return json({"test": True})
|
||||
|
||||
|
||||
app.run(host="0.0.0.0", port=8000)
|
BIN
examples/static/favicon.ico
Normal file
BIN
examples/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
examples/static/images/logo.png
Normal file
BIN
examples/static/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
2
examples/static/robots.txt
Normal file
2
examples/static/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow: /
|
6
examples/static_assets.py
Normal file
6
examples/static_assets.py
Normal file
@ -0,0 +1,6 @@
|
||||
from sanic import Sanic
|
||||
|
||||
|
||||
app = Sanic("Example")
|
||||
|
||||
app.static("/", "./static")
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user