Compare commits

...

245 Commits

Author SHA1 Message Date
Adam Hopkins
44bf7ba79a Cleanup tests 2023-08-21 22:54:04 +03:00
Adam Hopkins
9e7ca10c52 Cleanup tests 2023-08-21 21:37:45 +03:00
Adam Hopkins
fe32f4eb74 Fix border character 2023-08-21 20:10:47 +03:00
Adam Hopkins
ebe29d3d26 Make pretty 2023-08-21 16:40:22 +03:00
Adam Hopkins
f651f7436f Fix MOTD for extra data 2023-08-21 16:37:55 +03:00
Adam Hopkins
16256522f6 Disable Test PyPI dist 2023-07-25 16:13:47 +03:00
Adam Hopkins
205795d1e8 Prepare for v23.6 release (#2797) 2023-07-25 15:57:29 +03:00
Adam Hopkins
9cbe1fb8ad Add convenience method for exception reporting (#2792) 2023-07-18 00:21:55 +03:00
L. Kärkkäinen
31d7ba8f8c Add request.client_ip (#2790)
Co-authored-by: L. Kärkkäinen <Tronic@users.noreply.github.com>
2023-07-13 23:01:02 +03:00
Adam Hopkins
dc3c4d1393 Add custom typing to config and ctx (#2785) 2023-07-12 23:47:58 +03:00
Adam Hopkins
929d270569 Update bug-report.yml (#2788) 2023-07-12 19:00:28 +03:00
Adam Hopkins
93714df051 Update bug-report.yml (#2787) 2023-07-12 18:53:14 +03:00
L. Kärkkäinen
6e61eab872 Increase KEEP_ALIVE_TIMEOUT default to 120 seconds (#2670)
Co-authored-by: L. Kärkkäinen <Tronic@users.noreply.github.com>
2023-07-12 08:45:30 +03:00
Adam Hopkins
6848ff24d8 Run keep alive tests in loop to get available port (#2779) 2023-07-09 22:58:17 +03:00
Adam Hopkins
666371bb92 Set multiprocessing start method early (#2776) 2023-07-09 22:34:15 +03:00
Adam Hopkins
4a2b82e42e Remove Python3.7 support (#2777) 2023-07-09 22:00:14 +03:00
Moshe Nahmias
5dd1623192 Alow Blueprint routes to explicitly define error_format (#2773)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-07-09 14:47:59 +03:00
Adam Hopkins
976da69e79 Add a new exception signal for ALL exceptions raised anywhere in application (#2724) 2023-07-09 10:53:36 +03:00
Liam Coatman
11a0b15194 Handle case when headers argument of ResponseStream constructor is None (#2729)
* Handle case when headers is None

* Add test for response stream with default headers

* Move test

---------

Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-07-09 10:34:40 +03:00
Adam Hopkins
c21999a248 Resolve headers on different renderers - Issue 2749 (#2774)
* Resolve headers on different renderers - Issue 2749

* Make pretty
2023-07-09 09:57:22 +03:00
guacs
c17230ef94 Update request type on middleware types (#2754)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-07-09 09:35:24 +03:00
Adam Hopkins
049983cb70 Fix traversals for intended results (#2728) 2023-07-09 09:21:39 +03:00
Zhiwei
e374409567 Adding allow route overwrite option in blueprint (#2716)
* Adding allow route overwrite option

* Add test case for route overwriting after bp copy

* Fix test

* Fix

* Add test case `test_bp_allow_override`

* Remove conflicted future routes when overwriting is allowed

* Improved test test_bp_copy_with_route_overwriting

* Fix type

* Fix type 2

* Add `test_bp_copy_without_route_overwriting` case

* make `allow_route_overwrite` flag to be internal

* Remove unwanted test case

---------

Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-07-07 14:56:42 +03:00
Adam Hopkins
4068a0d83d Add name prefixing to BP groups (#2727) 2023-07-05 19:31:25 +03:00
Benjamin
70da5e9879 Fix Inner bug: TypeError: __init__() got an unexpected keyword argument 'escape_forward_slashes' #2740 (#2772) 2023-07-05 15:30:38 +03:00
Moshe Nahmias
f48506d620 fix #2757 - Improved error messaging on startup time application induced import error (#2770)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-07-05 14:38:15 +03:00
Mohammad Almoghrabi
f2cc83c1ba fix examples for freeze_support() issue on windows (#2741)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-07-05 13:45:08 +03:00
Mohammad Almoghrabi
273825dab6 Sanic on pypy (#2682)
Co-authored-by: L. Kärkkäinen <98187+Tronic@users.noreply.github.com>
Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-07-05 12:14:47 +03:00
Zhiwei
9a7dafd531 Unpin setuptools version (#2766) 2023-07-05 11:06:43 +03:00
Thirumalaisamy K
50117d174c Fix issue in getting current request through classmethod when served through a different ASGI server (#2760) 2023-06-14 22:03:43 +03:00
Néstor Pérez
af67801062 Fix JSONResponse default content type (#2737) 2023-04-09 22:23:21 +03:00
Adam Hopkins
6eaab2a7e5 Release 23.3 (#2723) 2023-03-26 22:54:28 +03:00
Adam Hopkins
d680af3709 v23.3 Deprecation Removal (#2717) 2023-03-26 15:24:08 +03:00
Adam Hopkins
a8c2d77c91 Sync state tolerance (#2725) 2023-03-26 08:39:59 +03:00
Adam Hopkins
6e1c787e5d Simpler CLI targets (#2700)
Co-authored-by: L. Kärkkäinen <98187+Tronic@users.noreply.github.com>
2023-03-21 20:50:25 +02:00
L. Kärkkäinen
932088e37e Stricter charset handling and escaping of request URLs (#2710)
Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
2023-03-21 19:55:21 +02:00
Adam Hopkins
1a63b9bec0 Add convenience methods for cookie creation and deletion (#2706)
* Add convenience methods for cookie creation and deletion

* Restore del

* Backwards compat, forward thinking

* Add delitem deprecation notice

* Add get full deprecation notice

* Add deprecation docstring

* Better deprecation docstring

* Add has_cookie

* Same defaults

* Better deprecation message

* Accessor annotations

* make pretty

* parse cookies

* Revert quote translator

* make pretty

* make pretty

* Add unit tests

* Make pretty

* Fix unit tests

* Directly include unquote

* Add some more unit tests

* Move modules into their own dir

* make pretty

* cleanup test imports

* Add test for cookie accessor

* Make test consistent

* Remove file

* Remove additional escaping

* Add header style getattr for hyphens

* Add test for cookie accessor with hyphens

* Add new translator

* Parametrize test_request_with_duplicate_cookie_key

* make pretty

* Add deprecation of direct cookie encoding

* Speedup Cookie creation

* Implement prefixes on delete_cookie

* typing changes

* Add passthru functions on response objects for setting cookies

* Add test for passthru

---------

Co-authored-by: L. Kärkkäinen <98187+Tronic@users.noreply.github.com>
2023-03-21 11:25:35 +02:00
Zhiwei
61aa16f6ac Decode headers as UTF-8 also in ASGI (#2606)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-03-20 15:39:57 +02:00
Adam Hopkins
71cd53b64e Standardize init of exceptions (#2545) 2023-03-20 14:50:50 +02:00
Adam Hopkins
89188f5fc6 Add CertLoader as application option (#2722) 2023-03-20 14:05:21 +02:00
Adam Hopkins
a245ab3773 Change logging format to %s (#2721) 2023-03-20 13:25:06 +02:00
Adam Hopkins
ac1f56118a Skip middleware on RequestCancelled (#2720) 2023-03-20 13:00:34 +02:00
Adam Hopkins
53820bc241 Allow password to be passed to TLS context (#2719) 2023-03-20 12:34:36 +02:00
stricaud
009954003c Fix comparison from wrong formats with datetime objects (#2697)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-03-20 12:12:09 +02:00
Adam Hopkins
8f265b8169 Add convenience for dynamic changes to routing (#2704) 2023-03-19 15:40:58 +02:00
Adam Hopkins
5ee36fd933 Separate ASGI request and lifespan callables (#2646) 2023-03-17 09:05:33 +02:00
Matt Bendiksen
08a81c81be scheme arg to create the redirect should be 'https' (#2712) 2023-03-16 12:13:17 +02:00
Adam Hopkins
5a0ed75171 Consume body on DELETE by default (#2711) 2023-03-15 18:42:45 +02:00
Adam Hopkins
d62a92fac9 API to define a number of workers (#2701) 2023-03-15 16:02:17 +02:00
Adam Hopkins
88c918e72f Update rfc.yml 2023-03-09 10:10:22 +02:00
Adam Hopkins
c8aab8fb3d Update rfc.yml 2023-03-09 10:09:30 +02:00
Adam Hopkins
ecacfd396b Rename rfc to rfc.yml 2023-03-09 10:06:42 +02:00
Adam Hopkins
3c361e9852 Create rfc 2023-03-09 10:05:06 +02:00
L. Kärkkäinen
a5d7d03413 Nicer traceback formatting (#2667)
Co-authored-by: L. Kärkkäinen <98187+Tronic@users.noreply.github.com>
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
Co-authored-by: SML <smlbiobot@gmail.com>
2023-03-06 21:24:12 +02:00
L. Kärkkäinen
259e458847 Simplified parse_content_header escaping (#2707) 2023-03-06 06:39:16 +02:00
Adam Hopkins
cb49c2b26d Add header accessors (#2696) 2023-02-28 00:26:53 +02:00
L. Kärkkäinen
dfc0704831 Error page rendering format selection (#2668)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
2023-02-26 08:25:10 +02:00
Adam Hopkins
d238995f1b Refresh Request.accept functionality (#2687) 2023-02-21 08:22:51 +02:00
Mohammad Almoghrabi
6f5303e080 check the status of socket before shutting down (#2680)
* check the status of socket before shutting down

* remove socket status checking & ignore OSError exception
2023-02-14 22:59:41 +02:00
Ryu Juheon
5e7f6998bd fix(websocket): ASGI websocket must pass thru bytes as is (#2651) 2023-02-05 16:41:54 +02:00
L. Kärkkäinen
c7a71cd00c Use FALLBACK_ERROR_FORMAT for handlers that return empty() (#2659)
Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2023-02-05 15:29:01 +02:00
Adam Hopkins
9cb9e88678 Establish basic file browser and index fallback (#2662)
Co-authored-by: L. Kärkkäinen <98187+Tronic@users.noreply.github.com>
Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
2023-02-05 15:09:04 +02:00
Rodolfo Olivieri
30c53b6857 Remove deprecated property in blueprint (#2666)
Fixes https://github.com/sanic-org/sanic/issues/2442
2023-01-30 09:26:55 +02:00
Adam Hopkins
4ad8168bb0 Version 22.12 release notes (#2637) 2022-12-27 16:50:36 +02:00
Adam Hopkins
28f5b3c301 Add better inspector arg parsing (#2642) 2022-12-26 12:27:40 +02:00
Adam Hopkins
c573019e7f ASGI websocket recv text or bytes (#2640) 2022-12-25 13:52:07 +02:00
Adam Hopkins
029f564032 Pass unquote thru add_route (#2639) 2022-12-21 10:45:23 +02:00
Adam Hopkins
2abe66b670 Add priority to register_middleware method (#2636) 2022-12-19 19:14:46 +02:00
Adam Hopkins
911485d52e Fix Windows sock share (#2635) 2022-12-18 15:04:10 +02:00
Adam Hopkins
4744a89c33 Fix double ctrl-c kill (#2634) 2022-12-18 14:40:38 +02:00
Adam Hopkins
f7040ccec8 Implement restart ordering (#2632) 2022-12-18 14:09:17 +02:00
Adam Hopkins
518152d97e Reload interval on class variable (#2633) 2022-12-18 13:36:54 +02:00
Adam Hopkins
0e44e9cacb Move to HTTP Inspector (#2626) 2022-12-18 10:29:58 +02:00
Adam Hopkins
bfb54b0969 Test for 3.11 support (#2612)
Co-authored-by: Zhiwei <zhi.wei.liang@outlook.com>
2022-12-17 23:46:22 +02:00
Zhiwei
154863d6c6 Method Signal Handler Test (#2630) 2022-12-17 20:38:46 +02:00
Adam Hopkins
a3ff0c13b7 ASGI lifespan failure on exception (#2627) 2022-12-16 08:56:07 +02:00
Mary
95ee518aec Replace deprecated distutils.strtobool (#2628) 2022-12-16 07:48:41 +02:00
Zhiwei
71d3d87bcc Deprecate Conditions and Triggers Saved in handler Callable; Save Condition in signal.extra Instead (#2608) 2022-12-15 12:32:07 +02:00
Adam Hopkins
b276b91c21 Allow fork in limited cases (#2624) 2022-12-15 11:49:26 +02:00
Adam Hopkins
064168f3c8 Add a SIGKILL to second ctrl+c (#2621) 2022-12-14 23:51:11 +02:00
Adam Hopkins
db39e127bf Scale workers (#2617) 2022-12-13 09:28:23 +02:00
L. Kärkkäinen
13e9ab7ba9 Filename normalisation of form-data/multipart file uploads (umlauts on Apple clients) (#2625)
Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
2022-12-13 08:36:21 +02:00
Adam Hopkins
92e7463721 Add a restart mechanism to all workers in the multiplexer (#2622) 2022-12-11 11:33:42 +02:00
Néstor Pérez
8e720365c2 Add JSONResponse class (#2569)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-12-11 10:37:45 +02:00
Adam Hopkins
d4041161c7 Ensure middleware executes once per request timeout (#2615) 2022-12-07 23:07:17 +02:00
Adam Hopkins
f32437bf13 Kill server early on worker error (#2610) 2022-12-07 14:42:17 +02:00
LiraNuna
0909e94527 Corrected Colors enum under Python 3.11 (#2590)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Fixes https://github.com/sanic-org/sanic/issues/2589
2022-11-29 12:17:48 +02:00
Adam Hopkins
aef2673c38 Force socket shutdown before close (#2607)
Co-authored-by: Zhiwei <zhi.wei.liang@outlook.com>
2022-11-29 12:04:22 +02:00
Aymeric Augustin
4c14910d5b Add compatibility with websockets 11.0. (#2609)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-11-29 11:45:18 +02:00
Adam Hopkins
beae35f921 Ignore recent failures on bad TLS tests (#2611) 2022-11-29 10:51:51 +02:00
Zhiwei
ad4e526c77 Require uvloop >= 0.15.0 (#2598) 2022-11-13 15:32:04 +02:00
Adam Hopkins
4422d0c34d Mergeback from current-release 2022-10-31 13:24:47 +02:00
Adam Hopkins
ad9183d21d Merge branch 'main' of github.com:sanic-org/sanic into current-release 2022-10-31 13:22:47 +02:00
Adam Hopkins
d70636ba2e Add GenericCreator for loading SSL certs in processes (#2578) 2022-10-31 13:22:30 +02:00
Adam Hopkins
da23f85675 Set version 2022-10-31 13:20:17 +02:00
Adam Hopkins
3f4663b9f8 Resolve edge case in nested BP Groups (#2592) 2022-10-31 12:58:41 +02:00
Adam Hopkins
65d7447cf6 Add interval sleep in reloader (#2595) 2022-10-31 12:34:01 +02:00
Adam Hopkins
5369291c27 22.9 Docs (#2556) 2022-10-31 11:47:23 +02:00
Ryu Juheon
1c4925edf7 fix: sideeffects created by changing fork to spawn (#2591) 2022-10-27 20:39:17 +03:00
Santi Cardozo
6b9edfd05c improve error message if no apps found in registry (#2585) 2022-10-25 16:54:44 +03:00
Adam Hopkins
97f33f42df Update SECURITY.md 2022-10-25 13:05:13 +03:00
Adam Hopkins
15a588a90c Upgrade markdown templates to issue forms (#2588) 2022-10-25 13:04:11 +03:00
Ryu Juheon
82421e7efc docs: sanic now supports windows. (#2582) 2022-10-21 14:31:22 +03:00
Adam Hopkins
f891995b48 Start v22.12 2022-09-29 13:04:46 +03:00
Adam Hopkins
5052321801 Remove deprecated items (#2555) 2022-09-29 01:07:09 +03:00
Adam Hopkins
23ce4eaaa4 Merge branch 'main' of github.com:sanic-org/sanic 2022-09-23 00:16:27 +03:00
Adam Hopkins
23a430c4ad Set version properly 2022-09-23 00:16:10 +03:00
Adam Hopkins
ec158ffa69 Additional logger and support for multiprocess manager (#2551) 2022-09-23 00:01:33 +03:00
Adam Hopkins
6e32270036 Begin middleware revamp (#2550) 2022-09-22 00:43:42 +03:00
Zhiwei
43ba381e7b Refactor _static_request_handler (#2533)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-09-21 00:45:03 +03:00
Zhiwei
16503319e5 Make WebsocketImplProtocol async iterable (#2490) 2022-09-21 00:20:32 +03:00
Adam Hopkins
389363ab71 Better request cancel handling (#2513) 2022-09-19 16:04:09 +03:00
Adam Hopkins
7f894c45b3 Add deprecation warning filter (#2546) 2022-09-18 18:54:35 +03:00
Adam Hopkins
4726cf1910 Sanic Server WorkerManager refactor (#2499)
Co-authored-by: Néstor Pérez <25409753+prryplatypus@users.noreply.github.com>
2022-09-18 17:17:23 +03:00
Adam Hopkins
d352a4155e Add signals before and after handler execution (#2540) 2022-09-15 15:49:21 +03:00
Adam Hopkins
e5010286b4 Raise warning and deprecation notice on violations (#2537) 2022-09-15 15:24:46 +03:00
Adam Hopkins
358498db96 Do not apply double slash to Blueprint and static dirs (#2515) 2022-09-15 14:43:20 +03:00
monosans
e4999401ab Improve and fix some type annotations (#2536) 2022-09-13 08:53:48 +03:00
Néstor Pérez
c8df0aa2cb Fix easter egg through CLI (#2542) 2022-09-12 01:44:21 +03:00
Adam Hopkins
5fb207176b Update bug_report.md 2022-08-29 12:47:01 +03:00
Adam Hopkins
a12b560478 Update feature_request.md 2022-08-29 12:46:39 +03:00
Zhiwei
753ee992a6 Validate File When Requested (#2526)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-08-18 12:05:05 +03:00
Hunt Zhan
09089b1bd3 Resolve issue 2529 (#2530) 2022-08-18 08:58:07 +03:00
Adam Hopkins
7ddbe5e844 Update config.yml 2022-08-17 10:44:02 +03:00
Adam Hopkins
ab5a7038af Update SECURITY.md 2022-08-17 10:42:22 +03:00
Adam Hopkins
4f3c780dc3 Update feature_request.md 2022-08-17 10:38:15 +03:00
Adam Hopkins
71f7765a4c Update bug_report.md 2022-08-17 10:37:35 +03:00
Adam Hopkins
0392d1dcfc Always show server location in ASGI (#2522)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Co-authored-by: Zhiwei Liang <zhi.wei.liang@outlook.com>
Co-authored-by: Néstor Pérez <25409753+prryplatypus@users.noreply.github.com>
2022-08-11 10:00:35 +03:00
Adam Hopkins
7827b1b41d Add Request properties for HTTP method info (#2516) 2022-08-10 21:12:09 +03:00
Adam Hopkins
8e9342e188 Warn on duplicate route names (#2525) 2022-08-10 20:36:47 +03:00
Adam Hopkins
2f6f2bfa76 Rename code of conduct 2022-08-02 13:56:53 +03:00
Ryu Juheon
dee09d7fff style: add some type hints (#2517) 2022-08-02 08:47:59 +03:00
Adam Hopkins
9cf38a0a83 MERGEBACK (#2495) (#2512)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Co-authored-by: Zhiwei Liang <zhi.wei.liang@outlook.com>
Co-authored-by: Néstor Pérez <25409753+prryplatypus@users.noreply.github.com>
2022-07-31 15:50:46 +03:00
Adam Hopkins
3def3d3569 Use path.parts instead of match (#2508) 2022-07-31 12:54:42 +03:00
Adam Hopkins
e100a14fd4 Use pathlib for path resolution (#2506) 2022-07-31 08:49:02 +03:00
Adam Hopkins
2fa28f1711 Fix dotted test 2022-07-28 10:07:30 +03:00
Néstor Pérez
9d415e4ec6 Prevent directory traversion with static files (#2495)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Co-authored-by: Zhiwei Liang <zhi.wei.liang@outlook.com>
2022-07-28 09:45:45 +03:00
Tim Gates
312ab298fd docs: Fix a few typos (#2502)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-07-24 22:47:39 +03:00
Zhiwei
2fc21ad576 Replace Unsupported Python Version Number from the Contributing Doc (#2505)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-07-24 22:33:05 +03:00
Zhiwei
8f6c87c3d6 Fix Test Cases: test_http for Py3.9+, test_json_response_json for ujson 5.4.0+, and test_zero_downtime; Test Case Type Annotations (#2504) 2022-07-24 22:07:54 +03:00
Adam Hopkins
4429e76532 Add to changelog 2022-06-30 12:52:27 +03:00
Michael Azimov
e4be70bae8 Add custom loads function (#2445)
Co-authored-by: Zhiwei <chihwei.public@outlook.com>
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-06-29 23:39:21 +03:00
Adam Hopkins
13d5a44278 Release 22.6 (#2487) 2022-06-28 15:25:46 +03:00
Adam Hopkins
aba333bfb6 Improve API docs (#2488) 2022-06-28 10:53:03 +03:00
Adam Hopkins
b59da498cc HTTP/3 Support (#2378) 2022-06-27 11:19:26 +03:00
Zhiwei
70382f21ba Fix and improve file cache control header calculation (#2486) 2022-06-26 23:11:48 +03:00
Néstor Pérez
0e1bf89fad Add missing spaces in CLI error message (#2485) 2022-06-26 10:38:35 +03:00
Aidan Timson
6c48c8b3ba Fix for running in pythonw (#2448)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-06-19 14:48:06 +03:00
Zhiwei
d1c5e8003b Fix test_cli and test_cookies (#2479) 2022-06-19 04:43:12 +03:00
Adam Hopkins
ce926a34f2 Add Request contextvars (#2475)
* Add Request contextvars

* Add missing contextvar setter

* Move location of context setter
2022-06-16 22:57:02 +03:00
Zhiwei
a744041e38 File Cache Control Headers Support (#2447)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-06-16 16:24:39 +03:00
Mary
2f90a85df1 feat(type): extend (#2466)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-06-16 15:38:13 +03:00
Adam Hopkins
a411bc06e3 Resolve typing of stacked route definitions (#2455) 2022-06-16 15:15:20 +03:00
Adam Hopkins
1668e1532f Move verbosity filtering to logger (#2453) 2022-06-16 12:35:49 +03:00
Vetési Zoltán
b87982769f Trigger http.lifecycle.request signal in ASGI mode (#2451)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-06-16 11:55:50 +03:00
Ryu Juheon
65b53a5f3f style: add msg in `task.cancel` (#2416)
* style: add msg in ``task.cancel``

* style: apply isort

* fix: use else statement

* fix: use tuple

* fix: rollback for test

* fix: rollback like previous change

* fix: add ``=``

Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-06-16 10:55:20 +03:00
Zhiwei
49789b7841 Clean Up Black and Isort Config (#2449)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-05-26 12:48:32 +03:00
Amitay
c249004c30 fixed manual to match current Sanic app name policy (#2461)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-05-26 10:16:24 +03:00
Ashley Sommer
4ee2e57ec8 Properly catch websocket CancelledError in websocket handler in Python 3.7 (#2463) 2022-05-23 22:47:05 +03:00
Néstor Pérez
86ae5f981c refactor: consistent exception naming (#2420)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-05-12 20:39:35 +03:00
Adam Hopkins
2bfa65e0de Current release mergeback (#2454) 2022-05-11 09:37:33 +03:00
Adam Hopkins
293278bb08 Resolve warning issue with error handler mismatch warning (#2452) 2022-05-11 09:36:05 +03:00
Michael Azimov
5d683c6ea4 Expose scope parameter in request object (#2432)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-04-26 17:25:29 +03:00
Stephen Sadowski
78b6723149 Preserve blank form values for urlencoded forms (option) (#2439)
* task(request.form): Add tests for blank values

* fix(request): abstract form property to implement get_form(), allow for preserving of blanks

* fix(request): hinting for parsed_form

* fix(request): typing for parsed_files

* fix(request): ignore type assumption

* fix(request): mypy typechecking caused E501 when type set to ignore

* fix(request): mypy is too stupid to parse continuations

* fix(request): formatting

* fix(request): fix annotation and return for get_form()

* fix(request): linting, hinting
2022-04-24 23:01:35 +03:00
Ryu juheon
3a6cc7389c feat: easier websocket interface annotation (#2438) 2022-04-24 13:32:13 +03:00
Adam Hopkins
cc97287f8e Add fall back for Windows even loop fetching (#2421) 2022-04-17 12:25:41 +03:00
Adam Hopkins
00218aa9f2 22.3 Internal version bumps (#2419) 2022-03-31 14:30:30 +03:00
Adam Hopkins
874718db94 Bump version and 22.3 changelog (#2418) 2022-03-30 15:09:45 +03:00
Javier Marcet
bb4474897f Fix "DeprecationWarning: There is no current event loop" (#2390)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-03-30 09:40:30 +03:00
Adam Hopkins
0cb342aef4 Better exception for bad URL parse (#2415) 2022-03-25 00:22:12 +02:00
Ashley Sommer
030987480c Add config option to skip Touchup step, for debugging purposes (#2361)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-03-24 13:52:05 +02:00
Robert Schütz
f6fdc80b40 allow multidict version 6 (#2396)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-03-24 00:38:45 +02:00
Jonathan Vargas
361c242473 remove error_logger on websockets (#2373)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-03-23 16:25:19 +02:00
André Ericson
32962d1e1c Fixing typing for ListenerMixin.listener (#2376)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-03-23 15:34:33 +02:00
Adam Hopkins
6e0a6871b5 Upgrade tests for sanic-routing changes (#2405) 2022-03-23 13:43:36 +02:00
Adam Hopkins
0030425c8c Conditionally inject CLI arguments into factory (#2402) 2022-03-23 12:00:41 +02:00
Adam Hopkins
c9dbc8ed26 Remove loop as required listener arg (#2414) 2022-03-23 11:02:39 +02:00
Callum
44b108b564 Changes to CLI (#2401)
Co-authored-by: Callum Fleming <howzitcal@zohomail.com>
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-03-23 10:30:41 +02:00
Adam Hopkins
2a8e91052f Add two new events on the reloader process (#2413) 2022-03-22 23:29:39 +02:00
Bluenix
0c9df02e66 Add a docstring to Request.respond() (#2409)
Co-authored-by: Ryu juheon <saidbysolo@gmail.com>
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2022-03-14 13:10:49 +02:00
Arie Bovenberg
7523e87937 remove overlapping slots from app.Sanic, fix broken slots inherit of HTTPResponse (#2387) 2022-02-24 17:45:23 +02:00
Bluenix
d4fb44e986 Document middleware on_request and on_response (#2398) 2022-02-13 21:08:08 +02:00
Ryu juheon
68b654d981 fix(tasks): newly assigned `None` in registry (#2381) 2022-02-08 08:33:09 +02:00
Adam Hopkins
88bc6d8966 Upgrade black and isort changes (#2397) 2022-02-02 10:41:55 +02:00
Adam Hopkins
ac388d644b Downgrade warnings to backwater debug messages (#2382) 2022-01-19 14:26:45 +02:00
Ryu juheon
bb517ddcca fix: deprecation warning in `asyncio.wait` (#2383) 2022-01-19 08:09:17 +02:00
Adam Hopkins
b8d991420b Sanic multi-application server (#2347) 2022-01-16 09:03:04 +02:00
Adam Hopkins
4a416e177a Updates to CLI help messaging (#2372) 2022-01-14 00:54:51 +02:00
Adam Hopkins
8dfa49b648 22.3 Deprecations and changes (#2362) 2022-01-12 16:28:43 +02:00
Adam Hopkins
8b0eaa097c Change back to codecov (#2363) 2022-01-09 12:22:09 +02:00
Sergey Rybakov
101151b419 Add credentials property to Request objects (#2357) 2022-01-06 19:14:52 +02:00
Adam Hopkins
4669036f45 Mergeback of 21.12.1 (#2358)
Co-authored-by: Néstor Pérez <25409753+prryplatypus@users.noreply.github.com>
Co-authored-by: Ryu juheon <saidbysolo@gmail.com>
2022-01-06 12:40:52 +02:00
raphaelauv
9bf9067c99 [FIX] README ASGI link (#2350) 2022-01-04 06:39:59 +02:00
Adam Hopkins
a7bc8b56ba Set dev version 2021-12-26 22:19:39 +02:00
Zhiwei
371985d129 deprecation warning for not catch lowercase env var (#2344) 2021-12-26 21:47:15 +02:00
Adam Hopkins
3eae00898d Set setuptools version for RTD 2021-12-26 14:25:09 +02:00
Adam Hopkins
dc3ccba527 Auto extend with Sanic Extensions (#2308) 2021-12-25 22:20:06 +02:00
Adam Hopkins
b91ffed010 Change signal routing for increased consistency (#2277) 2021-12-24 01:27:54 +02:00
Adam Hopkins
8c07e388cd LTS v21.12 Deprecations (#2306)
Co-authored-by: Néstor Pérez <25409753+prryplatypus@users.noreply.github.com>
2021-12-24 00:30:27 +02:00
Néstor Pérez
98ce4bdeb2 Optional uvloop use (#2264)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
2021-12-23 11:57:33 +02:00
Adam Hopkins
4659069350 Add route context (#2302) 2021-12-21 22:56:12 +02:00
Adam Hopkins
080d41627a Env custom type casting (#2330) 2021-12-21 00:50:45 +02:00
Adam Hopkins
d799c5f03c Add named tasks (#2304) 2021-12-20 23:50:04 +02:00
Adam Hopkins
abe062b371 Remove app instance from Config for error handler setting (#2320) 2021-12-18 18:58:14 +02:00
Zhiwei
b5a00ac1ca Add Py310 Tests Badge to README (#2341) 2021-12-15 13:09:13 +02:00
Adam Hopkins
f282865362 Cleanup ports on tests (#2338) 2021-12-13 19:48:30 +02:00
Adam Hopkins
377c2ada38 Remove paths from coverage checks (#2336) 2021-12-13 15:03:51 +02:00
Adam Hopkins
264453459e Add runtime checking to create_server to verify that startup has been run (#2328) 2021-12-13 09:36:41 +02:00
Adam Hopkins
3d383d7b97 Update README.rst 2021-12-12 13:58:34 +02:00
Adam Hopkins
c0cc26021b Allow underscore to start instance names (#2335) 2021-12-10 00:04:34 +02:00
Zhiwei
96c027bad5 Prevent sending multiple or mixed responses on a single request (#2327)
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
2021-12-09 12:00:18 +02:00
Adam Hopkins
b2a1bc69f5 Make warnings for DeprecationWarning consistent (#2332) 2021-12-08 21:01:28 +02:00
Zhiwei
426742b3e2 Fix Sanic.handle_exception Method's Type Doc (#2333)
* Fix type doc

* Remove explicit type defines in docstring
2021-12-07 12:10:04 +02:00
Kian Meng Ang
ab35121864 Fix typos (#2329)
* Fix typos

* Downgrade mistune version

* Fix blueprint host param

Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2021-12-06 09:17:01 +02:00
Zhiwei
cf3c205fa5 Fixed: CI Runs on Ready PRs Only (#2324)
* Revert "Update tests to not run all the time (#2311)"

This reverts commit 2c03eee329.

* Make CI only runs on PRs that are ready

* Remove CI Tasks on Push
2021-12-06 00:05:07 +02:00
Adam Hopkins
19f6544923 Resolve potential bug in MOTD in Docker (#2331)
* Resolve potential bug in MOTD in Docker
2021-12-03 13:27:16 +02:00
Clay Sweetser
f641830d26 Refactor environment variable hydration logic. (#2321)
- Refactor environment variable hydration logic to be less nested. This allows possible future extension of the hydration logic.
- Fix a spelling mistake in `load_environment_vars` docstring.

Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
2021-12-03 00:01:20 +02:00
Zhiwei
a8d55e180c Fix Type Hint (#2322)
* Fix Type Hint

Union is not necessary here? My IDE pops an error for it.

* Rerun workflows

* empty commit
2021-12-02 23:17:22 +02:00
Adam Hopkins
55c36e0240 Fix examples to work as expected (#2305)
* Fix examples to work as expected

* Clean up examples

* Update worker test

* Merge in from main and cleanup example
2021-11-23 23:00:25 +02:00
Adam Hopkins
2c03eee329 Update tests to not run all the time (#2311) 2021-11-23 15:53:46 +02:00
Adam Hopkins
65e28b8c22 Mergeback (#2319)
* Mergeback
2021-11-21 15:13:34 +02:00
Adam Hopkins
dfd33dd63d Update README.rst 2021-11-21 10:27:23 +02:00
Hussein Mohamed
722a6db8d9 Dispatch http.lifecyle.response from exception handler (#2299) 2021-11-19 08:50:02 +02:00
Xavier Petit
9c576c74db Fix typehints in route shorthand methods (#2317)
* Fix typehints in route shorthand methods

Change typehint of the version variable in RouteMixin  to allow int string and float types values
Resolves #2314

* fix lint error in version variable
2021-11-19 08:28:05 +02:00
Adam Hopkins
523db190a7 Add contextual exceptions (#2290) 2021-11-18 17:47:27 +02:00
Adam Hopkins
95631b9686 Coffee please (#2316)
* Coffee please

* Add unit tests
2021-11-18 14:53:06 +02:00
Adam Hopkins
0860bfe1f1 Merge release 21.9.2 (#2313) 2021-11-17 19:36:36 +02:00
Adam Hopkins
85e7b712b9 Allow early Blueprint registrations to still apply later added objects (#2260) 2021-11-17 17:29:41 +02:00
L. Kärkkäinen
b731a6b48c Make HTTP connections start in IDLE stage, avoiding delays and error messages (#2268)
* Make all new connections start in IDLE stage, and switch to REQUEST stage only once any bytes are received from client. This makes new connections without any request obey keepalive timeout rather than request timeout like they currently do.

* Revert typo

* Remove request timeout endpoint test which is no longer working (still tested by mocking). Fix mock timeout test setup.

Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
2021-11-16 23:03:27 +02:00
Adam Hopkins
cde02b5936 More consistent config setting with post-FALLBACK_ERROR_FORMAT apply (#2310)
* Update unit testing and add more consistent config

* Change init and app values to private

* Cleanup line lengths
2021-11-16 13:07:33 +02:00
Adam Hopkins
abeb8d0bc0 Provide list of reloaded files (#2307)
* Allow access to reloaded files

* Return to simple boolean values

* Resolve before adding to changed files
2021-11-16 10:16:32 +02:00
Adam Hopkins
9a9f72ad64 Move builtin signals to enum (#2309)
* Move builtin signals to enum

* Fix annotations
2021-11-14 23:21:14 +02:00
Adam Hopkins
392a497366 Restructure of CLI and application state (#2295)
* Initial work on restructure of application state

* Updated MOTD with more flexible input and add basic version

* Remove unnecessary type ignores

* Add wrapping and smarter output per process type

* Add support for ASGI MOTD

* Add Windows color support ernable

* Refactor __main__ into submodule

* Renest arguments

* Passing unit tests

* Passing unit tests

* Typing

* Fix num worker test

* Add context to assert failure

* Add some type annotations

* Some linting

* Line aware searching in test

* Test abstractions

* Fix some flappy tests

* Bump up timeout on CLI tests

* Change test for no access logs on gunicornworker

* Add some basic test converage

* Some new tests, and disallow workers and fast on app.run
2021-11-07 21:39:03 +02:00
Adam Hopkins
36e6a6c506 Increase join concat performance (#2291) 2021-10-29 12:55:09 +03:00
Stephen Sadowski
a361b345ad Py310 loop fixup (#2294)
* Fixup for 3.8+; Sanic still supports 3.7 where loop is required

* Added branching statement to hanle asyncio.Event() loop parameter removal in 3.10, and optional supply in 3.9
2021-10-28 17:16:23 -05:00
Adam Hopkins
f5bd6e3b2f Add Python 3.10 testing (and support) (#2257)
Administratively merging because @vltr and @ahopkins are the release managers, and @ahopkins is originator of the PR

* Add Python 3.10 testing (and support)

* fixed py310 tox environment for windows, quoted '3.10' in python-310 tests to avoid numeric compression

* updated tox.ini for py310

* quoted the rest of the bare 3.10 references in the workflows

* Issue with pytest requires version bump to 6.2.5 for python 3.10

Co-authored-by: Stephen Sadowski <stephen.sadowski@sjsadowski.com>
2021-10-28 13:41:57 -05:00
L. Kärkkäinen
6c7df68c7c Vhost support using multiple TLS certificates (#2270)
* Initial support for using multiple SSL certificates.

* Also list IP address subjectAltNames on log.

* Use Python 3.7+ way of specifying TLSv1.2 as the minimum version. Linter fixes.

* isort

* Cleanup, store server name for later use. Add RSA ciphers. Log rejected SNIs.

* Cleanup, linter.

* Alter the order of initial log messages and handling. In particular, enable debug mode early so that debug messages during init can be shown.

* Store server name (SNI) to conn_info.

* Update test with new error message.

* Refactor for readability.

* Cleanup

* Replace old expired test cert with new ones and a script for regenerating them as needed.

* Refactor TLS tests to a separate file.

* Add cryptography to dev deps for rebuilding TLS certs.

* Minor adjustment to messages.

* Tests added for new TLS code.

* Find the correct log row before testing for message. The order was different on CI.

* More log message order fixup. The tests do not account for the logo being printed first.

* Another attempt at log message indexing fixup.

* Major TLS refactoring.

CertSelector now allows dicts and SSLContext within its list.
Server names are stored even when no list is used.
SSLContext.sanic now contains a dict with any setting passed and information extracted from cert.
That information is available on request.conn_info.cert.
Type annotations added.
More tests incl. a handler for faking hostname in tests.

* Remove a problematic logger test that apparently was not adding any coverage or value to anything.

* Revert accidental commit of uvloop disable.

* Typing fixes / refactoring.

* Additional test for cert selection. Certs recreated without DNS:localhost on sanic.example cert.

* Add tests for single certificate path shorthand and SNI information.

* Move TLS dict processing to CertSimple, make the names field optional and use names from the cert if absent.

* Sanic CLI options --tls and --tls-strict-host to use the new features.

* SSL argument typing updated

* Use ValueError for internal message passing to avoid CertificateError's odd message formatting.

* Linter

* Test CLI TLS options.

* Maybe the right codeclimate option now...

* Improved TLS argument help, removed support for combining --cert/--key with --tls.

* Removed support for strict checking without any certs, black forced fscked up formatting.

* Update CLI tests for stricter TLS options.

Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
2021-10-28 16:50:05 +03:00
Meysam
5b82884f8b ci: fail on error 👷 (#2292)
Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
2021-10-27 11:55:34 +03:00
Néstor Pérez
f0f81ec458 Add ability to log all exceptions (#2262)
* Add ability to log all exceptions

* Fix linting 🙄

* Remove shorthand

* Make `ErrorHandler.log` backwards-compat

* Ignore mypy error

* Don't store `noisy_exceptions` attribute in app

* Added tests

* Store noisy exceptions setting in config

* Default to not-noisy if config key not available

* Add CLI tests for `noisy-exceptions`

* Remove debugging line I left in 😅

* Fix tests

Co-authored-by: Adam Hopkins <admhpkns@gmail.com>
2021-10-27 10:43:58 +03:00
Cyril Nicodème
71cc30e5cd Replacing assignation by typing for websocket_handshake (#2273)
* Replacing assignation by typing for `websocket_handshake`

Related to #2272

* Fix some type hinting issues

* Cleanup websocket handchake response concat

* Optimize concat encoding

Co-authored-by: Adam Hopkins <adam@amhopkins.com>
2021-10-27 10:00:04 +03:00
L. Kärkkäinen
645310cff6 Change codeclimate complexity threshold from 5 to 10. (#2286)
Co-authored-by: L. Karkkainen <tronic@users.noreply.github.com>
Co-authored-by: Stephen Sadowski <stephen.sadowski@sjsadowski.com>
2021-10-24 22:30:35 +03:00
Stephen Sadowski
2f30b5748a Update host test function names so they are not overwritten (#2287)
Fix function name reuse in cli tests
2021-10-24 12:29:16 -05:00
Stephen Sadowski
5e1ef96934 fix ipv6 display in startup info log (#2285)
* fix ipv6 display in startup info log

* refactored to oneliner by request

* Added test for passing ipv4 host

* Added test for passing ipv6 any host

* Added test for passing ipv6 loopback host
2021-10-24 11:14:00 -05:00
Ryu juheon
57e98b62b3 style: add some type hints (#2279)
* style: add some type hints

* fix: *args is a tuple, but overridden as a list

* fix: if touch this, it will be a maybe breaking change

* fix: remove unused import

* style(app): more correct type
2021-10-20 15:15:39 +03:00
Néstor Pérez
3262878ebd Fix docs error (#2269) 2021-10-10 22:41:45 +03:00
313 changed files with 23456 additions and 6548 deletions

View File

@@ -1,2 +0,0 @@
[tool.black]
line-length = 79

View File

@@ -1,24 +0,0 @@
exclude_patterns:
- "sanic/__main__.py"
- "sanic/reloader_helpers.py"
- "sanic/simple.py"
- "sanic/utils.py"
- ".github/"
- "changelogs/"
- "docker/"
- "docs/"
- "examples/"
- "hack/"
- "scripts/"
- "tests/"
checks:
argument-count:
enabled: false
file-lines:
config:
threshold: 1000
method-count:
config:
threshold: 40
complex-logic:
enabled: false

View File

@@ -4,9 +4,12 @@ source = sanic
omit =
site-packages
sanic/__main__.py
sanic/reloader_helpers.py
sanic/server/legacy.py
sanic/compat.py
sanic/simple.py
sanic/utils.py
sanic/cli
sanic/pages
[html]
directory = coverage
@@ -18,3 +21,5 @@ exclude_lines =
noqa
NOQA
pragma: no cover
TYPE_CHECKING
skip_empty = True

78
.github/ISSUE_TEMPLATE/bug-report.yml vendored Normal file
View 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

View File

@@ -1,25 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is, make sure to paste any exceptions and tracebacks.
**Code snippet**
Relevant source code, make sure to remove what is not necessary.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Environment (please complete the following information):**
- OS: [e.g. iOS]
- Version [e.g. 0.8.3]
**Additional context**
Add any other context about the problem here.

View File

@@ -1,5 +1,8 @@
blank_issues_enabled: true
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.

View 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

View File

@@ -1,16 +0,0 @@
---
name: Feature request
about: Suggest an idea for Sanic
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context or sample code about the feature request here.

33
.github/ISSUE_TEMPLATE/rfc.yml vendored Normal file
View 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

View File

@@ -2,14 +2,22 @@ name: "CodeQL"
on:
push:
branches: [ main ]
branches:
- main
- current-release
- "*LTS"
pull_request:
branches: [ main ]
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

View File

@@ -1,17 +1,17 @@
name: Coverage check
# on:
# push:
# branches:
# - main
# tags:
# - "!*" # Do not execute on tags
# paths:
# - sanic/*
# - tests/*
# pull_request:
# paths:
# - "!*.MD"
on: [push, pull_request]
on:
push:
branches:
- main
- current-release
- "*LTS"
tags:
- "!*" # Do not execute on tags
pull_request:
branches:
- main
- current-release
- "*LTS"
jobs:
test:
runs-on: ${{ matrix.os }}
@@ -23,7 +23,6 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
@@ -32,9 +31,10 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install tox
- uses: paambaati/codeclimate-action@v2.5.3
if: always()
env:
CC_TEST_REPORTER_ID: ${{ secrets.CODECLIMATE }}
- name: Run coverage
run: tox -e coverage
continue-on-error: true
- uses: codecov/codecov-action@v2
with:
coverageCommand: tox -e coverage
files: ./coverage.xml
fail_ci_if_error: false

View File

@@ -3,9 +3,13 @@ on:
pull_request:
branches:
- main
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
bandit:
if: github.event.pull_request.draft == false
name: type-check-${{ matrix.config.python-version }}
runs-on: ${{ matrix.os }}
strategy:
@@ -13,9 +17,10 @@ jobs:
matrix:
os: [ubuntu-latest]
config:
- { python-version: 3.7, tox-env: security}
- { 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}
steps:
- name: Checkout the repository
uses: actions/checkout@v2

View File

@@ -3,15 +3,19 @@ on:
pull_request:
branches:
- main
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
docsLinter:
if: github.event.pull_request.draft == false
name: Lint Documentation
runs-on: ubuntu-latest
strategy:
matrix:
config:
- {python-version: "3.8", tox-env: "docs"}
- {python-version: "3.10", tox-env: "docs"}
fail-fast: false

View File

@@ -3,9 +3,13 @@ on:
pull_request:
branches:
- main
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
linter:
if: github.event.pull_request.draft == false
name: lint
runs-on: ${{ matrix.os }}
strategy:
@@ -13,7 +17,7 @@ jobs:
matrix:
os: [ubuntu-latest]
config:
- { python-version: 3.8, tox-env: lint}
- { python-version: "3.10", tox-env: lint}
steps:
- name: Checkout the repository
uses: actions/checkout@v2

View File

@@ -5,11 +5,11 @@ on:
tox-env:
description: "Tox Env to run on the PyPy Infra"
required: false
default: "pypy37"
default: "pypy310"
pypy-version:
description: "Version of PyPy to use"
required: false
default: "pypy-3.7"
default: "pypy-3.10"
jobs:
testPyPy:
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}

48
.github/workflows/pr-python310.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Python 3.10 Tests
on:
pull_request:
branches:
- main
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
testPy310:
if: github.event.pull_request.draft == false
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest]
config:
- {
python-version: "3.10",
tox-env: py310,
ignore-error-flake: "false",
command-timeout: "0",
}
- {
python-version: "3.10",
tox-env: py310-no-ext,
ignore-error-flake: "true",
command-timeout: "600000",
}
steps:
- name: Checkout the Repository
uses: actions/checkout@v2
id: checkout-branch
- name: Run Unit Tests
uses: harshanarayana/custom-actions@main
with:
python-version: ${{ matrix.config.python-version }}
test-infra-tool: tox
test-infra-version: latest
action: tests
test-additional-args: "-e=${{ matrix.config.tox-env }},-vv=''"
experimental-ignore-error: "${{ matrix.config.ignore-error-flake }}"
command-timeout: "${{ matrix.config.command-timeout }}"
test-failure-retry: "3"

48
.github/workflows/pr-python311.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Python 3.11 Tests
on:
pull_request:
branches:
- main
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
testPy311:
if: github.event.pull_request.draft == false
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest]
config:
- {
python-version: "3.11",
tox-env: py311,
ignore-error-flake: "false",
command-timeout: "0",
}
- {
python-version: "3.11",
tox-env: py311-no-ext,
ignore-error-flake: "true",
command-timeout: "600000",
}
steps:
- name: Checkout the Repository
uses: actions/checkout@v2
id: checkout-branch
- name: Run Unit Tests
uses: harshanarayana/custom-actions@main
with:
python-version: ${{ matrix.config.python-version }}
test-infra-tool: tox
test-infra-version: latest
action: tests
test-additional-args: "-e=${{ matrix.config.tox-env }},-vv=''"
experimental-ignore-error: "${{ matrix.config.ignore-error-flake }}"
command-timeout: "${{ matrix.config.command-timeout }}"
test-failure-retry: "3"

View File

@@ -1,38 +0,0 @@
name: Python 3.7 Tests
on:
pull_request:
branches:
- main
push:
branches:
- main
paths:
- sanic/*
- tests/*
jobs:
testPy37:
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest]
config:
- { python-version: 3.7, tox-env: py37 }
- { python-version: 3.7, tox-env: py37-no-ext }
steps:
- name: Checkout the Repository
uses: actions/checkout@v2
id: checkout-branch
- name: Run Unit Tests
uses: harshanarayana/custom-actions@main
with:
python-version: ${{ matrix.config.python-version }}
test-infra-tool: tox
test-infra-version: latest
action: tests
test-additional-args: "-e=${{ matrix.config.tox-env }}"
test-failure-retry: "3"

View File

@@ -3,19 +3,17 @@ on:
pull_request:
branches:
- main
push:
branches:
- main
paths:
- sanic/*
- tests/*
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
testPy38:
if: github.event.pull_request.draft == false
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
fail-fast: true
matrix:
# os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest]

View File

@@ -3,19 +3,17 @@ on:
pull_request:
branches:
- main
push:
branches:
- main
paths:
- sanic/*
- tests/*
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
testPy39:
if: github.event.pull_request.draft == false
name: ut-${{ matrix.config.tox-env }}-${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
fail-fast: true
matrix:
# os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest]

View File

@@ -3,9 +3,13 @@ on:
pull_request:
branches:
- main
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
typeChecking:
if: github.event.pull_request.draft == false
name: type-check-${{ matrix.config.python-version }}
runs-on: ${{ matrix.os }}
strategy:
@@ -13,9 +17,10 @@ jobs:
matrix:
os: [ubuntu-latest]
config:
- { python-version: 3.7, tox-env: type-checking}
- { 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}
steps:
- name: Checkout the repository
uses: actions/checkout@v2

View File

@@ -3,19 +3,23 @@ on:
pull_request:
branches:
- main
- current-release
- "*LTS"
types: [opened, synchronize, reopened, ready_for_review]
jobs:
testsOnWindows:
if: github.event.pull_request.draft == false
name: ut-${{ matrix.config.tox-env }}
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
config:
- { python-version: 3.7, tox-env: py37-no-ext }
- { python-version: 3.8, tox-env: py38-no-ext }
- { python-version: 3.9, tox-env: py39-no-ext }
- { python-version: pypy-3.7, tox-env: pypy37-no-ext }
- { python-version: "3.10", tox-env: py310-no-ext }
- { python-version: "3.11", tox-env: py310-no-ext }
steps:
- name: Checkout Repository

View File

@@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: true
matrix:
python-version: ["3.7", "3.8", "3.9"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- name: Checkout repository

View File

@@ -1,28 +1,39 @@
name: Publish Artifacts
name: Upload Python Package
on:
release:
types: [created]
workflow_dispatch:
jobs:
publishPythonPackage:
name: Publishing Sanic Release Artifacts
build-n-publish:
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
python-version: ["3.8"]
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Publish Python Package
uses: harshanarayana/custom-actions@main
with:
python-version: ${{ matrix.python-version }}
package-infra-name: "twine"
pypi-user: __token__
pypi-access-token: ${{ secrets.PYPI_ACCESS_TOKEN }}
action: "package-publish"
pypi-verify-metadata: "true"
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Install pypa/build
run: >-
python3 -m
pip install
build
--user
- name: Build a binary wheel and a source tarball
run: >-
python3 -m
build
--sdist
--wheel
--outdir dist/
.
# - name: Publish distribution 📦 to Test PyPI
# uses: pypa/gh-action-pypi-publish@release/v1
# with:
# password: ${{ secrets.SANIC_TEST_PYPI_API_TOKEN }}
# repository-url: https://test.pypi.org/legacy/
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.SANIC_PYPI_API_TOKEN }}

1
.gitignore vendored
View File

@@ -21,4 +21,5 @@ dist/*
pip-wheel-metadata/
.pytest_cache/*
.venv/*
venv/*
.vscode/*

View File

@@ -1,12 +1,12 @@
.. note::
From v21.9, CHANGELOG files are maintained in ``./docs/sanic/releases``
CHANGELOG files are maintained in ``./docs/sanic/releases``. To view the full CHANGELOG, please visit https://sanic.readthedocs.io/en/stable/sanic/changelog.html.
Version 21.6.1
--------------
Bugfixes
********
**Bugfixes**
* `#2178 <https://github.com/sanic-org/sanic/pull/2178>`_
Update sanic-routing to allow for better splitting of complex URI templates
@@ -20,8 +20,7 @@ Bugfixes
Version 21.6.0
--------------
Features
********
**Features**
* `#2094 <https://github.com/sanic-org/sanic/pull/2094>`_
Add ``response.eof()`` method for closing a stream in a handler
@@ -68,8 +67,7 @@ Features
* `#2170 <https://github.com/sanic-org/sanic/pull/2170>`_
Additional methods for attaching ``HTTPMethodView``
Bugfixes
********
**Bugfixes**
* `#2091 <https://github.com/sanic-org/sanic/pull/2091>`_
Fix ``UserWarning`` in ASGI mode for missing ``__slots__``
@@ -85,8 +83,7 @@ Bugfixes
Fix issue where Blueprint exception handlers do not consistently route to proper handler
Deprecations and Removals
*************************
**Deprecations and Removals**
* `#2156 <https://github.com/sanic-org/sanic/pull/2156>`_
Remove config value ``REQUEST_BUFFER_QUEUE_SIZE``
@@ -95,14 +92,12 @@ Deprecations and Removals
* `#2172 <https://github.com/sanic-org/sanic/pull/2170>`_
Deprecate StreamingHTTPResponse
Developer infrastructure
************************
**Developer infrastructure**
* `#2149 <https://github.com/sanic-org/sanic/pull/2149>`_
Remove Travis CI in favor of GitHub Actions
Improved Documentation
**********************
**Improved Documentation**
* `#2164 <https://github.com/sanic-org/sanic/pull/2164>`_
Fix typo in documentation
@@ -112,8 +107,7 @@ Improved Documentation
Version 21.3.2
--------------
Bugfixes
********
**Bugfixes**
* `#2081 <https://github.com/sanic-org/sanic/pull/2081>`_
Disable response timeout on websocket connections
@@ -124,8 +118,7 @@ Bugfixes
Version 21.3.1
--------------
Bugfixes
********
**Bugfixes**
* `#2076 <https://github.com/sanic-org/sanic/pull/2076>`_
Static files inside subfolders are not accessible (404)
@@ -135,8 +128,7 @@ Version 21.3.0
`Release Notes <https://sanicframework.org/en/guide/release-notes/v21.3.html>`_
Features
********
**Features**
*
`#1876 <https://github.com/sanic-org/sanic/pull/1876>`_
@@ -189,8 +181,7 @@ Features
`#2063 <https://github.com/sanic-org/sanic/pull/2063>`_
App and connection level context objects
Bugfixes and issues resolved
****************************
**Bugfixes**
* Resolve `#1420 <https://github.com/sanic-org/sanic/pull/1420>`_
``url_for`` where ``strict_slashes`` are on for a path ending in ``/``
@@ -220,8 +211,7 @@ Bugfixes and issues resolved
`#2001 <https://github.com/sanic-org/sanic/pull/2001>`_
Raise ValueError when cookie max-age is not an integer
Deprecations and Removals
*************************
**Deprecations and Removals**
*
`#2007 <https://github.com/sanic-org/sanic/pull/2007>`_
@@ -240,8 +230,7 @@ Deprecations and Removals
* ``Request.endpoint`` deprecated in favor of ``Request.name``
* handler type name prefixes removed (static, websocket, etc)
Developer infrastructure
************************
**Developer infrastructure**
*
`#1995 <https://github.com/sanic-org/sanic/pull/1995>`_
@@ -259,8 +248,7 @@ Developer infrastructure
`#2049 <https://github.com/sanic-org/sanic/pull/2049>`_
Updated setup.py to use ``find_packages``
Improved Documentation
**********************
**Improved Documentation**
*
`#1218 <https://github.com/sanic-org/sanic/pull/1218>`_
@@ -282,8 +270,7 @@ Improved Documentation
`#2052 <https://github.com/sanic-org/sanic/pull/2052>`_
Fix some examples and docs
Miscellaneous
*************
**Miscellaneous**
* ``Request.route`` property
* Better websocket subprotocols support
@@ -329,8 +316,7 @@ Miscellaneous
Version 20.12.3
---------------
Bugfixes
********
**Bugfixes**
*
`#2021 <https://github.com/sanic-org/sanic/pull/2021>`_
@@ -339,8 +325,7 @@ Bugfixes
Version 20.12.2
---------------
Dependencies
************
**Dependencies**
*
`#2026 <https://github.com/sanic-org/sanic/pull/2026>`_
@@ -353,8 +338,7 @@ Dependencies
Version 19.12.5
---------------
Dependencies
************
**Dependencies**
*
`#2025 <https://github.com/sanic-org/sanic/pull/2025>`_
@@ -367,19 +351,12 @@ Dependencies
Version 20.12.0
---------------
Features
********
**Features**
*
`#1993 <https://github.com/sanic-org/sanic/pull/1993>`_
Add disable app registry
Version 20.12.0
---------------
Features
********
*
`#1945 <https://github.com/sanic-org/sanic/pull/1945>`_
Static route more verbose if file not found
@@ -416,22 +393,19 @@ Features
`#1979 <https://github.com/sanic-org/sanic/pull/1979>`_
Add app registry and Sanic class level app retrieval
Bugfixes
********
**Bugfixes**
*
`#1965 <https://github.com/sanic-org/sanic/pull/1965>`_
Fix Chunked Transport-Encoding in ASGI streaming response
Deprecations and Removals
*************************
**Deprecations and Removals**
*
`#1981 <https://github.com/sanic-org/sanic/pull/1981>`_
Cleanup and remove deprecated code
Developer infrastructure
************************
**Developer infrastructure**
*
`#1956 <https://github.com/sanic-org/sanic/pull/1956>`_
@@ -445,8 +419,7 @@ Developer infrastructure
`#1986 <https://github.com/sanic-org/sanic/pull/1986>`_
Update tox requirements
Improved Documentation
**********************
**Improved Documentation**
*
`#1951 <https://github.com/sanic-org/sanic/pull/1951>`_
@@ -464,8 +437,7 @@ Improved Documentation
Version 20.9.1
---------------
Bugfixes
********
**Bugfixes**
*
`#1954 <https://github.com/sanic-org/sanic/pull/1954>`_
@@ -478,8 +450,7 @@ Bugfixes
Version 19.12.3
---------------
Bugfixes
********
**Bugfixes**
*
`#1959 <https://github.com/sanic-org/sanic/pull/1959>`_
@@ -490,8 +461,7 @@ Version 20.9.0
---------------
Features
********
**Features**
*
`#1887 <https://github.com/sanic-org/sanic/pull/1887>`_
@@ -518,22 +488,19 @@ Features
`#1937 <https://github.com/sanic-org/sanic/pull/1937>`_
Added auto, text, and json fallback error handlers (in v21.3, the default will change form html to auto)
Bugfixes
********
**Bugfixes**
*
`#1897 <https://github.com/sanic-org/sanic/pull/1897>`_
Resolves exception from unread bytes in stream
Deprecations and Removals
*************************
**Deprecations and Removals**
*
`#1903 <https://github.com/sanic-org/sanic/pull/1903>`_
config.from_envar, config.from_pyfile, and config.from_object are deprecated and set to be removed in v21.3
Developer infrastructure
************************
**Developer infrastructure**
*
`#1890 <https://github.com/sanic-org/sanic/pull/1890>`_,
@@ -548,8 +515,7 @@ Developer infrastructure
`#1924 <https://github.com/sanic-org/sanic/pull/1924>`_
Adding --strict-markers for pytest
Improved Documentation
**********************
**Improved Documentation**
*
`#1922 <https://github.com/sanic-org/sanic/pull/1922>`_
@@ -559,8 +525,7 @@ Improved Documentation
Version 20.6.3
---------------
Bugfixes
********
**Bugfixes**
*
`#1884 <https://github.com/sanic-org/sanic/pull/1884>`_
@@ -570,8 +535,7 @@ Bugfixes
Version 20.6.2
---------------
Features
********
**Features**
*
`#1641 <https://github.com/sanic-org/sanic/pull/1641>`_
@@ -581,8 +545,7 @@ Features
Version 20.6.1
---------------
Features
********
**Features**
*
`#1760 <https://github.com/sanic-org/sanic/pull/1760>`_
@@ -596,8 +559,7 @@ Features
`#1880 <https://github.com/sanic-org/sanic/pull/1880>`_
Add handler names for websockets for url_for usage
Bugfixes
********
**Bugfixes**
*
`#1776 <https://github.com/sanic-org/sanic/pull/1776>`_
@@ -619,15 +581,13 @@ Bugfixes
`#1853 <https://github.com/sanic-org/sanic/pull/1853>`_
Fix pickle error when attempting to pickle an application which contains websocket routes
Deprecations and Removals
*************************
**Deprecations and Removals**
*
`#1739 <https://github.com/sanic-org/sanic/pull/1739>`_
Deprecate body_bytes to merge into body
Developer infrastructure
************************
**Developer infrastructure**
*
`#1852 <https://github.com/sanic-org/sanic/pull/1852>`_
@@ -642,8 +602,7 @@ Developer infrastructure
Wrap run()'s "protocol" type annotation in Optional[]
Improved Documentation
**********************
**Improved Documentation**
*
`#1846 <https://github.com/sanic-org/sanic/pull/1846>`_
@@ -657,14 +616,13 @@ Improved Documentation
Version 20.6.0
---------------
*Released, but unintentionally ommitting PR #1880, so was replaced by 20.6.1*
*Released, but unintentionally omitting PR #1880, so was replaced by 20.6.1*
Version 20.3.0
---------------
Features
********
**Features**
*
`#1762 <https://github.com/sanic-org/sanic/pull/1762>`_
@@ -695,8 +653,7 @@ Features
`#1820 <https://github.com/sanic-org/sanic/pull/1820>`_
Do not set content-type and content-length headers in exceptions
Bugfixes
********
**Bugfixes**
*
`#1748 <https://github.com/sanic-org/sanic/pull/1748>`_
@@ -714,8 +671,7 @@ Bugfixes
`#1808 <https://github.com/sanic-org/sanic/pull/1808>`_
Fix Ctrl+C and tests on Windows
Deprecations and Removals
*************************
**Deprecations and Removals**
*
`#1800 <https://github.com/sanic-org/sanic/pull/1800>`_
@@ -733,8 +689,7 @@ Deprecations and Removals
`#1818 <https://github.com/sanic-org/sanic/pull/1818>`_
Complete deprecation of ``app.remove_route`` and ``request.raw_args``
Dependencies
************
**Dependencies**
*
`#1794 <https://github.com/sanic-org/sanic/pull/1794>`_
@@ -744,15 +699,13 @@ Dependencies
`#1806 <https://github.com/sanic-org/sanic/pull/1806>`_
Import ``ASGIDispatch`` from top-level ``httpx`` (from third-party deprecation)
Developer infrastructure
************************
**Developer infrastructure**
*
`#1833 <https://github.com/sanic-org/sanic/pull/1833>`_
Resolve broken documentation builds
Improved Documentation
**********************
**Improved Documentation**
*
`#1755 <https://github.com/sanic-org/sanic/pull/1755>`_
@@ -794,8 +747,7 @@ Improved Documentation
Version 19.12.0
---------------
Bugfixes
********
**Bugfixes**
- Fix blueprint middleware application
@@ -814,8 +766,7 @@ Bugfixes
due to an `AttributeError`. This fix makes the availability of `SERVER_NAME` on our `app.config` an optional behavior. (`#1707 <https://github.com/sanic-org/sanic/issues/1707>`__)
Improved Documentation
**********************
**Improved Documentation**
- Move docs from MD to RST
@@ -829,8 +780,7 @@ Improved Documentation
Version 19.6.3
--------------
Features
********
**Features**
- Enable Towncrier Support
@@ -838,8 +788,7 @@ Features
of generating and managing change logs as part of each of pull requests. (`#1631 <https://github.com/sanic-org/sanic/issues/1631>`__)
Improved Documentation
**********************
**Improved Documentation**
- Documentation infrastructure changes
@@ -852,8 +801,7 @@ Improved Documentation
Version 19.6.2
--------------
Features
********
**Features**
*
`#1562 <https://github.com/sanic-org/sanic/pull/1562>`_
@@ -869,8 +817,7 @@ Features
Add Configure support from object string
Bugfixes
********
**Bugfixes**
*
`#1587 <https://github.com/sanic-org/sanic/pull/1587>`_
@@ -888,8 +835,7 @@ Bugfixes
`#1594 <https://github.com/sanic-org/sanic/pull/1594>`_
Strict Slashes behavior fix
Deprecations and Removals
*************************
**Deprecations and Removals**
*
`#1544 <https://github.com/sanic-org/sanic/pull/1544>`_
@@ -913,8 +859,7 @@ Deprecations and Removals
Version 19.3
------------
Features
********
**Features**
*
`#1497 <https://github.com/sanic-org/sanic/pull/1497>`_
@@ -982,8 +927,7 @@ Features
This is a breaking change.
Bugfixes
********
**Bugfixes**
*
@@ -1019,8 +963,7 @@ Bugfixes
This allows the access log to be disabled for example when running via
gunicorn.
Developer infrastructure
************************
**Developer infrastructure**
* `#1529 <https://github.com/sanic-org/sanic/pull/1529>`_ Update project PyPI credentials
* `#1515 <https://github.com/sanic-org/sanic/pull/1515>`_ fix linter issue causing travis build failures (fix #1514)
@@ -1028,8 +971,7 @@ Developer infrastructure
* `#1478 <https://github.com/sanic-org/sanic/pull/1478>`_ Upgrade setuptools version and use native docutils in doc build
* `#1464 <https://github.com/sanic-org/sanic/pull/1464>`_ Upgrade pytest, and fix caplog unit tests
Improved Documentation
**********************
**Improved Documentation**
* `#1516 <https://github.com/sanic-org/sanic/pull/1516>`_ Fix typo at the exception documentation
* `#1510 <https://github.com/sanic-org/sanic/pull/1510>`_ fix typo in Asyncio example
@@ -1090,21 +1032,19 @@ Version 18.12
* Fix Range header handling for static files (#1402)
* Fix the logger and make it work (#1397)
* Fix type pikcle->pickle in multiprocessing test
* Fix pickling blueprints Change the string passed in the "name" section of the namedtuples in Blueprint to match the name of the Blueprint module attribute name. This allows blueprints to be pickled and unpickled, without errors, which is a requirment of running Sanic in multiprocessing mode in Windows. Added a test for pickling and unpickling blueprints Added a test for pickling and unpickling sanic itself Added a test for enabling multiprocessing on an app with a blueprint (only useful to catch this bug if the tests are run on Windows).
* Fix pickling blueprints Change the string passed in the "name" section of the namedtuples in Blueprint to match the name of the Blueprint module attribute name. This allows blueprints to be pickled and unpickled, without errors, which is a requirement of running Sanic in multiprocessing mode in Windows. Added a test for pickling and unpickling blueprints Added a test for pickling and unpickling sanic itself Added a test for enabling multiprocessing on an app with a blueprint (only useful to catch this bug if the tests are run on Windows).
* Fix document for logging
Version 0.8
-----------
0.8.3
*****
**0.8.3**
* Changes:
* Ownership changed to org 'sanic-org'
0.8.0
*****
**0.8.0**
* Changes:
@@ -1129,7 +1069,7 @@ Version 0.8
* Content-length header on 204/304 responses (Arnulfo Solís)
* Extend WebSocketProtocol arguments and add docs (Bob Olde Hampsink, yunstanford)
* Update development status from pre-alpha to beta (Maksim Anisenkov)
* KeepAlive Timout log level changed to debug (Arnulfo Solís)
* KeepAlive Timeout log level changed to debug (Arnulfo Solís)
* Pin pytest to 3.3.2 because of pytest-dev/pytest#3170 (Maksim Aniskenov)
* Install Python 3.5 and 3.6 on docker container for tests (Shahin Azad)
* Add support for blueprint groups and nesting (Elias Tarhini)
@@ -1184,19 +1124,16 @@ Version 0.1
-----------
0.1.7
*****
**0.1.7**
* Reversed static url and directory arguments to meet spec
0.1.6
*****
**0.1.6**
* Static files
* Lazy Cookie Loading
0.1.5
*****
**0.1.5**
* Cookies
* Blueprint listeners and ordering
@@ -1204,23 +1141,19 @@ Version 0.1
* 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
*****
**0.1.4**
* Multiprocessing
0.1.3
*****
**0.1.3**
* Blueprint support
* Faster Response processing
0.1.1 - 0.1.2
*************
**0.1.1 - 0.1.2**
* Struggling to update pypi via CI
0.1.0
*****
**0.1.0**
* Released to public

View File

@@ -55,7 +55,7 @@ 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 sanic-maintainers@googlegroups.com. All
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.

View File

@@ -71,9 +71,9 @@ To execute only unittests, run ``tox`` with environment like so:
.. code-block:: bash
tox -e py36 -v -- tests/test_config.py
# or
tox -e py37 -v -- tests/test_config.py
# or
tox -e py310 -v -- tests/test_config.py
Run lint checks
---------------
@@ -140,6 +140,7 @@ 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
*****
@@ -167,7 +168,13 @@ flake8
#. pycodestyle
#. Ned Batchelder's McCabe script
``isort``\ , ``black`` and ``flake8`` checks are performed during ``tox`` lint checks.
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.

View File

@@ -66,15 +66,15 @@ ifdef include_tests
isort -rc sanic tests
else
$(info Sorting Imports)
isort -rc sanic tests --profile=black
isort -rc sanic tests
endif
endif
black:
black --config ./.black.toml sanic tests
black sanic tests
isort:
isort sanic tests --profile=black
isort sanic tests
pretty: black isort

View File

@@ -11,7 +11,7 @@ Sanic | Build fast. Run fast.
:stub-columns: 1
* - Build
- | |Py39Test| |Py38Test| |Py37Test| |Codecov|
- | |Py310Test| |Py39Test| |Py38Test| |Py37Test|
* - Docs
- | |UserGuide| |Documentation|
* - Package
@@ -27,8 +27,8 @@ Sanic | Build fast. Run fast.
:target: https://community.sanicframework.org/
.. |Discord| image:: https://img.shields.io/discord/812221182594121728?logo=discord
:target: https://discord.gg/FARQzAEMAA
.. |Codecov| image:: https://codecov.io/gh/sanic-org/sanic/branch/master/graph/badge.svg
:target: https://codecov.io/gh/sanic-org/sanic
.. |Py310Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python310.yml/badge.svg?branch=main
:target: https://github.com/sanic-org/sanic/actions/workflows/pr-python310.yml
.. |Py39Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python39.yml/badge.svg?branch=main
:target: https://github.com/sanic-org/sanic/actions/workflows/pr-python39.yml
.. |Py38Test| image:: https://github.com/sanic-org/sanic/actions/workflows/pr-python38.yml/badge.svg?branch=main
@@ -66,7 +66,7 @@ Sanic | Build fast. Run fast.
Sanic is a **Python 3.7+** 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://sanic.readthedocs.io/en/latest/sanic/deploying.html#running-via-asgi>`_.
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>`_
@@ -77,7 +77,11 @@ The goal of the project is to provide a simple way to get up and running a highl
Sponsor
-------
Check out `open collective <https://opencollective.com/sanic-org>`_ to learn more about helping to fund Sanic.
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
------------
@@ -98,9 +102,6 @@ Installation
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.
.. note::
Windows support is currently "experimental" and on a best-effort basis. Multiple workers are also not currently supported on Windows (see `Issue #1517 <https://github.com/sanic-org/sanic/issues/1517>`_), but setting ``workers=1`` should launch the server successfully.
Hello World Example
-------------------
@@ -110,7 +111,7 @@ Hello World Example
from sanic import Sanic
from sanic.response import json
app = Sanic("My Hello, world app")
app = Sanic("my-hello-world-app")
@app.route('/')
async def test(request):
@@ -162,3 +163,8 @@ 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>`_.
.. |Linode| image:: https://www.linode.com/wp-content/uploads/2021/01/Linode-Logo-Black.svg
:alt: Linode
:target: https://www.linode.com
:width: 200px

View File

@@ -4,31 +4,42 @@
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 |
| ------- | ------------- | ------------------ |
| 20.12 | until 2022-12 | :heavy_check_mark: |
| 20.9 | | :x: |
| 20.6 | | :x: |
| 20.3 | | :x: |
| 19.12 | until 2021-12 | :white_check_mark: |
| 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: |
:white_check_mark: = security/bug fixes
:heavy_check_mark: = full support
| 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.

28
codecov.yml Normal file
View 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/"

View File

@@ -2,3 +2,12 @@
.wy-nav-top {
background: #444444;
}
#changelog section {
padding-left: 3rem;
}
#changelog section h2,
#changelog section h3 {
margin-left: -3rem;
}

View File

@@ -24,7 +24,11 @@ import sanic
# -- General configuration ------------------------------------------------
extensions = ["sphinx.ext.autodoc", "m2r2"]
extensions = [
"sphinx.ext.autodoc",
"m2r2",
"enum_tools.autoenum",
]
templates_path = ["_templates"]

View File

@@ -9,7 +9,7 @@ API
===
.. toctree::
:maxdepth: 2
:maxdepth: 3
👥 User Guide <https://sanicframework.org/guide/>
sanic/api_reference

View File

@@ -15,3 +15,19 @@ 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:

View File

@@ -17,6 +17,14 @@ sanic.handlers
:show-inheritance:
sanic.headers
--------------
.. automodule:: sanic.headers
:members:
:show-inheritance:
sanic.request
-------------
@@ -38,10 +46,3 @@ sanic.views
.. automodule:: sanic.views
:members:
:show-inheritance:
sanic.websocket
---------------
.. automodule:: sanic.websocket
:members:
:show-inheritance:

View File

@@ -16,10 +16,3 @@ sanic.server
:members:
:show-inheritance:
sanic.worker
------------
.. automodule:: sanic.worker
:members:
:show-inheritance:

View File

@@ -1,6 +1,16 @@
📜 Changelog
============
.. mdinclude:: ./releases/21.9.md
| 🔶 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

View 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

View File

@@ -1,4 +1,14 @@
## Version 21.9
## 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

View 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

View 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`

View 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

View 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

View 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

View 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:

View File

@@ -4,12 +4,14 @@ import asyncio
from sanic import Sanic
app = Sanic()
app = Sanic("Example")
async def notify_server_started_after_five_seconds():
await asyncio.sleep(5)
print('Server successfully started!')
print("Server successfully started!")
app.add_task(notify_server_started_after_five_seconds())

View File

@@ -1,30 +1,29 @@
from sanic import Sanic
from sanic.response import text
from random import randint
app = Sanic()
from sanic import Sanic
from sanic.response import text
@app.middleware('request')
app = Sanic("Example")
@app.middleware("request")
def append_request(request):
# Add new key with random value
request['num'] = randint(0, 100)
request.ctx.num = randint(0, 100)
@app.get('/pop')
@app.get("/pop")
def pop_handler(request):
# Pop key from request object
num = request.pop('num')
return text(num)
return text(request.ctx.num)
@app.get('/key_exist')
@app.get("/key_exist")
def key_exist_handler(request):
# Check the key is exist or not
if 'num' in request:
return text('num exist in request')
if hasattr(request.ctx, "num"):
return text("num exist in request")
return text('num does not exist in reqeust')
return text("num does not exist in request")
app.run(host="0.0.0.0", port=8000, debug=True)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)

View File

@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
from sanic import Sanic
from functools import wraps
from sanic import Sanic
from sanic.response import json
app = Sanic()
app = Sanic("Example")
def check_request_for_authorization_status(request):
@@ -27,14 +29,16 @@ def authorized(f):
return response
else:
# the user is not authorized.
return json({'status': 'not_authorized'}, 403)
return json({"status": "not_authorized"}, 403)
return decorated_function
@app.route("/")
@authorized
async def test(request):
return json({'status': 'authorized'})
return json({"status": "authorized"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -1,43 +1,54 @@
from sanic import Sanic, Blueprint
from sanic import Blueprint, Sanic
from sanic.response import text
'''
Demonstrates that blueprint request middleware are executed in the order they
"""
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(__name__)
app = Sanic("Example")
bp = Blueprint("bp_"+__name__)
bp = Blueprint("bp_example")
@bp.middleware('request')
@bp.on_request
def request_middleware_1(request):
print('1')
print("1")
@bp.middleware('request')
@bp.on_request
def request_middleware_2(request):
print('2')
print("2")
@bp.middleware('request')
@bp.on_request
def request_middleware_3(request):
print('3')
print("3")
@bp.middleware('response')
@bp.on_response
def resp_middleware_4(request, response):
print('4')
print("4")
@bp.middleware('response')
@bp.on_response
def resp_middleware_5(request, response):
print('5')
print("5")
@bp.middleware('response')
@bp.on_response
def resp_middleware_6(request, response):
print('6')
print("6")
@bp.route('/')
@bp.route("/")
def pop_handler(request):
return text('hello world')
return text("hello world")
app.blueprint(bp, url_prefix='/bp')
app.run(host="0.0.0.0", port=8000, debug=True, auto_reload=False)
app.blueprint(bp, url_prefix="/bp")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True, auto_reload=False)

View File

@@ -1,10 +1,11 @@
from sanic import Blueprint, Sanic
from sanic.response import file, json
app = Sanic(__name__)
blueprint = Blueprint("name", url_prefix="/my_blueprint")
blueprint2 = Blueprint("name2", url_prefix="/my_blueprint2")
blueprint3 = Blueprint("name3", url_prefix="/my_blueprint3")
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")
@@ -36,4 +37,5 @@ app.blueprint(blueprint)
app.blueprint(blueprint2)
app.blueprint(blueprint3)
app.run(host="0.0.0.0", port=9999, debug=True)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=9999, debug=True)

View File

@@ -2,17 +2,21 @@ from asyncio import sleep
from sanic import Sanic, response
app = Sanic(__name__, strict_slashes=True)
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:number>")
@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__':
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -7,8 +7,10 @@ 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.handlers import ErrorHandler
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)
@@ -16,7 +18,6 @@ Imports and code relevant for our CustomHandler class
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)
@@ -38,17 +39,17 @@ server's error_handler to an instance of our CustomHandler
from sanic import Sanic
app = Sanic(__name__)
handler = CustomHandler()
app.error_handler = handler
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!')
raise SanicException("You Broke It!")
if __name__ == '__main__':
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)

View File

@@ -1,7 +1,7 @@
from sanic import Sanic
from sanic import response
from sanic import Sanic, response
app = Sanic(__name__)
app = Sanic("Example")
@app.route("/")
@@ -9,5 +9,5 @@ async def test(request):
return response.json({"test": True})
if __name__ == '__main__':
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -1,4 +1,6 @@
from sanic import Sanic, response, text
from sanic.handlers import ErrorHandler
from sanic.server.async_server import AsyncioServer
HTTP_PORT = 9999
@@ -27,25 +29,45 @@ def proxy(request, path):
path=path,
_server=https.config.SERVER_NAME,
_external=True,
_scheme="http",
_scheme="https",
)
return response.redirect(url)
@https.listener("main_process_start")
@https.main_process_start
async def start(app, _):
global http
app.http_server = await http.create_server(
http_server = await http.create_server(
port=HTTP_PORT, return_asyncio_server=True
)
app.http_server.after_start()
app.add_task(runner(http, http_server))
app.ctx.http_server = http_server
app.ctx.http = http
@https.listener("main_process_stop")
@https.main_process_stop
async def stop(app, _):
app.http_server.before_stop()
await app.http_server.close()
app.http_server.after_stop()
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
https.run(port=HTTPS_PORT, debug=True)
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)

View File

@@ -1,26 +1,30 @@
import asyncio
import httpx
from sanic import Sanic
from sanic.response import json
import asyncio
import aiohttp
app = Sanic(__name__)
app = Sanic("Example")
sem = None
@app.listener('before_server_start')
def init(sanic, loop):
@app.before_server_start
def init(sanic, _):
global sem
concurrency_per_worker = 4
sem = asyncio.Semaphore(concurrency_per_worker, loop=loop)
sem = asyncio.Semaphore(concurrency_per_worker)
async def bounded_fetch(session, url):
"""
Use session object to perform 'get' request on url
"""
async with sem, session.get(url) as response:
return await response.json()
async with sem:
response = await session.get(url)
return response.json()
@app.route("/")
@@ -28,11 +32,12 @@ async def test(request):
"""
Download and serve example JSON
"""
url = "https://api.github.com/repos/channelcat/sanic"
url = "https://api.github.com/repos/sanic-org/sanic"
async with aiohttp.ClientSession() as session:
async with httpx.AsyncClient() as session:
response = await bounded_fetch(session, url)
return json(response)
app.run(host="0.0.0.0", port=8000, workers=2)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, workers=2)

View File

@@ -1,6 +1,6 @@
import logging
import aiotask_context as context
from contextvars import ContextVar
from sanic import Sanic, response
@@ -11,8 +11,8 @@ log = logging.getLogger(__name__)
class RequestIdFilter(logging.Filter):
def filter(self, record):
try:
record.request_id = context.get("X-Request-ID")
except ValueError:
record.request_id = app.ctx.request_id.get(None) or "n/a"
except AttributeError:
record.request_id = "n/a"
return True
@@ -44,13 +44,12 @@ LOG_SETTINGS = {
}
app = Sanic(__name__, log_config=LOG_SETTINGS)
app = Sanic("Example", log_config=LOG_SETTINGS)
@app.on_request
async def set_request_id(request):
request_id = request.id
context.set("X-Request-ID", request_id)
request.app.ctx.request_id.set(request.id)
log.info(f"Setting {request.id=}")
@@ -61,14 +60,14 @@ async def set_request_header(request, response):
@app.route("/")
async def test(request):
log.debug("X-Request-ID: %s", context.get("X-Request-ID"))
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):
loop.set_task_factory(context.task_factory)
app.ctx.request_id = ContextVar("request_id")
if __name__ == "__main__":

View File

@@ -1,5 +1,6 @@
import logging
import socket
from os import getenv
from platform import node
from uuid import getnode as get_mac
@@ -7,10 +8,11 @@ from uuid import getnode as get_mac
from logdna import LogDNAHandler
from sanic import Sanic
from sanic.response import json
from sanic.request import Request
from sanic.response import json
log = logging.getLogger('logdna')
log = logging.getLogger("logdna")
log.setLevel(logging.INFO)
@@ -30,16 +32,18 @@ logdna_options = {
"index_meta": True,
"hostname": node(),
"ip": get_my_ip_address(),
"mac": get_mac_address()
"mac": get_mac_address(),
}
logdna_handler = LogDNAHandler(getenv("LOGDNA_API_KEY"), options=logdna_options)
logdna_handler = LogDNAHandler(
getenv("LOGDNA_API_KEY"), options=logdna_options
)
logdna = logging.getLogger(__name__)
logdna.setLevel(logging.INFO)
logdna.addHandler(logdna_handler)
app = Sanic(__name__)
app = Sanic("Example")
@app.middleware
@@ -49,13 +53,8 @@ def log_request(request: Request):
@app.route("/")
def default(request):
return json({
"response": "I was here"
})
return json({"response": "I was here"})
if __name__ == "__main__":
app.run(
host="0.0.0.0",
port=getenv("PORT", 8080)
)
app.run(host="0.0.0.0", port=getenv("PORT", 8080))

View File

@@ -2,27 +2,29 @@
Modify header or status in response
"""
from sanic import Sanic
from sanic import response
app = Sanic(__name__)
from sanic import Sanic, response
@app.route('/')
app = Sanic("Example")
@app.route("/")
def handle_request(request):
return response.json(
{'message': 'Hello world!'},
headers={'X-Served-By': 'sanic'},
status=200
{"message": "Hello world!"},
headers={"X-Served-By": "sanic"},
status=200,
)
@app.route('/unauthorized')
@app.route("/unauthorized")
def handle_request(request):
return response.json(
{'message': 'You are not authorized'},
headers={'X-Served-By': 'sanic'},
status=404
{"message": "You are not authorized"},
headers={"X-Served-By": "sanic"},
status=404,
)
app.run(host="0.0.0.0", port=8000, debug=True)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)

View File

@@ -20,4 +20,5 @@ def test(request):
return text("hey")
app.run(host="0.0.0.0", port=8000)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -32,7 +32,7 @@ def test_port(worker_id):
@pytest.fixture(scope="session")
def app():
app = Sanic()
app = Sanic("Example")
@app.route("/")
async def index(request):

View File

@@ -8,7 +8,6 @@ from sanic.handlers import ErrorHandler
class RaygunExceptionReporter(ErrorHandler):
def __init__(self, raygun_api_key=None):
super().__init__()
if raygun_api_key is None:
@@ -22,16 +21,13 @@ class RaygunExceptionReporter(ErrorHandler):
raygun_error_reporter = RaygunExceptionReporter()
app = Sanic(__name__, error_handler=raygun_error_reporter)
app = Sanic("Example", error_handler=raygun_error_reporter)
@app.route("/raise")
async def test(request):
raise SanicException('You Broke It!')
raise SanicException("You Broke It!")
if __name__ == '__main__':
app.run(
host="0.0.0.0",
port=getenv("PORT", 8080)
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=getenv("PORT", 8080))

View File

@@ -1,18 +1,18 @@
from sanic import Sanic
from sanic import response
from sanic import Sanic, response
app = Sanic(__name__)
@app.route('/')
app = Sanic("Example")
@app.route("/")
def handle_request(request):
return response.redirect('/redirect')
return response.redirect("/redirect")
@app.route('/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)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -6,5 +6,5 @@ data = ""
for i in range(1, 250000):
data += str(i)
r = requests.post('http://0.0.0.0:8000/stream', data=data)
r = requests.post("http://0.0.0.0:8000/stream", data=data)
print(r.text)

View File

@@ -1,65 +1,63 @@
from sanic import Sanic
from sanic.views import CompositionView
from sanic.views import HTTPMethodView
from sanic.views import stream as stream_decorator
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('blueprint_request_stream')
app = Sanic('request_stream')
bp = Blueprint("bp_example")
app = Sanic("Example")
class SimpleView(HTTPMethodView):
@stream_decorator
async def post(self, request):
result = ''
result = ""
while True:
body = await request.stream.get()
if body is None:
break
result += body.decode('utf-8')
result += body.decode("utf-8")
return text(result)
@app.post('/stream', stream=True)
@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')
body = body.decode("utf-8").replace("1", "A")
await response.write(body)
return stream(streaming)
@bp.put('/bp_stream', stream=True)
@bp.put("/bp_stream", stream=True)
async def bp_handler(request):
result = ''
result = ""
while True:
body = await request.stream.get()
if body is None:
break
result += body.decode('utf-8').replace('1', 'A')
result += body.decode("utf-8").replace("1", "A")
return text(result)
async def post_handler(request):
result = ''
result = ""
while True:
body = await request.stream.get()
if body is None:
break
result += body.decode('utf-8')
result += body.decode("utf-8")
return text(result)
app.blueprint(bp)
app.add_route(SimpleView.as_view(), '/method_view')
view = CompositionView()
view.add(['POST'], post_handler, stream=True)
app.add_route(view, '/composition_view')
app.add_route(SimpleView.as_view(), "/method_view")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -1,21 +1,24 @@
import asyncio
from sanic import Sanic
from sanic import response
from sanic import Sanic, response
from sanic.config import Config
from sanic.exceptions import RequestTimeout
Config.REQUEST_TIMEOUT = 1
app = Sanic(__name__)
app = Sanic("Example")
@app.route('/')
@app.route("/")
async def test(request):
await asyncio.sleep(3)
return response.text('Hello, world!')
return response.text("Hello, world!")
@app.exception(RequestTimeout)
def timeout(request, exception):
return response.text('RequestTimeout from error_handler.', 408)
return response.text("RequestTimeout from error_handler.", 408)
app.run(host='0.0.0.0', port=8000)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -1,21 +1,22 @@
from os import getenv
import rollbar
from sanic.handlers import ErrorHandler
from sanic import Sanic
from sanic.exceptions import SanicException
from os import getenv
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(__name__, error_handler=RollbarExceptionHandler())
app = Sanic("Example", error_handler=RollbarExceptionHandler())
@app.route("/raise")
@@ -24,7 +25,4 @@ def create_error(request):
if __name__ == "__main__":
app.run(
host="0.0.0.0",
port=getenv("PORT", 8080)
)
app.run(host="0.0.0.0", port=getenv("PORT", 8080))

View File

@@ -11,7 +11,7 @@ from pathlib import Path
from sanic import Sanic, response
app = Sanic(__name__)
app = Sanic("Example")
@app.route("/text")
@@ -59,31 +59,31 @@ async def handler_stream(request):
return response.stream(body)
@app.listener("before_server_start")
@app.before_server_start
async def listener_before_server_start(*args, **kwargs):
print("before_server_start")
@app.listener("after_server_start")
@app.after_server_start
async def listener_after_server_start(*args, **kwargs):
print("after_server_start")
@app.listener("before_server_stop")
@app.before_server_stop
async def listener_before_server_stop(*args, **kwargs):
print("before_server_stop")
@app.listener("after_server_stop")
@app.after_server_stop
async def listener_after_server_stop(*args, **kwargs):
print("after_server_stop")
@app.middleware("request")
@app.on_request
async def print_on_request(request):
print("print_on_request")
@app.middleware("response")
@app.on_response
async def print_on_response(request, response):
print("print_on_response")

View File

@@ -1,22 +1,30 @@
from sanic import Sanic
from sanic import response
from signal import signal, SIGINT
import asyncio
import uvloop
app = Sanic(__name__)
from sanic import Sanic, response
app = Sanic("Example")
@app.route("/")
async def test(request):
return response.json({"answer": "42"})
asyncio.set_event_loop(uvloop.new_event_loop())
server = app.create_server(host="0.0.0.0", port=8000, return_asyncio_server=True)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(server)
signal(SIGINT, lambda s, f: loop.stop())
try:
loop.run_forever()
except:
loop.stop()
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())

View File

@@ -8,46 +8,61 @@ from sanic import Sanic, response
from sanic.server import AsyncioServer
app = Sanic(__name__)
app = Sanic("Example")
@app.listener("after_server_start")
async def after_start_test(app, loop):
print("Async Server Started!")
@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())
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) # type: ignore
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())
# 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.
server.before_start()
server.after_start()
try:
loop.run_forever()
except KeyboardInterrupt:
loop.stop()
finally:
server.before_stop()
# Wait for server to close
close_task = server.close()
loop.run_until_complete(close_task)
# 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()
server.after_stop()
# Complete all tasks on the loop
for connection in server.connections:
connection.close_if_idle()
loop.run_until_complete(server.after_stop())

View File

@@ -6,20 +6,19 @@ 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(__name__)
app = Sanic("Example")
# noinspection PyUnusedLocal
@app.route("/working")
async def working_path(request):
return json({
"response": "Working API Response"
})
return json({"response": "Working API Response"})
# noinspection PyUnusedLocal
@@ -28,8 +27,5 @@ async def raise_error(request):
raise Exception("Testing Sentry Integration")
if __name__ == '__main__':
app.run(
host="0.0.0.0",
port=getenv("PORT", 8080)
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=getenv("PORT", 8080))

View File

@@ -1,42 +1,41 @@
from sanic import Sanic
from sanic.views import HTTPMethodView
from sanic.response import text
from sanic.views import HTTPMethodView
app = Sanic('some_name')
app = Sanic("some_name")
class SimpleView(HTTPMethodView):
def get(self, request):
return text('I am get method')
return text("I am get method")
def post(self, request):
return text('I am post method')
return text("I am post method")
def put(self, request):
return text('I am put method')
return text("I am put method")
def patch(self, request):
return text('I am patch method')
return text("I am patch method")
def delete(self, request):
return text('I am delete method')
return text("I am delete method")
class SimpleAsyncView(HTTPMethodView):
async def get(self, request):
return text('I am async get method')
return text("I am async get method")
async def post(self, request):
return text('I am async post method')
return text("I am async post method")
async def put(self, request):
return text('I am async put method')
return text("I am async put method")
app.add_route(SimpleView.as_view(), '/')
app.add_route(SimpleAsyncView.as_view(), '/async')
app.add_route(SimpleView.as_view(), "/")
app.add_route(SimpleAsyncView.as_view(), "/async")
if __name__ == '__main__':
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)

View File

@@ -1,6 +1,6 @@
from sanic import Sanic
app = Sanic(__name__)
app = Sanic("Example")
app.static("/", "./static")

View File

@@ -1,13 +1,14 @@
from sanic import Sanic
from sanic import response as res
app = Sanic(__name__)
app = Sanic("Example")
@app.route("/")
async def test(req):
return res.text("I\'m a teapot", status=418)
return res.text("I'm a teapot", status=418)
if __name__ == '__main__':
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -1,11 +1,11 @@
import os
from sanic import Sanic
from sanic.log import logger as log
from sanic import response
from sanic import Sanic, response
from sanic.exceptions import ServerError
from sanic.log import logger as log
app = Sanic(__name__)
app = Sanic("Example")
@app.route("/")
@@ -13,7 +13,7 @@ async def test_async(request):
return response.json({"test": True})
@app.route("/sync", methods=['GET', 'POST'])
@app.route("/sync", methods=["GET", "POST"])
def test_sync(request):
return response.json({"test": True})
@@ -31,6 +31,7 @@ def exception(request):
@app.route("/await")
async def test_await(request):
import asyncio
await asyncio.sleep(5)
return response.text("I'm feeling sleepy")
@@ -42,8 +43,10 @@ async def test_file(request):
@app.route("/file_stream")
async def test_file_stream(request):
return await response.file_stream(os.path.abspath("setup.py"),
chunk_size=1024)
return await response.file_stream(
os.path.abspath("setup.py"), chunk_size=1024
)
# ----------------------------------------------- #
# Exceptions
@@ -52,14 +55,17 @@ async def test_file_stream(request):
@app.exception(ServerError)
async def test(request, exception):
return response.json({"exception": "{}".format(exception), "status": exception.status_code},
status=exception.status_code)
return response.json(
{"exception": str(exception), "status": exception.status_code},
status=exception.status_code,
)
# ----------------------------------------------- #
# Read from request
# ----------------------------------------------- #
@app.route("/json")
def post_json(request):
return response.json({"received": True, "message": request.json})
@@ -67,38 +73,51 @@ def post_json(request):
@app.route("/form")
def post_form_json(request):
return response.json({"received": True, "form_data": request.form, "test": request.form.get('test')})
return response.json(
{
"received": True,
"form_data": request.form,
"test": request.form.get("test"),
}
)
@app.route("/query_string")
def query_string(request):
return response.json({"parsed": True, "args": request.args, "url": request.url,
"query_string": request.query_string})
return response.json(
{
"parsed": True,
"args": request.args,
"url": request.url,
"query_string": request.query_string,
}
)
# ----------------------------------------------- #
# Run Server
# ----------------------------------------------- #
@app.listener('before_server_start')
@app.before_server_start
def before_start(app, loop):
log.info("SERVER STARTING")
@app.listener('after_server_start')
@app.after_server_start
def after_start(app, loop):
log.info("OH OH OH OH OHHHHHHHH")
@app.listener('before_server_stop')
@app.before_server_stop
def before_stop(app, loop):
log.info("SERVER STOPPING")
@app.listener('after_server_stop')
@app.after_server_stop
def after_stop(app, loop):
log.info("TRIED EVERYTHING")
if __name__ == '__main__':
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)

View File

@@ -1,23 +1,13 @@
from sanic import Sanic
from sanic import response
import socket
import os
from sanic import Sanic, response
app = Sanic(__name__)
app = Sanic("Example")
@app.route("/test")
async def test(request):
return response.text("OK")
if __name__ == '__main__':
server_address = './uds_socket'
# Make sure the socket does not already exist
try:
os.unlink(server_address)
except OSError:
if os.path.exists(server_address):
raise
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(server_address)
app.run(sock=sock)
if __name__ == "__main__":
app.run(unix="./uds_socket")

View File

@@ -1,20 +1,21 @@
from sanic import Sanic
from sanic import response
app = Sanic(__name__)
from sanic import Sanic, response
@app.route('/')
app = Sanic("Example")
@app.route("/")
async def index(request):
# generate a URL for the endpoint `post_handler`
url = app.url_for('post_handler', post_id=5)
url = app.url_for("post_handler", post_id=5)
# the URL is `/posts/5`, redirect to it
return response.redirect(url)
@app.route('/posts/<post_id>')
@app.route("/posts/<post_id>")
async def post_handler(request, post_id):
return response.text('Post - {}'.format(post_id))
if __name__ == '__main__':
return response.text("Post - {}".format(post_id))
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)

View File

@@ -8,7 +8,9 @@ app = Sanic(name="blue-print-group-version-example")
bp1 = Blueprint(name="ultron", url_prefix="/ultron")
bp2 = Blueprint(name="vision", url_prefix="/vision", strict_slashes=None)
bpg = Blueprint.group([bp1, bp2], url_prefix="/sentient/robot", version=1, strict_slashes=True)
bpg = Blueprint.group(
bp1, bp2, url_prefix="/sentient/robot", version=1, strict_slashes=True
)
@bp1.get("/name")
@@ -31,5 +33,5 @@ async def bp2_revised_name(request):
app.blueprint(bpg)
if __name__ == '__main__':
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)

View File

@@ -8,7 +8,7 @@ from sanic.blueprints import Blueprint
# curl -H "Host: bp.example.com" localhost:8000/question
# curl -H "Host: bp.example.com" localhost:8000/answer
app = Sanic(__name__)
app = Sanic("Example")
bp = Blueprint("bp", host="bp.example.com")

View File

@@ -1,25 +1,27 @@
from sanic import Sanic
from sanic.response import redirect
app = Sanic(__name__)
app = Sanic("Example")
app.static('index.html', "websocket.html")
app.static("index.html", "websocket.html")
@app.route('/')
@app.route("/")
def index(request):
return redirect("index.html")
@app.websocket('/feed')
@app.websocket("/feed")
async def feed(request, ws):
while True:
data = 'hello!'
print('Sending: ' + data)
data = "hello!"
print("Sending: " + data)
await ws.send(data)
data = await ws.recv()
print('Received: ' + data)
print("Received: " + data)
if __name__ == '__main__':
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)

View File

@@ -1,6 +0,0 @@
FROM catthehacker/ubuntu:act-latest
SHELL [ "/bin/bash", "-c" ]
ENTRYPOINT []
RUN apt-get update
RUN apt-get install gcc -y
RUN apt-get install -y --no-install-recommends g++

View File

@@ -1,3 +1,29 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
[tool.black]
line-length = 79
[tool.isort]
atomic = true
default_section = "THIRDPARTY"
include_trailing_comma = true
known_first_party = "sanic"
known_third_party = "pytest"
line_length = 79
lines_after_imports = 2
lines_between_types = 1
multi_line_output = 3
profile = "black"
[[tool.mypy.overrides]]
module = [
"httptools.*",
"trustme.*",
"sanic_routing.*",
"aioquic.*",
"html5tagger.*",
"tracerite.*",
]
ignore_missing_imports = true

View File

@@ -6,4 +6,4 @@ python:
path: .
extra_requirements:
- docs
system_packages: true
system_packages: true

View File

@@ -1,19 +1,86 @@
from types import SimpleNamespace
from typing_extensions import TypeAlias
from sanic.__version__ import __version__
from sanic.app import Sanic
from sanic.blueprints import Blueprint
from sanic.config import Config
from sanic.constants import HTTPMethod
from sanic.exceptions import (
BadRequest,
ExpectationFailed,
FileNotFound,
Forbidden,
HeaderNotFound,
InternalServerError,
InvalidHeader,
MethodNotAllowed,
NotFound,
RangeNotSatisfiable,
SanicException,
ServerError,
ServiceUnavailable,
Unauthorized,
)
from sanic.request import Request
from sanic.response import HTTPResponse, html, json, text
from sanic.response import (
HTTPResponse,
empty,
file,
html,
json,
raw,
redirect,
text,
)
from sanic.server.websockets.impl import WebsocketImplProtocol as Websocket
DefaultSanic: TypeAlias = "Sanic[Config, SimpleNamespace]"
"""
A type alias for a Sanic app with a default config and namespace.
"""
DefaultRequest: TypeAlias = Request[DefaultSanic, SimpleNamespace]
"""
A type alias for a request with a default Sanic app and namespace.
"""
__all__ = (
"__version__",
# Common objects
"Sanic",
"Config",
"Blueprint",
"HTTPMethod",
"HTTPResponse",
"Request",
"Websocket",
# Common types
"DefaultSanic",
"DefaultRequest",
# Common exceptions
"BadRequest",
"ExpectationFailed",
"FileNotFound",
"Forbidden",
"HeaderNotFound",
"InternalServerError",
"InvalidHeader",
"MethodNotAllowed",
"NotFound",
"RangeNotSatisfiable",
"SanicException",
"ServerError",
"ServiceUnavailable",
"Unauthorized",
# Common response methods
"empty",
"file",
"html",
"json",
"raw",
"redirect",
"text",
)

View File

@@ -1,196 +1,15 @@
import os
import sys
from argparse import ArgumentParser, RawTextHelpFormatter
from importlib import import_module
from pathlib import Path
from typing import Any, Dict, Optional
from sanic_routing import __version__ as __routing_version__ # type: ignore
from sanic import __version__
from sanic.app import Sanic
from sanic.config import BASE_LOGO
from sanic.log import error_logger
from sanic.simple import create_simple_server
from sanic.cli.app import SanicCLI
from sanic.compat import OS_IS_WINDOWS, enable_windows_color_support
class SanicArgumentParser(ArgumentParser):
def add_bool_arguments(self, *args, **kwargs):
group = self.add_mutually_exclusive_group()
group.add_argument(*args, action="store_true", **kwargs)
kwargs["help"] = f"no {kwargs['help']}\n "
group.add_argument(
"--no-" + args[0][2:], *args[1:], action="store_false", **kwargs
)
if OS_IS_WINDOWS:
enable_windows_color_support()
def main():
parser = SanicArgumentParser(
prog="sanic",
description=BASE_LOGO,
formatter_class=lambda prog: RawTextHelpFormatter(
prog, max_help_position=33
),
)
parser.add_argument(
"-v",
"--version",
action="version",
version=f"Sanic {__version__}; Routing {__routing_version__}",
)
parser.add_argument(
"--factory",
action="store_true",
help=(
"Treat app as an application factory, "
"i.e. a () -> <Sanic app> callable"
),
)
parser.add_argument(
"-s",
"--simple",
dest="simple",
action="store_true",
help="Run Sanic as a Simple Server (module arg should be a path)\n ",
)
parser.add_argument(
"-H",
"--host",
dest="host",
type=str,
default="127.0.0.1",
help="Host address [default 127.0.0.1]",
)
parser.add_argument(
"-p",
"--port",
dest="port",
type=int,
default=8000,
help="Port to serve on [default 8000]",
)
parser.add_argument(
"-u",
"--unix",
dest="unix",
type=str,
default="",
help="location of unix socket\n ",
)
parser.add_argument(
"--cert", dest="cert", type=str, help="Location of certificate for SSL"
)
parser.add_argument(
"--key", dest="key", type=str, help="location of keyfile for SSL\n "
)
parser.add_bool_arguments(
"--access-logs", dest="access_log", help="display access logs"
)
parser.add_argument(
"-w",
"--workers",
dest="workers",
type=int,
default=1,
help="number of worker processes [default 1]\n ",
)
parser.add_argument("-d", "--debug", dest="debug", action="store_true")
parser.add_argument(
"-r",
"--reload",
"--auto-reload",
dest="auto_reload",
action="store_true",
help="Watch source directory for file changes and reload on changes",
)
parser.add_argument(
"-R",
"--reload-dir",
dest="path",
action="append",
help="Extra directories to watch and reload on changes\n ",
)
parser.add_argument(
"module",
help=(
"Path to your Sanic app. Example: path.to.server:app\n"
"If running a Simple Server, path to directory to serve. "
"Example: ./\n"
),
)
args = parser.parse_args()
try:
module_path = os.path.abspath(os.getcwd())
if module_path not in sys.path:
sys.path.append(module_path)
if args.simple:
path = Path(args.module)
app = create_simple_server(path)
else:
delimiter = ":" if ":" in args.module else "."
module_name, app_name = args.module.rsplit(delimiter, 1)
if app_name.endswith("()"):
args.factory = True
app_name = app_name[:-2]
module = import_module(module_name)
app = getattr(module, app_name, None)
if args.factory:
app = app()
app_type_name = type(app).__name__
if not isinstance(app, Sanic):
raise ValueError(
f"Module is not a Sanic app, it is a {app_type_name}. "
f"Perhaps you meant {args.module}.app?"
)
if args.cert is not None or args.key is not None:
ssl: Optional[Dict[str, Any]] = {
"cert": args.cert,
"key": args.key,
}
else:
ssl = None
kwargs = {
"host": args.host,
"port": args.port,
"unix": args.unix,
"workers": args.workers,
"debug": args.debug,
"access_log": args.access_log,
"ssl": ssl,
}
if args.auto_reload:
kwargs["auto_reload"] = True
if args.path:
if args.auto_reload or args.debug:
kwargs["reload_dir"] = args.path
else:
error_logger.warning(
"Ignoring '--reload-dir' since auto reloading was not "
"enabled. If you would like to watch directories for "
"changes, consider using --debug or --auto-reload."
)
app.run(**kwargs)
except ImportError as e:
if module_name.startswith(e.name):
error_logger.error(
f"No module named {e.name} found.\n"
" Example File: project/sanic_server.py -> app\n"
" Example Module: project.sanic_server.app"
)
else:
raise e
except ValueError:
error_logger.exception("Failed to run app")
def main(args=None):
cli = SanicCLI()
cli.attach()
cli.run(args)
if __name__ == "__main__":

View File

@@ -1 +1 @@
__version__ = "21.9.1"
__version__ = "23.6.0"

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1,32 @@
from enum import Enum, IntEnum, auto
class StrEnum(str, Enum): # no cov
def _generate_next_value_(name: str, *args) -> str: # type: ignore
return name.lower()
def __eq__(self, value: object) -> bool:
value = str(value).upper()
return super().__eq__(value)
def __hash__(self) -> int:
return hash(self.value)
def __str__(self) -> str:
return self.value
class Server(StrEnum):
SANIC = auto()
ASGI = auto()
class Mode(StrEnum):
PRODUCTION = auto()
DEBUG = auto()
class ServerStage(IntEnum):
STOPPED = auto()
PARTIAL = auto()
SERVING = auto()

34
sanic/application/ext.py Normal file
View File

@@ -0,0 +1,34 @@
from __future__ import annotations
from contextlib import suppress
from importlib import import_module
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from sanic import Sanic
def setup_ext(app: Sanic, *, fail: bool = False, **kwargs):
if not app.config.AUTO_EXTEND:
return
sanic_ext = None
with suppress(ModuleNotFoundError):
sanic_ext = import_module("sanic_ext")
if not sanic_ext: # no cov
if fail:
raise RuntimeError(
"Sanic Extensions is not installed. You can add it to your "
"environment using:\n$ pip install sanic[ext]\nor\n$ pip "
"install sanic-ext"
)
return
if not getattr(app, "_ext", None):
Ext = getattr(sanic_ext, "Extend")
app._ext = Ext(app, **kwargs)
return app.ext

61
sanic/application/logo.py Normal file
View File

@@ -0,0 +1,61 @@
import re
import sys
from os import environ
from sanic.helpers import is_atty
BASE_LOGO = """
Sanic
Build Fast. Run Fast.
"""
COFFEE_LOGO = """\033[48;2;255;13;104m \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ▄████████▄ \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ██ ██▀▀▄ \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ███████████ █ \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ███████████▄▄▀ \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ▀███████▀ \033[0m
\033[48;2;255;13;104m \033[0m
Dark roast. No sugar."""
COLOR_LOGO = """\033[48;2;255;13;104m \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ▄███ █████ ██ \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ██ \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ▀███████ ███▄ \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ██ \033[0m
\033[38;2;255;255;255;48;2;255;13;104m ████ ████████▀ \033[0m
\033[48;2;255;13;104m \033[0m
Build Fast. Run Fast."""
FULL_COLOR_LOGO = """
\033[38;2;255;13;104m ▄███ █████ ██ \033[0m ▄█▄ ██ █ █ ▄██████████
\033[38;2;255;13;104m ██ \033[0m █ █ █ ██ █ █ ██
\033[38;2;255;13;104m ▀███████ ███▄ \033[0m ▀ █ █ ██ ▄ █ ██
\033[38;2;255;13;104m ██\033[0m █████████ █ ██ █ █ ▄▄
\033[38;2;255;13;104m ████ ████████▀ \033[0m █ █ █ ██ █ ▀██ ███████
""" # noqa
SVG_LOGO_SIMPLE = """<svg id=logo-simple viewBox="0 0 964 279"><desc>Sanic</desc><path d="M107 222c9-2 10-20 1-22s-20-2-30-2-17 7-16 14 6 10 15 10h30zm115-1c16-2 30-11 35-23s6-24 2-33-6-14-15-20-24-11-38-10c-7 3-10 13-5 19s17-1 24 4 15 14 13 24-5 15-14 18-50 0-74 0h-17c-6 4-10 15-4 20s16 2 23 3zM251 83q9-1 9-7 0-15-10-16h-13c-10 6-10 20 0 22zM147 60c-4 0-10 3-11 11s5 13 10 12 42 0 67 0c5-3 7-10 6-15s-4-8-9-8zm-33 1c-8 0-16 0-24 3s-20 10-25 20-6 24-4 36 15 22 26 27 78 8 94 3c4-4 4-12 0-18s-69 8-93-10c-8-7-9-23 0-30s12-10 20-10 12 2 16-3 1-15-5-18z" fill="#ff0d68"/><path d="M676 74c0-14-18-9-20 0s0 30 0 39 20 9 20 2zm-297-10c-12 2-15 12-23 23l-41 58H340l22-30c8-12 23-13 30-4s20 24 24 38-10 10-17 10l-68 2q-17 1-48 30c-7 6-10 20 0 24s15-8 20-13 20 -20 58-21h50 c20 2 33 9 52 30 8 10 24-4 16-13L384 65q-3-2-5-1zm131 0c-10 1-12 12-11 20v96c1 10-3 23 5 32s20-5 17-15c0-23-3-46 2-67 5-12 22-14 32-5l103 87c7 5 19 1 18-9v-64c-3-10-20-9-21 2s-20 22-30 13l-97-80c-5-4-10-10-18-10zM701 76v128c2 10 15 12 20 4s0-102 0-124s-20-18-20-7z M850 63c-35 0-69-2-86 15s-20 60-13 66 13 8 16 0 1-10 1-27 12-26 20-32 66-5 85-5 31 4 31-10-18-7-54-7M764 159c-6-2-15-2-16 12s19 37 33 43 23 8 25-4-4-11-11-14q-9-3-22-18c-4-7-3-16-10-19zM828 196c-4 0-8 1-10 5s-4 12 0 15 8 2 12 2h60c5 0 10-2 12-6 3-7-1-16-8-16z" fill="#1f1f1f"/></svg>""" # noqa
ansi_pattern = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
def get_logo(full=False, coffee=False):
logo = (
(FULL_COLOR_LOGO if full else (COFFEE_LOGO if coffee else COLOR_LOGO))
if is_atty()
else BASE_LOGO
)
if (
sys.platform == "darwin"
and environ.get("TERM_PROGRAM") == "Apple_Terminal"
):
logo = ansi_pattern.sub("", logo)
return logo

153
sanic/application/motd.py Normal file
View File

@@ -0,0 +1,153 @@
from abc import ABC, abstractmethod
from shutil import get_terminal_size
from textwrap import indent, wrap
from typing import Dict, Optional
from sanic import __version__
from sanic.helpers import is_atty
from sanic.log import logger
class MOTD(ABC):
def __init__(
self,
logo: Optional[str],
serve_location: str,
data: Dict[str, str],
extra: Dict[str, str],
) -> None:
self.logo = logo
self.serve_location = serve_location
self.data = data
self.extra = extra
self.key_width = 0
self.value_width = 0
@abstractmethod
def display(self):
... # noqa
@classmethod
def output(
cls,
logo: Optional[str],
serve_location: str,
data: Dict[str, str],
extra: Dict[str, str],
) -> None:
motd_class = MOTDTTY if is_atty() else MOTDBasic
motd_class(logo, serve_location, data, extra).display()
class MOTDBasic(MOTD):
def display(self):
if self.logo:
logger.debug(self.logo)
lines = [f"Sanic v{__version__}"]
if self.serve_location:
lines.append(f"Goin' Fast @ {self.serve_location}")
lines += [
*(f"{key}: {value}" for key, value in self.data.items()),
*(f"{key}: {value}" for key, value in self.extra.items()),
]
for line in lines:
logger.info(line)
class MOTDTTY(MOTD):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.set_variables()
def set_variables(self): # no cov
fallback = (108, 24)
terminal_width = max(
get_terminal_size(fallback=fallback).columns, fallback[0]
)
self.max_value_width = terminal_width - fallback[0] + 36
self.key_width = 4
self.value_width = self.max_value_width
if self.data:
self.key_width = max(map(len, self.data.keys()))
self.value_width = min(
max(map(len, self.data.values())), self.max_value_width
)
if self.extra:
self.key_width = max(
self.key_width, max(map(len, self.extra.keys()))
)
self.value_width = min(
max((*map(len, self.extra.values()), self.value_width)),
self.max_value_width,
)
self.logo_lines = self.logo.split("\n") if self.logo else []
self.logo_line_length = 24
self.centering_length = (
self.key_width + self.value_width + 2 + self.logo_line_length
)
self.display_length = self.key_width + self.value_width + 2
def display(self, version=True, action="Goin' Fast", out=None):
if not out:
out = logger.info
header = "Sanic"
if version:
header += f" v{__version__}"
header = header.center(self.centering_length)
running = (
f"{action} @ {self.serve_location}" if self.serve_location else ""
).center(self.centering_length)
length = len(header) + 2 - self.logo_line_length
first_filler = "" * (self.logo_line_length - 1)
second_filler = "" * length
display_filler = "" * (self.display_length + 2)
lines = [
f"\n{first_filler}{second_filler}",
f"{header}",
f"{running}",
f"{first_filler}{second_filler}",
]
self._render_data(lines, self.data, 0)
if self.extra:
logo_part = self._get_logo_part(len(lines) - 4)
lines.append(f"{logo_part}{display_filler}")
self._render_data(lines, self.extra, len(lines) - 4)
self._render_fill(lines)
lines.append(f"{first_filler}{second_filler}\n")
out(indent("\n".join(lines), " "))
def _render_data(self, lines, data, start):
offset = 0
for idx, (key, value) in enumerate(data.items(), start=start):
key = key.rjust(self.key_width)
wrapped = wrap(value, self.max_value_width, break_on_hyphens=False)
for wrap_index, part in enumerate(wrapped):
part = part.ljust(self.value_width)
logo_part = self._get_logo_part(idx + offset + wrap_index)
display = (
f"{key}: {part}"
if wrap_index == 0
else (" " * len(key) + f" {part}")
)
lines.append(f"{logo_part}{display}")
if wrap_index:
offset += 1
def _render_fill(self, lines):
filler = " " * self.display_length
idx = len(lines) - 5
for i in range(1, len(self.logo_lines) - idx):
logo_part = self.logo_lines[idx + i]
lines.append(f"{logo_part}{filler}")
def _get_logo_part(self, idx):
try:
logo_part = self.logo_lines[idx]
except IndexError:
logo_part = " " * (self.logo_line_length - 3)
return logo_part

View File

@@ -0,0 +1,86 @@
import os
import sys
import time
from contextlib import contextmanager
from queue import Queue
from threading import Thread
if os.name == "nt": # noqa
import ctypes # noqa
class _CursorInfo(ctypes.Structure):
_fields_ = [("size", ctypes.c_int), ("visible", ctypes.c_byte)]
class Spinner: # noqa
def __init__(self, message: str) -> None:
self.message = message
self.queue: Queue[int] = Queue()
self.spinner = self.cursor()
self.thread = Thread(target=self.run)
def start(self):
self.queue.put(1)
self.thread.start()
self.hide()
def run(self):
while self.queue.get():
output = f"\r{self.message} [{next(self.spinner)}]"
sys.stdout.write(output)
sys.stdout.flush()
time.sleep(0.1)
self.queue.put(1)
def stop(self):
self.queue.put(0)
self.thread.join()
self.show()
@staticmethod
def cursor():
while True:
for cursor in "|/-\\":
yield cursor
@staticmethod
def hide():
if os.name == "nt":
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(
handle, ctypes.byref(ci)
)
ci.visible = False
ctypes.windll.kernel32.SetConsoleCursorInfo(
handle, ctypes.byref(ci)
)
elif os.name == "posix":
sys.stdout.write("\033[?25l")
sys.stdout.flush()
@staticmethod
def show():
if os.name == "nt":
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(
handle, ctypes.byref(ci)
)
ci.visible = True
ctypes.windll.kernel32.SetConsoleCursorInfo(
handle, ctypes.byref(ci)
)
elif os.name == "posix":
sys.stdout.write("\033[?25h")
sys.stdout.flush()
@contextmanager
def loading(message: str = "Loading"): # noqa
spinner = Spinner(message)
spinner.start()
yield
spinner.stop()

View File

@@ -0,0 +1,91 @@
from __future__ import annotations
import logging
from dataclasses import dataclass, field
from pathlib import Path
from socket import socket
from ssl import SSLContext
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union
from sanic.application.constants import Mode, Server, ServerStage
from sanic.log import VerbosityFilter, logger
from sanic.server.async_server import AsyncioServer
if TYPE_CHECKING:
from sanic import Sanic
@dataclass
class ApplicationServerInfo:
settings: Dict[str, Any]
stage: ServerStage = field(default=ServerStage.STOPPED)
server: Optional[AsyncioServer] = field(default=None)
@dataclass
class ApplicationState:
app: Sanic
asgi: bool = field(default=False)
coffee: bool = field(default=False)
fast: bool = field(default=False)
host: str = field(default="")
port: int = field(default=0)
ssl: Optional[SSLContext] = field(default=None)
sock: Optional[socket] = field(default=None)
unix: Optional[str] = field(default=None)
mode: Mode = field(default=Mode.PRODUCTION)
reload_dirs: Set[Path] = field(default_factory=set)
auto_reload: bool = field(default=False)
server: Server = field(default=Server.SANIC)
is_running: bool = field(default=False)
is_started: bool = field(default=False)
is_stopping: bool = field(default=False)
verbosity: int = field(default=0)
workers: int = field(default=0)
primary: bool = field(default=True)
server_info: List[ApplicationServerInfo] = field(default_factory=list)
# This property relates to the ApplicationState instance and should
# not be changed except in the __post_init__ method
_init: bool = field(default=False)
def __post_init__(self) -> None:
self._init = True
def __setattr__(self, name: str, value: Any) -> None:
if self._init and name == "_init":
raise RuntimeError(
"Cannot change the value of _init after instantiation"
)
super().__setattr__(name, value)
if self._init and hasattr(self, f"set_{name}"):
getattr(self, f"set_{name}")(value)
def set_mode(self, value: Union[str, Mode]):
if hasattr(self.app, "error_handler"):
self.app.error_handler.debug = self.app.debug
if getattr(self.app, "configure_logging", False) and self.app.debug:
logger.setLevel(logging.DEBUG)
def set_verbosity(self, value: int):
VerbosityFilter.verbosity = value
@property
def is_debug(self):
return self.mode is Mode.DEBUG
@property
def stage(self) -> ServerStage:
if not self.server_info:
return ServerStage.STOPPED
if all(info.stage is ServerStage.SERVING for info in self.server_info):
return ServerStage.SERVING
elif any(
info.stage is ServerStage.SERVING for info in self.server_info
):
return ServerStage.PARTIAL
return ServerStage.STOPPED

View File

@@ -1,41 +1,49 @@
from __future__ import annotations
import warnings
from typing import Optional
from urllib.parse import quote
import sanic.app # noqa
from typing import TYPE_CHECKING, Optional
from sanic.compat import Header
from sanic.exceptions import ServerError
from sanic.exceptions import BadRequest, ServerError
from sanic.helpers import Default
from sanic.http import Stage
from sanic.log import error_logger, logger
from sanic.models.asgi import ASGIReceive, ASGIScope, ASGISend, MockTransport
from sanic.request import Request
from sanic.response import BaseHTTPResponse
from sanic.server import ConnInfo
from sanic.server.websockets.connection import WebSocketConnection
class Lifespan:
def __init__(self, asgi_app: "ASGIApp") -> None:
self.asgi_app = asgi_app
if TYPE_CHECKING:
from sanic import Sanic
if (
"server.init.before"
in self.asgi_app.sanic_app.signal_router.name_index
):
warnings.warn(
class Lifespan:
def __init__(
self, sanic_app, scope: ASGIScope, receive: ASGIReceive, send: ASGISend
) -> None:
self.sanic_app = sanic_app
self.scope = scope
self.receive = receive
self.send = send
if "server.init.before" in self.sanic_app.signal_router.name_index:
logger.debug(
'You have set a listener for "before_server_start" '
"in ASGI mode. "
"It will be executed as early as possible, but not before "
"the ASGI server is started."
"the ASGI server is started.",
extra={"verbosity": 1},
)
if (
"server.shutdown.after"
in self.asgi_app.sanic_app.signal_router.name_index
):
warnings.warn(
if "server.shutdown.after" in self.sanic_app.signal_router.name_index:
logger.debug(
'You have set a listener for "after_server_stop" '
"in ASGI mode. "
"It will be executed as late as possible, but not after "
"the ASGI server is stopped."
"the ASGI server is stopped.",
extra={"verbosity": 1},
)
async def startup(self) -> None:
@@ -47,9 +55,16 @@ class Lifespan:
in sequence since the ASGI lifespan protocol only supports a single
startup event.
"""
await self.asgi_app.sanic_app._startup()
await self.asgi_app.sanic_app._server_event("init", "before")
await self.asgi_app.sanic_app._server_event("init", "after")
await self.sanic_app._startup()
await self.sanic_app._server_event("init", "before")
await self.sanic_app._server_event("init", "after")
if not isinstance(self.sanic_app.config.USE_UVLOOP, Default):
warnings.warn(
"You have set the USE_UVLOOP configuration option, but Sanic "
"cannot control the event loop when running in ASGI mode."
"This option will be ignored."
)
async def shutdown(self) -> None:
"""
@@ -60,88 +75,117 @@ class Lifespan:
in sequence since the ASGI lifespan protocol only supports a single
shutdown event.
"""
await self.asgi_app.sanic_app._server_event("shutdown", "before")
await self.asgi_app.sanic_app._server_event("shutdown", "after")
await self.sanic_app._server_event("shutdown", "before")
await self.sanic_app._server_event("shutdown", "after")
async def __call__(
self, scope: ASGIScope, receive: ASGIReceive, send: ASGISend
) -> None:
message = await receive()
if message["type"] == "lifespan.startup":
await self.startup()
await send({"type": "lifespan.startup.complete"})
message = await receive()
if message["type"] == "lifespan.shutdown":
await self.shutdown()
await send({"type": "lifespan.shutdown.complete"})
async def __call__(self) -> None:
while True:
message = await self.receive()
if message["type"] == "lifespan.startup":
try:
await self.startup()
except Exception as e:
error_logger.exception(e)
await self.send(
{"type": "lifespan.startup.failed", "message": str(e)}
)
else:
await self.send({"type": "lifespan.startup.complete"})
elif message["type"] == "lifespan.shutdown":
try:
await self.shutdown()
except Exception as e:
error_logger.exception(e)
await self.send(
{"type": "lifespan.shutdown.failed", "message": str(e)}
)
else:
await self.send({"type": "lifespan.shutdown.complete"})
return
class ASGIApp:
sanic_app: "sanic.app.Sanic"
sanic_app: Sanic
request: Request
transport: MockTransport
lifespan: Lifespan
ws: Optional[WebSocketConnection]
def __init__(self) -> None:
self.ws = None
stage: Stage
response: Optional[BaseHTTPResponse]
@classmethod
async def create(
cls, sanic_app, scope: ASGIScope, receive: ASGIReceive, send: ASGISend
) -> "ASGIApp":
cls,
sanic_app: Sanic,
scope: ASGIScope,
receive: ASGIReceive,
send: ASGISend,
) -> ASGIApp:
instance = cls()
instance.ws = None
instance.sanic_app = sanic_app
instance.transport = MockTransport(scope, receive, send)
instance.transport.loop = sanic_app.loop
instance.stage = Stage.IDLE
instance.response = None
instance.sanic_app.state.is_started = True
setattr(instance.transport, "add_task", sanic_app.loop.create_task)
headers = Header(
[
(key.decode("latin-1"), value.decode("latin-1"))
for key, value in scope.get("headers", [])
]
)
instance.lifespan = Lifespan(instance)
try:
headers = Header(
[
(
key.decode("ASCII"),
value.decode(errors="surrogateescape"),
)
for key, value in scope.get("headers", [])
]
)
except UnicodeDecodeError:
raise BadRequest(
"Header names can only contain US-ASCII characters"
)
if scope["type"] == "lifespan":
await instance.lifespan(scope, receive, send)
if scope["type"] == "http":
version = scope["http_version"]
method = scope["method"]
elif scope["type"] == "websocket":
version = "1.1"
method = "GET"
instance.ws = instance.transport.create_websocket_connection(
send, receive
)
else:
path = (
scope["path"][1:]
if scope["path"].startswith("/")
else scope["path"]
)
url = "/".join([scope.get("root_path", ""), quote(path)])
url_bytes = url.encode("latin-1")
url_bytes += b"?" + scope["query_string"]
raise ServerError("Received unknown ASGI scope")
if scope["type"] == "http":
version = scope["http_version"]
method = scope["method"]
elif scope["type"] == "websocket":
version = "1.1"
method = "GET"
url_bytes, query = scope["raw_path"], scope["query_string"]
if query:
# httpx ASGI client sends query string as part of raw_path
url_bytes = url_bytes.split(b"?", 1)[0]
# All servers send them separately
url_bytes = b"%b?%b" % (url_bytes, query)
instance.ws = instance.transport.create_websocket_connection(
send, receive
)
else:
raise ServerError("Received unknown ASGI scope")
request_class = sanic_app.request_class or Request
instance.request = request_class(
url_bytes,
headers,
version,
method,
instance.transport,
sanic_app,
)
request_class._current.set(instance.request)
instance.request.stream = instance # type: ignore
instance.request_body = True
instance.request.conn_info = ConnInfo(instance.transport)
request_class = sanic_app.request_class or Request
instance.request = request_class(
url_bytes,
headers,
version,
method,
instance.transport,
sanic_app,
)
instance.request.stream = instance
instance.request_body = True
instance.request.conn_info = ConnInfo(instance.transport)
await instance.sanic_app.dispatch(
"http.lifecycle.request",
inline=True,
context={"request": instance.request},
fail_not_found=False,
)
return instance
@@ -149,6 +193,8 @@ class ASGIApp:
"""
Read and stream the body in chunks from an incoming ASGI message.
"""
if self.stage is Stage.IDLE:
self.stage = Stage.REQUEST
message = await self.transport.receive()
body = message.get("body", b"")
if not message.get("more_body", False):
@@ -163,11 +209,17 @@ class ASGIApp:
if data:
yield data
def respond(self, response):
def respond(self, response: BaseHTTPResponse):
if self.stage is not Stage.HANDLER:
self.stage = Stage.FAILED
raise RuntimeError("Response already started")
if self.response is not None:
self.response.stream = None
response.stream, self.response = self, response
return response
async def send(self, data, end_stream):
self.stage = Stage.IDLE if end_stream else Stage.RESPONSE
if self.response:
response, self.response = self.response, None
await self.transport.send(
@@ -195,6 +247,10 @@ class ASGIApp:
Handle the incoming request.
"""
try:
self.stage = Stage.HANDLER
await self.sanic_app.handle_request(self.request)
except Exception as e:
await self.sanic_app.handle_exception(self.request, e)
try:
await self.sanic_app.handle_exception(self.request, e)
except Exception as exc:
await self.sanic_app.handle_exception(self.request, exc, False)

0
sanic/base/__init__.py Normal file
View File

6
sanic/base/meta.py Normal file
View File

@@ -0,0 +1,6 @@
class SanicMeta(type):
@classmethod
def __prepare__(metaclass, name, bases, **kwds):
cls = super().__prepare__(metaclass, name, bases, **kwds)
cls["__slots__"] = ()
return cls

View File

@@ -1,29 +1,34 @@
import re
from typing import Any, Tuple
from warnings import warn
from typing import Any, Optional
from sanic.base.meta import SanicMeta
from sanic.exceptions import SanicException
from sanic.mixins.exceptions import ExceptionMixin
from sanic.mixins.listeners import ListenerMixin
from sanic.mixins.middleware import MiddlewareMixin
from sanic.mixins.routes import RouteMixin
from sanic.mixins.signals import SignalMixin
from sanic.mixins.static import StaticMixin
VALID_NAME = re.compile(r"^[a-zA-Z][a-zA-Z0-9_\-]*$")
VALID_NAME = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_\-]*$")
class BaseSanic(
RouteMixin,
StaticMixin,
MiddlewareMixin,
ListenerMixin,
ExceptionMixin,
SignalMixin,
metaclass=SanicMeta,
):
__fake_slots__: Tuple[str, ...]
__slots__ = ("name",)
def __init__(self, name: str = None, *args, **kwargs) -> None:
def __init__(
self, name: Optional[str] = None, *args: Any, **kwargs: Any
) -> None:
class_name = self.__class__.__name__
if name is None:
@@ -33,11 +38,10 @@ class BaseSanic(
)
if not VALID_NAME.match(name):
warn(
f"{class_name} instance named '{name}' uses a format that is"
f"deprecated. Starting in version 21.12, {class_name} objects "
"must be named only using alphanumeric characters, _, or -.",
DeprecationWarning,
raise SanicException(
f"{class_name} instance named '{name}' uses an invalid "
"format. Names must begin with a character and may only "
"contain alphanumeric characters, _, or -."
)
self.name = name
@@ -52,15 +56,12 @@ class BaseSanic(
return f'{self.__class__.__name__}(name="{self.name}")'
def __setattr__(self, name: str, value: Any) -> None:
# This is a temporary compat layer so we can raise a warning until
# setting attributes on the app instance can be removed and deprecated
# with a proper implementation of __slots__
if name not in self.__fake_slots__:
warn(
try:
super().__setattr__(name, value)
except AttributeError as e:
raise AttributeError(
f"Setting variables on {self.__class__.__name__} instances is "
"deprecated and will be removed in version 21.12. You should "
f"change your {self.__class__.__name__} instance to use "
"not allowed. You should change your "
f"{self.__class__.__name__} instance to use "
f"instance.ctx.{name} instead.",
DeprecationWarning,
)
super().__setattr__(name, value)
) from e

View File

@@ -65,6 +65,7 @@ class BlueprintGroup(MutableSequence):
"_version",
"_strict_slashes",
"_version_prefix",
"_name_prefix",
)
def __init__(
@@ -73,6 +74,7 @@ class BlueprintGroup(MutableSequence):
version: Optional[Union[int, str, float]] = None,
strict_slashes: Optional[bool] = None,
version_prefix: str = "/v",
name_prefix: Optional[str] = "",
):
"""
Create a new Blueprint Group
@@ -87,6 +89,7 @@ class BlueprintGroup(MutableSequence):
self._version = version
self._version_prefix = version_prefix
self._strict_slashes = strict_slashes
self._name_prefix = name_prefix
@property
def url_prefix(self) -> Optional[Union[int, str, float]]:
@@ -134,6 +137,15 @@ class BlueprintGroup(MutableSequence):
"""
return self._version_prefix
@property
def name_prefix(self) -> Optional[str]:
"""
Name prefix for the blueprint group
:return: str
"""
return self._name_prefix
def __iter__(self):
"""
Tun the class Blueprint Group into an Iterable item
@@ -208,7 +220,7 @@ class BlueprintGroup(MutableSequence):
:param args: List of Python exceptions to be caught by the handler
:param kwargs: Additional optional arguments to be passed to the
exception handler
:return a decorated method to handle global exceptions for any
:return: a decorated method to handle global exceptions for any
blueprint registered under this group.
"""

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