From bc164ca2f26a3848a6b9d3884f9d92d08d45c9a8 Mon Sep 17 00:00:00 2001 From: Mix Date: Fri, 5 Feb 2021 20:29:53 +0800 Subject: [PATCH 01/10] :heavy_plus_sign: add a dependcies for quart --- poetry.lock | 207 +++++++++++++++++++++++++++++++++++++++++++------ pyproject.toml | 1 + 2 files changed, 186 insertions(+), 22 deletions(-) diff --git a/poetry.lock b/poetry.lock index b89548a3..6dfb1657 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,11 @@ +[[package]] +name = "aiofiles" +version = "0.6.0" +description = "File support for asyncio." +category = "main" +optional = true +python-versions = "*" + [[package]] name = "alabaster" version = "0.7.12" @@ -17,6 +25,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pytz = ">=2015.7" +[[package]] +name = "blinker" +version = "1.4" +description = "Fast, simple object-to-object and broadcast signaling" +category = "main" +optional = true +python-versions = "*" + [[package]] name = "certifi" version = "2020.12.5" @@ -83,6 +99,26 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "h2" +version = "4.0.0" +description = "HTTP/2 State-Machine based protocol implementation" +category = "main" +optional = true +python-versions = ">=3.6.1" + +[package.dependencies] +hpack = ">=4.0,<5" +hyperframe = ">=6.0,<7" + +[[package]] +name = "hpack" +version = "4.0.0" +description = "Pure-Python HPACK header compression" +category = "main" +optional = true +python-versions = ">=3.6.1" + [[package]] name = "html2text" version = "2020.1.16" @@ -135,6 +171,36 @@ sniffio = "*" brotli = ["brotlipy (>=0.7.0,<0.8.0)"] http2 = ["h2 (>=3.0.0,<4.0.0)"] +[[package]] +name = "hypercorn" +version = "0.11.2" +description = "A ASGI Server based on Hyper libraries and inspired by Gunicorn." +category = "main" +optional = true +python-versions = ">=3.7" + +[package.dependencies] +h11 = "*" +h2 = ">=3.1.0" +priority = "*" +toml = "*" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} +wsproto = ">=0.14.0" + +[package.extras] +h3 = ["aioquic (>=0.9.0,<1.0)"] +tests = ["hypothesis", "mock", "pytest", "pytest-asyncio", "pytest-cov", "pytest-trio", "trio"] +trio = ["trio (>=0.11.0)"] +uvloop = ["uvloop"] + +[[package]] +name = "hyperframe" +version = "6.0.0" +description = "HTTP/2 framing layer for Python" +category = "main" +optional = true +python-versions = ">=3.6.1" + [[package]] name = "idna" version = "2.10" @@ -151,11 +217,19 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +[[package]] +name = "itsdangerous" +version = "1.1.0" +description = "Various helpers to pass data to untrusted environments and back." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + [[package]] name = "jinja2" version = "2.11.3" description = "A very fast and expressive template engine." -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -184,7 +258,7 @@ dev = ["codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "tox (>=3 name = "markupsafe" version = "1.1.1" description = "Safely add untrusted strings to HTML/XML markup." -category = "dev" +category = "main" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" @@ -199,6 +273,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pyparsing = ">=2.0.2" +[[package]] +name = "priority" +version = "1.3.0" +description = "A pure-Python implementation of the HTTP/2 priority tree" +category = "main" +optional = true +python-versions = "*" + [[package]] name = "pydantic" version = "1.7.3" @@ -270,6 +352,28 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "quart" +version = "0.14.1" +description = "A Python ASGI web microframework with the same API as Flask" +category = "main" +optional = true +python-versions = ">=3.7.0" + +[package.dependencies] +aiofiles = "*" +blinker = "*" +click = "*" +hypercorn = ">=0.7.0" +itsdangerous = "*" +jinja2 = "*" +toml = "*" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} +werkzeug = ">=1.0.0" + +[package.extras] +dotenv = ["python-dotenv"] + [[package]] name = "requests" version = "2.25.1" @@ -453,6 +557,14 @@ python-versions = ">=3.6" [package.extras] full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "ujson"] +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "main" +optional = true +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + [[package]] name = "typing-extensions" version = "3.7.4.3" @@ -527,6 +639,18 @@ category = "main" optional = false python-versions = ">=3.6.1" +[[package]] +name = "werkzeug" +version = "1.0.1" +description = "The comprehensive WSGI web application library." +category = "main" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["pytest", "pytest-timeout", "coverage", "tox", "sphinx", "pallets-sphinx-themes", "sphinx-issues"] +watchdog = ["watchdog"] + [[package]] name = "win32-setctime" version = "1.0.3" @@ -538,6 +662,17 @@ python-versions = ">=3.5" [package.extras] dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"] +[[package]] +name = "wsproto" +version = "1.0.0" +description = "WebSockets state-machine based protocol implementation" +category = "main" +optional = true +python-versions = ">=3.6.1" + +[package.dependencies] +h11 = ">=0.9.0,<1" + [[package]] name = "yapf" version = "0.30.0" @@ -549,9 +684,13 @@ python-versions = "*" [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "9aa4fde8078788e6a12866ba4eb5d17ec6237355c663d6ea74040b6e165cdcf1" +content-hash = "273b07c9cef77a2763c43f26936718a44f91b3db90d4107204d0867f39a9813b" [metadata.files] +aiofiles = [ + {file = "aiofiles-0.6.0-py3-none-any.whl", hash = "sha256:bd3019af67f83b739f8e4053c6c0512a7f545b9a8d91aaeab55e6e0f9d123c27"}, + {file = "aiofiles-0.6.0.tar.gz", hash = "sha256:e0281b157d3d5d59d803e3f4557dcc9a3dff28a4dd4829a9ff478adae50ca092"}, +] alabaster = [ {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"}, {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"}, @@ -560,6 +699,9 @@ babel = [ {file = "Babel-2.9.0-py2.py3-none-any.whl", hash = "sha256:9d35c22fcc79893c3ecc85ac4a56cde1ecf3f19c540bba0922308a6c06ca6fa5"}, {file = "Babel-2.9.0.tar.gz", hash = "sha256:da031ab54472314f210b0adcff1588ee5d1d1d0ba4dbd07b94dba82bde791e05"}, ] +blinker = [ + {file = "blinker-1.4.tar.gz", hash = "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"}, +] certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, @@ -588,6 +730,14 @@ h11 = [ {file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"}, {file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"}, ] +h2 = [ + {file = "h2-4.0.0-py3-none-any.whl", hash = "sha256:ac9e293a1990b339d5d71b19c5fe630e3dd4d768c620d1730d355485323f1b25"}, + {file = "h2-4.0.0.tar.gz", hash = "sha256:bb7ac7099dd67a857ed52c815a6192b6b1f5ba6b516237fc24a085341340593d"}, +] +hpack = [ + {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, + {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, +] html2text = [ {file = "html2text-2020.1.16-py3-none-any.whl", hash = "sha256:c7c629882da0cf377d66f073329ccf34a12ed2adf0169b9285ae4e63ef54c82b"}, {file = "html2text-2020.1.16.tar.gz", hash = "sha256:e296318e16b059ddb97f7a8a1d6a5c1d7af4544049a01e261731d2d5cc277bbb"}, @@ -614,6 +764,14 @@ httpx = [ {file = "httpx-0.16.1-py3-none-any.whl", hash = "sha256:9cffb8ba31fac6536f2c8cde30df859013f59e4bcc5b8d43901cb3654a8e0a5b"}, {file = "httpx-0.16.1.tar.gz", hash = "sha256:126424c279c842738805974687e0518a94c7ae8d140cd65b9c4f77ac46ffa537"}, ] +hypercorn = [ + {file = "Hypercorn-0.11.2-py3-none-any.whl", hash = "sha256:8007c10f81566920f8ae12c0e26e146f94ca70506da964b5a727ad610aa1d821"}, + {file = "Hypercorn-0.11.2.tar.gz", hash = "sha256:5ba1e719c521080abd698ff5781a2331e34ef50fc1c89a50960538115a896a9a"}, +] +hyperframe = [ + {file = "hyperframe-6.0.0-py3-none-any.whl", hash = "sha256:a51026b1591cac726fc3d0b7994fbc7dc5efab861ef38503face2930fd7b2d34"}, + {file = "hyperframe-6.0.0.tar.gz", hash = "sha256:742d2a4bc3152a340a49d59f32e33ec420aa8e7054c1444ef5c7efff255842f1"}, +] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, @@ -622,6 +780,10 @@ imagesize = [ {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] +itsdangerous = [ + {file = "itsdangerous-1.1.0-py2.py3-none-any.whl", hash = "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"}, + {file = "itsdangerous-1.1.0.tar.gz", hash = "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19"}, +] jinja2 = [ {file = "Jinja2-2.11.3-py2.py3-none-any.whl", hash = "sha256:03e47ad063331dd6a3f04a43eddca8a966a26ba0c5b7207a9a9e4e08f1b29419"}, {file = "Jinja2-2.11.3.tar.gz", hash = "sha256:a6d58433de0ae800347cab1fa3043cebbabe8baa9d29e668f1c768cb87a333c6"}, @@ -649,45 +811,30 @@ markupsafe = [ {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"}, {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, ] packaging = [ {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] +priority = [ + {file = "priority-1.3.0-py2.py3-none-any.whl", hash = "sha256:be4fcb94b5e37cdeb40af5533afe6dd603bd665fe9c8b3052610fc1001d5d1eb"}, + {file = "priority-1.3.0.tar.gz", hash = "sha256:6bc1961a6d7fcacbfc337769f1a382c8e746566aaa365e78047abe9f66b2ffbe"}, +] pydantic = [ {file = "pydantic-1.7.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c59ea046aea25be14dc22d69c97bee629e6d48d2b2ecb724d7fe8806bf5f61cd"}, {file = "pydantic-1.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a4143c8d0c456a093387b96e0f5ee941a950992904d88bc816b4f0e72c9a0009"}, @@ -735,6 +882,10 @@ pytz = [ {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, ] +quart = [ + {file = "Quart-0.14.1-py3-none-any.whl", hash = "sha256:7b13786e07541cc9ce1466fdc6a6ccd5f36eb39118edd25a42d617593cd17707"}, + {file = "Quart-0.14.1.tar.gz", hash = "sha256:429c5b4ff27e1d2f9ca0aacc38f6aba0ff49b38b815448bf24b613d3de12ea02"}, +] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, @@ -784,6 +935,10 @@ starlette = [ {file = "starlette-0.13.6-py3-none-any.whl", hash = "sha256:bd2ffe5e37fb75d014728511f8e68ebf2c80b0fa3d04ca1479f4dc752ae31ac9"}, {file = "starlette-0.13.6.tar.gz", hash = "sha256:ebe8ee08d9be96a3c9f31b2cb2a24dbdf845247b745664bd8a3f9bd0c977fdbc"}, ] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] typing-extensions = [ {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, @@ -838,10 +993,18 @@ websockets = [ {file = "websockets-8.1-cp38-cp38-win_amd64.whl", hash = "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"}, {file = "websockets-8.1.tar.gz", hash = "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f"}, ] +werkzeug = [ + {file = "Werkzeug-1.0.1-py2.py3-none-any.whl", hash = "sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43"}, + {file = "Werkzeug-1.0.1.tar.gz", hash = "sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"}, +] win32-setctime = [ {file = "win32_setctime-1.0.3-py3-none-any.whl", hash = "sha256:dc925662de0a6eb987f0b01f599c01a8236cb8c62831c22d9cada09ad958243e"}, {file = "win32_setctime-1.0.3.tar.gz", hash = "sha256:4e88556c32fdf47f64165a2180ba4552f8bb32c1103a2fafd05723a0bd42bd4b"}, ] +wsproto = [ + {file = "wsproto-1.0.0-py3-none-any.whl", hash = "sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f"}, + {file = "wsproto-1.0.0.tar.gz", hash = "sha256:868776f8456997ad0d9720f7322b746bbe9193751b5b290b7f924659377c8c38"}, +] yapf = [ {file = "yapf-0.30.0-py2.py3-none-any.whl", hash = "sha256:3abf61ba67cf603069710d30acbc88cfe565d907e16ad81429ae90ce9651e0c9"}, {file = "yapf-0.30.0.tar.gz", hash = "sha256:3000abee4c28daebad55da6c85f3cd07b8062ce48e2e9943c8da1b9667d48427"}, diff --git a/pyproject.toml b/pyproject.toml index ee03af33..76d906e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,7 @@ fastapi = "^0.63.0" uvicorn = "^0.11.5" websockets = "^8.1" pydantic = {extras = ["dotenv", "typing_extensions"], version = "^1.7.3"} +Quart = {version = "^0.14.1", optional = true, extras = ["quart"]} [tool.poetry.dev-dependencies] yapf = "^0.30.0" From 6b43ad55752de99ca72e5d11a851a587bcfa222b Mon Sep 17 00:00:00 2001 From: Mix Date: Sat, 6 Feb 2021 09:40:57 +0800 Subject: [PATCH 02/10] :heavy_plus_sign: add quart as a extra requirement --- poetry.lock | 58 +++++++++++--------------------------------------- pyproject.toml | 5 ++++- 2 files changed, 17 insertions(+), 46 deletions(-) diff --git a/poetry.lock b/poetry.lock index 6dfb1657..f0ff0bd4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -41,14 +41,6 @@ category = "main" optional = false python-versions = "*" -[[package]] -name = "chardet" -version = "4.0.0" -description = "Universal encoding detector for Python 2 and 3" -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - [[package]] name = "click" version = "7.1.2" @@ -203,11 +195,11 @@ python-versions = ">=3.6.1" [[package]] name = "idna" -version = "2.10" +version = "3.1" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.4" [[package]] name = "imagesize" @@ -376,20 +368,14 @@ dotenv = ["python-dotenv"] [[package]] name = "requests" -version = "2.25.1" +version = "2.15.1" description = "Python HTTP for Humans." category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" - -[package.dependencies] -certifi = ">=2017.4.17" -chardet = ">=3.0.2,<5" -idna = ">=2.5,<3" -urllib3 = ">=1.21.1,<1.27" +python-versions = "*" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] +security = ["cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] @@ -592,19 +578,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "urllib3" -version = "1.26.3" -description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" - -[package.extras] -brotli = ["brotlipy (>=0.6.0)"] -secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] - [[package]] name = "uvicorn" version = "0.11.8" @@ -681,10 +654,13 @@ category = "dev" optional = false python-versions = "*" +[extras] +quart = ["Quart"] + [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "273b07c9cef77a2763c43f26936718a44f91b3db90d4107204d0867f39a9813b" +content-hash = "c23c2c3c795a7febb94bbba9ac04ff954a8f65a4389a367b1ce57793126d0f92" [metadata.files] aiofiles = [ @@ -706,10 +682,6 @@ certifi = [ {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, ] -chardet = [ - {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, - {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, -] click = [ {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, @@ -773,8 +745,8 @@ hyperframe = [ {file = "hyperframe-6.0.0.tar.gz", hash = "sha256:742d2a4bc3152a340a49d59f32e33ec420aa8e7054c1444ef5c7efff255842f1"}, ] idna = [ - {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, - {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, + {file = "idna-3.1-py3-none-any.whl", hash = "sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16"}, + {file = "idna-3.1.tar.gz", hash = "sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1"}, ] imagesize = [ {file = "imagesize-1.2.0-py2.py3-none-any.whl", hash = "sha256:6965f19a6a2039c7d48bca7dba2473069ff854c36ae6f19d2cde309d998228a1"}, @@ -887,8 +859,8 @@ quart = [ {file = "Quart-0.14.1.tar.gz", hash = "sha256:429c5b4ff27e1d2f9ca0aacc38f6aba0ff49b38b815448bf24b613d3de12ea02"}, ] requests = [ - {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, - {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, + {file = "requests-2.15.1-py2.py3-none-any.whl", hash = "sha256:ff753b2196cd18b1bbeddc9dcd5c864056599f7a7d9a4fb5677e723efa2b7fb9"}, + {file = "requests-2.15.1.tar.gz", hash = "sha256:e5659b9315a0610505e050bb7190bf6fa2ccee1ac295f2b760ef9d8a03ebbb2e"}, ] rfc3986 = [ {file = "rfc3986-1.4.0-py2.py3-none-any.whl", hash = "sha256:af9147e9aceda37c91a05f4deb128d4b4b49d6b199775fd2d2927768abdc8f50"}, @@ -950,10 +922,6 @@ unify = [ untokenize = [ {file = "untokenize-0.1.1.tar.gz", hash = "sha256:3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2"}, ] -urllib3 = [ - {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"}, - {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"}, -] uvicorn = [ {file = "uvicorn-0.11.8-py3-none-any.whl", hash = "sha256:4b70ddb4c1946e39db9f3082d53e323dfd50634b95fd83625d778729ef1730ef"}, {file = "uvicorn-0.11.8.tar.gz", hash = "sha256:46a83e371f37ea7ff29577d00015f02c942410288fb57def6440f2653fff1d26"}, diff --git a/pyproject.toml b/pyproject.toml index 76d906e8..593bac6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,13 +31,16 @@ fastapi = "^0.63.0" uvicorn = "^0.11.5" websockets = "^8.1" pydantic = {extras = ["dotenv", "typing_extensions"], version = "^1.7.3"} -Quart = {version = "^0.14.1", optional = true, extras = ["quart"]} +Quart = {version = "^0.14.1", optional = true} [tool.poetry.dev-dependencies] yapf = "^0.30.0" sphinx = "^3.4.1" sphinx-markdown-builder = { git = "https://github.com/nonebot/sphinx-markdown-builder.git" } +[tool.poetry.extras] +quart = ["quart"] + # [[tool.poetry.source]] # name = "aliyun" # url = "https://mirrors.aliyun.com/pypi/simple/" From 9e0862bc97d7b8eeb56dbc7a6fe1e1cb285c38a7 Mon Sep 17 00:00:00 2001 From: Mix Date: Sat, 6 Feb 2021 09:41:17 +0800 Subject: [PATCH 03/10] :sparkles: finish quart driver implement --- nonebot/drivers/quart.py | 199 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 nonebot/drivers/quart.py diff --git a/nonebot/drivers/quart.py b/nonebot/drivers/quart.py new file mode 100644 index 00000000..b8073739 --- /dev/null +++ b/nonebot/drivers/quart.py @@ -0,0 +1,199 @@ +import asyncio +from json.decoder import JSONDecodeError +from logging import getLogger, warn +from typing import Any, Callable, Coroutine, Dict, Optional, TypeVar + +from nonebot.config import Config as NoneBotConfig +from nonebot.config import Env +from nonebot.drivers import Driver as BaseDriver +from nonebot.drivers import WebSocket as BaseWebSocket +from nonebot.exception import RequestDenied +from nonebot.log import LoguruHandler, logger +from nonebot.typing import overrides + +try: + from hypercorn.asyncio import serve + from hypercorn.config import Config as HypercornConfig + from quart import Quart, Request, Response + from quart import Websocket as QuartWebSocket + from quart import exceptions + from quart import request as _request + from quart import websocket as _websocket +except ImportError: + raise ValueError('Quart not fount, please install quart first') + +_AsyncCallable = TypeVar("_AsyncCallable", bound=Callable[..., Coroutine]) + + +class Driver(BaseDriver): + + @overrides(BaseDriver) + def __init__(self, env: Env, config: NoneBotConfig): + super().__init__(env, config) + + self._server_app = Quart(self.__class__.__qualname__) + self._server_app.logger.handlers.clear() + self._server_app.logger.addHandler(LoguruHandler()) + self._server_app.route('//http', + methods=['POST'])(self._handle_http) + self._server_app.websocket('//ws')(self._handle_ws_reverse) + + @property + @overrides(BaseDriver) + def type(self) -> str: + return 'quart' + + @property + @overrides(BaseDriver) + def server_app(self) -> Quart: + return self._server_app + + @property + @overrides(BaseDriver) + def asgi(self): + return self._server_app + + @property + @overrides(BaseDriver) + def loggers(self): + return self._server_app.logger + + @overrides(BaseDriver) + def on_startup(self, func: _AsyncCallable) -> _AsyncCallable: + return self.server_app.before_serving(func) # type: ignore + + @overrides(BaseDriver) + def on_shutdown(self, func: _AsyncCallable) -> _AsyncCallable: + return self.server_app.after_serving(func) # type: ignore + + @overrides(BaseDriver) + def run(self, + host: Optional[str] = None, + port: Optional[int] = None, + **kwargs): + super().run(host, port, **kwargs) + config = HypercornConfig() + for k, v in kwargs.items(): + if not hasattr(config, k): + warn(f'Config {k!r} is not available for quart driver.') + continue + setattr(config, k, v) + config.bind.append( + f'{host or self.config.host}:{port or self.config.port}') + + serve_task = asyncio.run_coroutine_threadsafe( + coro=serve(self.server_app, config), + loop=asyncio.get_running_loop(), + ) + try: + serve_task.result() + finally: + serve_task.cancel() + + @overrides(BaseDriver) + async def _handle_http(self, adapter: str): + request: Request = _request + try: + data: Dict[str, Any] = await request.get_json() + except Exception as e: + raise exceptions.BadRequest() + if adapter not in self._adapters: + logger.warning(f'Unknown adapter {adapter}. ' + 'Please register the adapter before use.') + raise exceptions.NotFound() + BotClass = self._adapters[adapter] + headers = dict(request.headers) + try: + self_id = await BotClass.check_permission(self, 'http', headers, + data) + except RequestDenied as e: + raise exceptions.HTTPException(status_code=e.status_code, + description=e.reason, + name='Request Denied') + if self_id in self._clients: + logger.warning("There's already a reverse websocket connection," + "so the event may be handled twice.") + bot = BotClass('http', self_id) + asyncio.create_task(bot.handle_message(data)) + return Response('', 204) + + @overrides(BaseDriver) + async def _handle_ws_reverse(self, adapter: str): + websocket: QuartWebSocket = _websocket + + if adapter not in self._adapters: + logger.warning( + f'Unknown adapter {adapter}. Please register the adapter before use.' + ) + raise exceptions.NotFound() + + BotClass = self._adapters[adapter] + headers = dict(websocket.headers) + try: + self_id = await BotClass.check_permission(self, 'ws', headers, None) + except RequestDenied as e: + raise exceptions.HTTPException(status_code=e.status_code, + description=e.reason, + name='Request Denied') + if self_id in self._clients: + logger.warning("There's already a reverse websocket connection," + "so the event may be handled twice.") + ws = WebSocket(websocket) + bot = BotClass('websocket', self_id, websocket=ws) + await ws.accept() + logger.opt(colors=True).info( + f"WebSocket Connection from {adapter.upper()} " + f"Bot {self_id} Accepted!") + self._bot_connect(bot) + + try: + while not ws.closed: + data = await ws.receive() + if data is None: + continue + asyncio.create_task(bot.handle_message(data)) + finally: + self._bot_disconnect(bot) + + +class WebSocket(BaseWebSocket): + + @overrides(BaseWebSocket) + def __init__(self, websocket: QuartWebSocket): + super().__init__(websocket) + self._closed = False + + @property + @overrides(BaseWebSocket) + def websocket(self) -> QuartWebSocket: + return self._websocket + + @property + @overrides(BaseWebSocket) + def closed(self): + return self._closed + + @overrides(BaseWebSocket) + async def accept(self): + await self.websocket.accept() + self._closed = False + + @overrides(BaseWebSocket) + async def close(self): + self._closed = True + + @overrides(BaseWebSocket) + async def receive(self) -> Optional[Dict[str, Any]]: + data: Optional[Dict[str, Any]] = None + try: + data = await self.websocket.receive_json() + except JSONDecodeError: + logger.warning('Received an invalid json message.') + except asyncio.CancelledError: + self._closed = True + logger.warning('WebSocket disconnected by peer.') + return data + + @overrides(BaseWebSocket) + async def send(self, data: dict): + await self.websocket.send_json(data) From 496f64f103e9462a5ddeb029316302236f3f92ce Mon Sep 17 00:00:00 2001 From: Mix Date: Sat, 6 Feb 2021 10:34:52 +0800 Subject: [PATCH 04/10] :bug: fix bugs in quart driver --- nonebot/drivers/quart.py | 96 ++++++++++++++++++++++++++-------------- tests/.env.dev | 2 +- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/nonebot/drivers/quart.py b/nonebot/drivers/quart.py index b8073739..2ee9eb1a 100644 --- a/nonebot/drivers/quart.py +++ b/nonebot/drivers/quart.py @@ -1,19 +1,21 @@ import asyncio from json.decoder import JSONDecodeError -from logging import getLogger, warn -from typing import Any, Callable, Coroutine, Dict, Optional, TypeVar +from typing import (TYPE_CHECKING, Any, Callable, Coroutine, Dict, Optional, + Type, TypeVar) + +import uvicorn from nonebot.config import Config as NoneBotConfig from nonebot.config import Env from nonebot.drivers import Driver as BaseDriver from nonebot.drivers import WebSocket as BaseWebSocket from nonebot.exception import RequestDenied -from nonebot.log import LoguruHandler, logger +from nonebot.log import logger from nonebot.typing import overrides +if TYPE_CHECKING: + from nonebot.adapters import Bot try: - from hypercorn.asyncio import serve - from hypercorn.config import Config as HypercornConfig from quart import Quart, Request, Response from quart import Websocket as QuartWebSocket from quart import exceptions @@ -32,11 +34,21 @@ class Driver(BaseDriver): super().__init__(env, config) self._server_app = Quart(self.__class__.__qualname__) - self._server_app.logger.handlers.clear() - self._server_app.logger.addHandler(LoguruHandler()) - self._server_app.route('//http', - methods=['POST'])(self._handle_http) - self._server_app.websocket('//ws')(self._handle_ws_reverse) + + @overrides(BaseDriver) + def register_adapter(self, name: str, adapter: Type["Bot"], **kwargs): + if name in self._adapters: + return + + super().register_adapter(name, adapter, **kwargs) + + @self.server_app.route(f'/{name}/http', endpoint=name + '_http') + async def _http_handler(): + await self._handle_http(name) + + @self.server_app.websocket(f'/{name}/ws', endpoint=name + '_ws') + async def _ws_handler(): + await self._handle_ws_reverse(name) @property @overrides(BaseDriver) @@ -55,7 +67,7 @@ class Driver(BaseDriver): @property @overrides(BaseDriver) - def loggers(self): + def logger(self): return self._server_app.logger @overrides(BaseDriver) @@ -66,43 +78,60 @@ class Driver(BaseDriver): def on_shutdown(self, func: _AsyncCallable) -> _AsyncCallable: return self.server_app.after_serving(func) # type: ignore + @overrides(BaseDriver) @overrides(BaseDriver) def run(self, host: Optional[str] = None, port: Optional[int] = None, + *, + app: Optional[str] = None, **kwargs): - super().run(host, port, **kwargs) - config = HypercornConfig() - for k, v in kwargs.items(): - if not hasattr(config, k): - warn(f'Config {k!r} is not available for quart driver.') - continue - setattr(config, k, v) - config.bind.append( - f'{host or self.config.host}:{port or self.config.port}') - - serve_task = asyncio.run_coroutine_threadsafe( - coro=serve(self.server_app, config), - loop=asyncio.get_running_loop(), - ) - try: - serve_task.result() - finally: - serve_task.cancel() + """使用 ``uvicorn`` 启动 Quart""" + super().run(host, port, app, **kwargs) + LOGGING_CONFIG = { + "version": 1, + "disable_existing_loggers": False, + "handlers": { + "default": { + "class": "nonebot.log.LoguruHandler", + }, + }, + "loggers": { + "uvicorn.error": { + "handlers": ["default"], + "level": "INFO" + }, + "uvicorn.access": { + "handlers": ["default"], + "level": "INFO", + }, + }, + } + uvicorn.run(app or self.server_app, + host=host or str(self.config.host), + port=port or self.config.port, + reload=bool(app) and self.config.debug, + debug=self.config.debug, + log_config=LOGGING_CONFIG, + **kwargs) @overrides(BaseDriver) async def _handle_http(self, adapter: str): request: Request = _request + try: data: Dict[str, Any] = await request.get_json() except Exception as e: raise exceptions.BadRequest() + if adapter not in self._adapters: logger.warning(f'Unknown adapter {adapter}. ' 'Please register the adapter before use.') raise exceptions.NotFound() + BotClass = self._adapters[adapter] - headers = dict(request.headers) + headers = {k: v for k, v in request.headers.items(lower=True)} + try: self_id = await BotClass.check_permission(self, 'http', headers, data) @@ -120,7 +149,6 @@ class Driver(BaseDriver): @overrides(BaseDriver) async def _handle_ws_reverse(self, adapter: str): websocket: QuartWebSocket = _websocket - if adapter not in self._adapters: logger.warning( f'Unknown adapter {adapter}. Please register the adapter before use.' @@ -128,10 +156,12 @@ class Driver(BaseDriver): raise exceptions.NotFound() BotClass = self._adapters[adapter] - headers = dict(websocket.headers) + headers = {k: v for k, v in websocket.headers.items(lower=True)} try: - self_id = await BotClass.check_permission(self, 'ws', headers, None) + self_id = await BotClass.check_permission(self, 'websocket', + headers, None) except RequestDenied as e: + print(e.reason) raise exceptions.HTTPException(status_code=e.status_code, description=e.reason, name='Request Denied') diff --git a/tests/.env.dev b/tests/.env.dev index 33e6f835..ef16df99 100644 --- a/tests/.env.dev +++ b/tests/.env.dev @@ -1,4 +1,4 @@ -DRIVER=nonebot.drivers.fastapi +DRIVER=nonebot.drivers.quart HOST=0.0.0.0 PORT=2333 DEBUG=true From 86965ee06d49e4cd347de63a1d560ddd22862031 Mon Sep 17 00:00:00 2001 From: Mix Date: Sat, 6 Feb 2021 10:46:17 +0800 Subject: [PATCH 05/10] :bulb: add comments in quart driver --- docs_build/drivers/quart.rst | 12 ++++++++++++ nonebot/drivers/quart.py | 26 +++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 docs_build/drivers/quart.rst diff --git a/docs_build/drivers/quart.rst b/docs_build/drivers/quart.rst new file mode 100644 index 00000000..189dd478 --- /dev/null +++ b/docs_build/drivers/quart.rst @@ -0,0 +1,12 @@ +--- +contentSidebar: true +sidebarDepth: 0 +--- + +NoneBot.drivers.quart 模块 +========================== + +.. automodule:: nonebot.drivers.quart + :members: + :private-members: + :show-inheritance: \ No newline at end of file diff --git a/nonebot/drivers/quart.py b/nonebot/drivers/quart.py index 2ee9eb1a..7fa46f68 100644 --- a/nonebot/drivers/quart.py +++ b/nonebot/drivers/quart.py @@ -1,3 +1,13 @@ +""" +Quart 驱动适配 +================ + +后端使用方法请参考: `Quart 文档`_ + +.. _Quart 文档: + https://pgjones.gitlab.io/quart/index.html +""" + import asyncio from json.decoder import JSONDecodeError from typing import (TYPE_CHECKING, Any, Callable, Coroutine, Dict, Optional, @@ -28,6 +38,14 @@ _AsyncCallable = TypeVar("_AsyncCallable", bound=Callable[..., Coroutine]) class Driver(BaseDriver): + """ + Quart 驱动框架 + + :上报地址: + + * ``/{adapter name}/http/``: HTTP POST 上报 + * ``/{adapter name}/ws``: WebSocket 上报 + """ @overrides(BaseDriver) def __init__(self, env: Env, config: NoneBotConfig): @@ -37,6 +55,7 @@ class Driver(BaseDriver): @overrides(BaseDriver) def register_adapter(self, name: str, adapter: Type["Bot"], **kwargs): + """向 Quart 路由添加对应 adapter 响应的 handler""" if name in self._adapters: return @@ -53,32 +72,37 @@ class Driver(BaseDriver): @property @overrides(BaseDriver) def type(self) -> str: + """驱动名称: ``quart``""" return 'quart' @property @overrides(BaseDriver) def server_app(self) -> Quart: + """``Quart`` 对象""" return self._server_app @property @overrides(BaseDriver) def asgi(self): + """``Quart`` 对象""" return self._server_app @property @overrides(BaseDriver) def logger(self): + """fastapi 使用的 logger""" return self._server_app.logger @overrides(BaseDriver) def on_startup(self, func: _AsyncCallable) -> _AsyncCallable: + """参考文档: `Startup and Shutdown `_""" return self.server_app.before_serving(func) # type: ignore @overrides(BaseDriver) def on_shutdown(self, func: _AsyncCallable) -> _AsyncCallable: + """参考文档: `Startup and Shutdown `_""" return self.server_app.after_serving(func) # type: ignore - @overrides(BaseDriver) @overrides(BaseDriver) def run(self, host: Optional[str] = None, From 7d9a8eaf196b46e824afbce966e67decfaa92a19 Mon Sep 17 00:00:00 2001 From: Mix Date: Sat, 6 Feb 2021 10:54:50 +0800 Subject: [PATCH 06/10] :green_heart: add extra install in document build --- .github/workflows/build_docs.yml | 4 ++-- poetry.lock | 3 ++- pyproject.toml | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 8fdc2d9a..bd20695a 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -2,7 +2,7 @@ name: Build API Doc on: pull_request: - types: [ opened, synchronize, reopened ] + types: [opened, synchronize, reopened] jobs: build: @@ -30,7 +30,7 @@ jobs: - name: Set up dependencies run: | - poetry install + poetry install -E all - name: Build Doc run: poetry run sphinx-build -M markdown ./docs_build ./build diff --git a/poetry.lock b/poetry.lock index f0ff0bd4..6d41f5cb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -655,12 +655,13 @@ optional = false python-versions = "*" [extras] +all = ["Quart"] quart = ["Quart"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "c23c2c3c795a7febb94bbba9ac04ff954a8f65a4389a367b1ce57793126d0f92" +content-hash = "11273401518ba0c93c5e381c6f0c1be02d60106bcda715c7ee7a06a78a8871d5" [metadata.files] aiofiles = [ diff --git a/pyproject.toml b/pyproject.toml index 593bac6c..b0cd8e42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ sphinx-markdown-builder = { git = "https://github.com/nonebot/sphinx-markdown-bu [tool.poetry.extras] quart = ["quart"] +all = ["quart"] # [[tool.poetry.source]] # name = "aliyun" From c537841bc18a94d841471d13bd2a1a7adb27ad69 Mon Sep 17 00:00:00 2001 From: Mix Date: Sat, 6 Feb 2021 10:58:58 +0800 Subject: [PATCH 07/10] :memo: add index in document for quart driver --- docs/.vuepress/config.js | 4 ++++ docs_build/README.rst | 1 + 2 files changed, 5 insertions(+) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 971c8b0e..97d3ac9b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -198,6 +198,10 @@ module.exports = context => ({ title: "nonebot.drivers.fastapi 模块", path: "drivers/fastapi" }, + { + title: "nonebot.drivers.quart 模块", + path: "drivers/quart" + }, { title: "nonebot.adapters 模块", path: "adapters/" diff --git a/docs_build/README.rst b/docs_build/README.rst index 4a273041..0e029d9b 100644 --- a/docs_build/README.rst +++ b/docs_build/README.rst @@ -15,6 +15,7 @@ NoneBot Api Reference - `nonebot.exception `_ - `nonebot.drivers `_ - `nonebot.drivers.fastapi `_ + - `nonebot.drivers.quart `_ - `nonebot.adapters `_ - `nonebot.adapters.cqhttp `_ - `nonebot.adapters.ding `_ From 4f7a033b9c5b88de51fc7e18538562a79dfd8be8 Mon Sep 17 00:00:00 2001 From: Mix Date: Sat, 6 Feb 2021 11:37:57 +0800 Subject: [PATCH 08/10] :zap: use dynamic routing in quart driver --- nonebot/drivers/quart.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/nonebot/drivers/quart.py b/nonebot/drivers/quart.py index 7fa46f68..c5fc0595 100644 --- a/nonebot/drivers/quart.py +++ b/nonebot/drivers/quart.py @@ -32,7 +32,8 @@ try: from quart import request as _request from quart import websocket as _websocket except ImportError: - raise ValueError('Quart not fount, please install quart first') + raise ValueError( + 'Please install Quart by using `pip install nonebot2[quart]`') _AsyncCallable = TypeVar("_AsyncCallable", bound=Callable[..., Coroutine]) @@ -43,7 +44,7 @@ class Driver(BaseDriver): :上报地址: - * ``/{adapter name}/http/``: HTTP POST 上报 + * ``/{adapter name}/http``: HTTP POST 上报 * ``/{adapter name}/ws``: WebSocket 上报 """ @@ -52,22 +53,11 @@ class Driver(BaseDriver): super().__init__(env, config) self._server_app = Quart(self.__class__.__qualname__) - - @overrides(BaseDriver) - def register_adapter(self, name: str, adapter: Type["Bot"], **kwargs): - """向 Quart 路由添加对应 adapter 响应的 handler""" - if name in self._adapters: - return - - super().register_adapter(name, adapter, **kwargs) - - @self.server_app.route(f'/{name}/http', endpoint=name + '_http') - async def _http_handler(): - await self._handle_http(name) - - @self.server_app.websocket(f'/{name}/ws', endpoint=name + '_ws') - async def _ws_handler(): - await self._handle_ws_reverse(name) + self._server_app.add_url_rule('//http', + methods=['POST'], + view_func=self._handle_http) + self._server_app.add_websocket('//ws', + view_func=self._handle_ws_reverse) @property @overrides(BaseDriver) From 6cb9fda53ae6566ced744a26d70a286a45480cf2 Mon Sep 17 00:00:00 2001 From: Mix Date: Sat, 6 Feb 2021 11:42:40 +0800 Subject: [PATCH 09/10] :art: remove unused imports --- nonebot/drivers/quart.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/nonebot/drivers/quart.py b/nonebot/drivers/quart.py index c5fc0595..9d189d64 100644 --- a/nonebot/drivers/quart.py +++ b/nonebot/drivers/quart.py @@ -10,8 +10,7 @@ Quart 驱动适配 import asyncio from json.decoder import JSONDecodeError -from typing import (TYPE_CHECKING, Any, Callable, Coroutine, Dict, Optional, - Type, TypeVar) +from typing import Any, Callable, Coroutine, Dict, Optional, Type, TypeVar import uvicorn @@ -23,8 +22,6 @@ from nonebot.exception import RequestDenied from nonebot.log import logger from nonebot.typing import overrides -if TYPE_CHECKING: - from nonebot.adapters import Bot try: from quart import Quart, Request, Response from quart import Websocket as QuartWebSocket From 4fd4fbfb0887a825578d3481304067af24d85dea Mon Sep 17 00:00:00 2001 From: nonebot Date: Sat, 6 Feb 2021 03:44:30 +0000 Subject: [PATCH 10/10] :memo: update api docs --- docs/api/README.md | 3 ++ docs/api/drivers/quart.md | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 docs/api/drivers/quart.md diff --git a/docs/api/README.md b/docs/api/README.md index 36e9803e..e12dd0ff 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -43,6 +43,9 @@ * [nonebot.drivers.fastapi](drivers/fastapi.html) + * [nonebot.drivers.quart](drivers/quart.html) + + * [nonebot.adapters](adapters/) diff --git a/docs/api/drivers/quart.md b/docs/api/drivers/quart.md new file mode 100644 index 00000000..068769e0 --- /dev/null +++ b/docs/api/drivers/quart.md @@ -0,0 +1,62 @@ +--- +contentSidebar: true +sidebarDepth: 0 +--- + +# NoneBot.drivers.quart 模块 + +## Quart 驱动适配 + +后端使用方法请参考: [Quart 文档](https://pgjones.gitlab.io/quart/index.html) + + +## _class_ `Driver` + +基类:[`nonebot.drivers.Driver`](README.md#nonebot.drivers.Driver) + +Quart 驱动框架 + + +* **上报地址** + + + * `/{adapter name}/http`: HTTP POST 上报 + + + * `/{adapter name}/ws`: WebSocket 上报 + + + +### _property_ `type` + +驱动名称: `quart` + + +### _property_ `server_app` + +`Quart` 对象 + + +### _property_ `asgi` + +`Quart` 对象 + + +### _property_ `logger` + +fastapi 使用的 logger + + +### `on_startup(func)` + +参考文档: [Startup and Shutdown](https://pgjones.gitlab.io/quart/how_to_guides/startup_shutdown.html) + + +### `on_shutdown(func)` + +参考文档: [Startup and Shutdown](https://pgjones.gitlab.io/quart/how_to_guides/startup_shutdown.html) + + +### `run(host=None, port=None, *, app=None, **kwargs)` + +使用 `uvicorn` 启动 Quart