From 4d242875d24840db8dfdc1ca39bf0d0dc5137f56 Mon Sep 17 00:00:00 2001 From: yanyongyu Date: Sat, 4 Jul 2020 22:51:10 +0800 Subject: [PATCH] add fastapi driver, config --- .gitignore | 2 + docs/.vuepress/config.js | 3 - docs_build/api.rst | 62 ++++--- nonebot/__init__.py | 46 ++++- nonebot/config.py | 29 +++ nonebot/drivers/__init__.py | 27 +++ nonebot/drivers/fastapi.py | 78 ++++++++ nonebot/log.py | 2 + nonebot/matcher.py | 24 +++ nonebot/message.py | 26 +++ nonebot/rule.py | 8 +- poetry.lock | 358 +++++++++++++++++++++++++++++++++++- pyproject.toml | 4 + tests/.env | 1 + tests/.env.dev | 4 + tests/bot.py | 15 +- 16 files changed, 644 insertions(+), 45 deletions(-) create mode 100644 nonebot/config.py create mode 100644 nonebot/drivers/__init__.py create mode 100644 nonebot/drivers/fastapi.py create mode 100644 nonebot/message.py create mode 100644 tests/.env create mode 100644 tests/.env.dev diff --git a/.gitignore b/.gitignore index ce338cb9..5e140b2f 100644 --- a/.gitignore +++ b/.gitignore @@ -186,3 +186,5 @@ typings/ .idea .vscode dev +docs_build/_build +!tests/.env diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index eff26981..2602a86b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -31,8 +31,5 @@ module.exports = { sidebar: {} }, - /** - * Apply plugins,ref:https://v1.vuepress.vuejs.org/zh/plugin/ - */ plugins: ["@vuepress/plugin-back-to-top", "@vuepress/plugin-medium-zoom"] }; diff --git a/docs_build/api.rst b/docs_build/api.rst index ec11194d..7ce4ca6c 100644 --- a/docs_build/api.rst +++ b/docs_build/api.rst @@ -1,4 +1,8 @@ -nonebot package +--- +sidebar: auto +--- + +nonebot api reference =============== .. automodule:: nonebot @@ -6,31 +10,7 @@ nonebot package :undoc-members: :show-inheritance: -nonebot.event module --------------------- - -.. automodule:: nonebot.event - :members: - :undoc-members: - :show-inheritance: - -nonebot.exception module ------------------------- - -.. automodule:: nonebot.exception - :members: - :undoc-members: - :show-inheritance: - -nonebot.log module ------------------- - -.. automodule:: nonebot.log - :members: - :undoc-members: - :show-inheritance: - -nonebot.matcher module +`nonebot.matcher` 模块 ---------------------- .. automodule:: nonebot.matcher @@ -38,7 +18,7 @@ nonebot.matcher module :undoc-members: :show-inheritance: -nonebot.plugin module +`nonebot.plugin` 模块 --------------------- .. automodule:: nonebot.plugin @@ -46,7 +26,7 @@ nonebot.plugin module :undoc-members: :show-inheritance: -nonebot.rule module +`nonebot.rule` 模块 ------------------- .. automodule:: nonebot.rule @@ -54,7 +34,31 @@ nonebot.rule module :undoc-members: :show-inheritance: -nonebot.typing module +`nonebot.event` 模块 +-------------------- + +.. automodule:: nonebot.event + :members: + :undoc-members: + :show-inheritance: + +`nonebot.exception` 模块 +------------------------ + +.. automodule:: nonebot.exception + :members: + :undoc-members: + :show-inheritance: + +`nonebot.log` 模块 +------------------ + +.. automodule:: nonebot.log + :members: + :undoc-members: + :show-inheritance: + +`nonebot.typing` 模块 --------------------- .. automodule:: nonebot.typing diff --git a/nonebot/__init__.py b/nonebot/__init__.py index 5dc9f792..35f6be00 100644 --- a/nonebot/__init__.py +++ b/nonebot/__init__.py @@ -2,8 +2,50 @@ # -*- coding: utf-8 -*- import logging -from .log import logger +import importlib +from typing import Optional +from ipaddress import IPv4Address + +from .log import logger +from .config import Env, Config +from .drivers import BaseDriver + +_driver: Optional[BaseDriver] = None + + +def get_driver() -> BaseDriver: + if _driver is None: + raise ValueError("NoneBot has not been initialized.") + return _driver + + +def get_app(): + driver = get_driver() + return driver.server_app + + +def get_asgi(): + driver = get_driver() + return driver.asgi + + +def init(*, _env_file=None, **kwargs): + global _driver + env = Env() + config = Config(**kwargs, _env_file=_env_file or f".env.{env.environment}") + + logger.setLevel(logging.DEBUG if config.debug else logging.INFO) + logger.debug(f"Loaded config: {config.dict()}") + + Driver = getattr(importlib.import_module(config.driver), "Driver") + _driver = Driver(config) + + +def run(host: Optional[IPv4Address] = None, + port: Optional[int] = None, + *args, + **kwargs): + get_driver().run(host, port, *args, **kwargs) -logger.setLevel(level=logging.DEBUG) from .plugin import load_plugins, get_loaded_plugins diff --git a/nonebot/config.py b/nonebot/config.py new file mode 100644 index 00000000..b06c0625 --- /dev/null +++ b/nonebot/config.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Set, Union +from ipaddress import IPv4Address + +from pydantic import BaseSettings + + +class Env(BaseSettings): + environment: str = "prod" + + class Config: + env_file = ".env" + + +class Config(BaseSettings): + driver: str = "nonebot.drivers.fastapi" + host: IPv4Address = IPv4Address("127.0.0.1") + port: int = 8080 + debug: bool = False + + superusers: Set[int] = set() + nickname: Union[str, Set[str]] = "" + + custom_config: dict = {} + + class Config: + env_file = ".env.prod" diff --git a/nonebot/drivers/__init__.py b/nonebot/drivers/__init__.py new file mode 100644 index 00000000..b40b7f52 --- /dev/null +++ b/nonebot/drivers/__init__.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from typing import Optional +from ipaddress import IPv4Address + + +class BaseDriver(object): + + @property + def server_app(self): + raise NotImplementedError + + @property + def asgi(self): + raise NotImplementedError + + @property + def logger(self): + raise NotImplementedError + + def run(self, + host: Optional[IPv4Address] = None, + port: Optional[int] = None, + *args, + **kwargs): + raise NotImplementedError diff --git a/nonebot/drivers/fastapi.py b/nonebot/drivers/fastapi.py new file mode 100644 index 00000000..0795cf15 --- /dev/null +++ b/nonebot/drivers/fastapi.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import sys +import logging +from typing import Optional +from ipaddress import IPv4Address + +import uvicorn +from fastapi import FastAPI + +from . import BaseDriver + + +class Driver(BaseDriver): + + def __init__(self, config): + self._server_app = FastAPI( + debug=config.debug, + openapi_url=None, + docs_url=None, + redoc_url=None, + ) + + self.config = config + + @property + def server_app(self): + return self._server_app + + @property + def asgi(self): + return self._server_app + + @property + def logger(self): + return logging.getLogger("fastapi") + + def run(self, + host: Optional[IPv4Address] = None, + port: Optional[int] = None, + *, + app: Optional[str] = None, + **kwargs): + LOGGING_CONFIG = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "default": { + "()": "logging.Formatter", + "fmt": "[%(asctime)s %(name)s] %(levelname)s: %(message)s", + }, + }, + "handlers": { + "default": { + "formatter": "default", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + }, + "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=app and self.config.debug, + debug=self.config.debug, + log_config=LOGGING_CONFIG, + **kwargs) diff --git a/nonebot/log.py b/nonebot/log.py index 180f1a75..272eaeda 100644 --- a/nonebot/log.py +++ b/nonebot/log.py @@ -5,6 +5,8 @@ import sys import logging logger = logging.getLogger("nonebot") +"""nonebot logger""" + default_handler = logging.StreamHandler(sys.stdout) default_handler.setFormatter( logging.Formatter("[%(asctime)s %(name)s] %(levelname)s: %(message)s")) diff --git a/nonebot/matcher.py b/nonebot/matcher.py index 344fee6a..4355a42f 100644 --- a/nonebot/matcher.py +++ b/nonebot/matcher.py @@ -14,6 +14,8 @@ matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list) class Matcher: + """`Matcher`类 + """ rule: Rule = Rule() handlers: List[Handler] = [] @@ -26,6 +28,8 @@ class Matcher: # _args_parser: Optional[Callable[[Event, dict], None]] = None def __init__(self): + """实例化 Matcher 以便运行 + """ self.handlers = self.handlers.copy() self.state = self._default_state.copy() # self.parser = self._args_parser or self._default_parser @@ -38,6 +42,11 @@ class Matcher: priority: int = 1, *, default_state: dict = {}) -> Type["Matcher"]: + """创建新的 Matcher + + Returns: + Type["Matcher"]: 新的 Matcher 类 + """ NewMatcher = type( "Matcher", (Matcher,), { @@ -52,6 +61,18 @@ class Matcher: return NewMatcher + @classmethod + def check_rule(cls, event: Event) -> bool: + """检查 Matcher 的 Rule 是否成立 + + Args: + event (Event): 消息事件 + + Returns: + bool: 条件成立与否 + """ + return cls.rule(event) + # @classmethod # def args_parser(cls, func: Callable[[Event, dict], None]): # cls._default_parser = func @@ -59,6 +80,7 @@ class Matcher: @classmethod def handle(cls): + """直接处理消息事件""" def _decorator(func: Handler) -> Handler: cls.handlers.append(func) @@ -68,6 +90,7 @@ class Matcher: @classmethod def receive(cls): + """接收一条新消息并处理""" def _decorator(func: Handler) -> Handler: @@ -117,6 +140,7 @@ class Matcher: # def reject(cls, prompt: Optional[str] = None): # raise RejectedException + # 运行handlers async def run(self, bot, event): if not self.rule(event): return diff --git a/nonebot/message.py b/nonebot/message.py new file mode 100644 index 00000000..4fb3b8ed --- /dev/null +++ b/nonebot/message.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from .log import logger +from .event import Event +from .matcher import matchers + + +async def handle_message(bot, event: Event): + # TODO: PreProcess + + for priority in sorted(matchers.keys()): + for index in range(len(matchers[priority])): + Matcher = matchers[priority][index] + if not Matcher.check_rule(event): + continue + + matcher = Matcher() + if Matcher.temp: + del matchers[priority][index] + + try: + await matcher.run(bot, event) + except Exception as e: + logger.exception(e) + return diff --git a/nonebot/rule.py b/nonebot/rule.py index 50ac9b5a..82c68a8c 100644 --- a/nonebot/rule.py +++ b/nonebot/rule.py @@ -12,16 +12,16 @@ class Rule: def __init__(self, checker: Optional[Callable[[Event], bool]] = None): self.checker = checker or (lambda event: True) - def __call__(self, event): + def __call__(self, event: Event) -> bool: return self.checker(event) - def __and__(self, other): + def __and__(self, other: "Rule") -> "Rule": return Rule(lambda event: self.checker(event) and other.checker(event)) - def __or__(self, other): + def __or__(self, other: "Rule") -> "Rule": return Rule(lambda event: self.checker(event) or other.checker(event)) - def __neg__(self): + def __neg__(self) -> "Rule": return Rule(lambda event: not self.checker(event)) diff --git a/poetry.lock b/poetry.lock index 15c6f700..f5277e89 100644 --- a/poetry.lock +++ b/poetry.lock @@ -85,6 +85,19 @@ reference = "aliyun" type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" +[[package]] +category = "main" +description = "Composable command line interface toolkit" +name = "click" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "7.1.2" + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + [[package]] category = "dev" description = "Cross-platform colored terminal text." @@ -112,6 +125,72 @@ reference = "aliyun" type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" +[[package]] +category = "main" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +name = "fastapi" +optional = false +python-versions = ">=3.6" +version = "0.58.1" + +[package.dependencies] +pydantic = ">=0.32.2,<2.0.0" +starlette = "0.13.4" + +[package.extras] +all = ["requests", "aiofiles", "jinja2", "python-multipart", "itsdangerous", "pyyaml", "graphene", "ujson", "orjson", "email-validator", "uvicorn", "async-exit-stack", "async-generator"] +dev = ["pyjwt", "passlib", "autoflake", "flake8", "uvicorn", "graphene"] +doc = ["mkdocs", "mkdocs-material", "markdown-include", "typer", "typer-cli", "pyyaml"] +test = ["pytest (5.4.3)", "pytest-cov (2.10.0)", "mypy", "black", "isort", "requests", "email-validator", "sqlalchemy", "peewee", "databases", "orjson", "async-exit-stack", "async-generator", "python-multipart", "aiofiles", "flask"] + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + +[[package]] +category = "main" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +name = "h11" +optional = false +python-versions = "*" +version = "0.9.0" + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + +[[package]] +category = "dev" +description = "Turn HTML into equivalent Markdown-structured text." +name = "html2text" +optional = false +python-versions = ">=3.5" +version = "2020.1.16" + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + +[[package]] +category = "main" +description = "A collection of framework independent HTTP protocol utils." +marker = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"" +name = "httptools" +optional = false +python-versions = "*" +version = "0.1.1" + +[package.extras] +test = ["Cython (0.29.14)"] + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + [[package]] category = "dev" description = "Internationalized Domain Names in Applications (IDNA)" @@ -187,6 +266,45 @@ reference = "aliyun" type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" +[[package]] +category = "main" +description = "Data validation and settings management using python 3.6 type hinting" +name = "pydantic" +optional = false +python-versions = ">=3.6" +version = "1.5.1" + +[package.dependencies] +[package.dependencies.python-dotenv] +optional = true +version = ">=0.10.4" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] +typing_extensions = ["typing-extensions (>=3.7.2)"] + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + +[[package]] +category = "dev" +description = "The kitchen sink of Python utility libraries for doing \"stuff\" in a functional way. Based on the Lo-Dash Javascript library." +name = "pydash" +optional = false +python-versions = "*" +version = "4.8.0" + +[package.extras] +dev = ["coverage", "flake8", "mock", "pylint", "pytest", "pytest-cov", "sphinx", "sphinx-rtd-theme", "tox", "twine", "wheel"] + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + [[package]] category = "dev" description = "Pygments is a syntax highlighting package written in Python." @@ -213,6 +331,22 @@ reference = "aliyun" type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" +[[package]] +category = "main" +description = "Add .env support to your django/flask apps in development and deployments" +name = "python-dotenv" +optional = false +python-versions = "*" +version = "0.13.0" + +[package.extras] +cli = ["click (>=5.0)"] + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + [[package]] category = "main" description = "World timezone definitions, modern and historical" @@ -312,6 +446,26 @@ reference = "aliyun" type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" +[[package]] +category = "dev" +description = "sphinx builder that outputs markdown files" +name = "sphinx-markdown-builder" +optional = false +python-versions = "*" +version = "0.5.4" + +[package.dependencies] +html2text = "*" +pydash = "*" +sphinx = "*" +unify = "*" +yapf = "*" + +[package.source] +reference = "cf45995f23cd30ea9b3ec09e85daf4aa0c34b374" +type = "git" +url = "https://github.com/nonebot/sphinx-markdown-builder.git" + [[package]] category = "dev" description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" @@ -413,6 +567,22 @@ reference = "aliyun" type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" +[[package]] +category = "main" +description = "The little ASGI library that shines." +name = "starlette" +optional = false +python-versions = ">=3.6" +version = "0.13.4" + +[package.extras] +full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "ujson"] + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + [[package]] category = "main" description = "tzinfo object for the local timezone" @@ -429,6 +599,35 @@ reference = "aliyun" type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" +[[package]] +category = "dev" +description = "Modifies strings to all use the same (single/double) quote where possible." +name = "unify" +optional = false +python-versions = "*" +version = "0.5" + +[package.dependencies] +untokenize = "*" + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + +[[package]] +category = "dev" +description = "Transforms tokens into original source code (while preserving whitespace)." +name = "untokenize" +optional = false +python-versions = "*" +version = "0.1.1" + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + [[package]] category = "dev" description = "HTTP library with thread-safe connection pooling, file post, and more." @@ -447,6 +646,56 @@ reference = "aliyun" type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" +[[package]] +category = "main" +description = "The lightning-fast ASGI server." +name = "uvicorn" +optional = false +python-versions = "*" +version = "0.11.5" + +[package.dependencies] +click = ">=7.0.0,<8.0.0" +h11 = ">=0.8,<0.10" +httptools = ">=0.1.0,<0.2.0" +uvloop = ">=0.14.0" +websockets = ">=8.0.0,<9.0.0" + +[package.extras] +watchgodreload = ["watchgod (>=0.6,<0.7)"] + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + +[[package]] +category = "main" +description = "Fast implementation of asyncio event loop on top of libuv" +marker = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"" +name = "uvloop" +optional = false +python-versions = "*" +version = "0.14.0" + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + +[[package]] +category = "main" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +name = "websockets" +optional = false +python-versions = ">=3.6.1" +version = "8.1" + +[package.source] +reference = "aliyun" +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" + [[package]] category = "dev" description = "A formatter for Python code." @@ -464,7 +713,7 @@ url = "https://mirrors.aliyun.com/pypi/simple" scheduler = ["apscheduler"] [metadata] -content-hash = "84f5268c5011bb03aea6f51e16b738a73f18a483b6948ea978b98943002c10bd" +content-hash = "5dc37a3a06ef422bb885c2f6b09179964e083f2005bf8873349431ebc4508152" python-versions = "^3.7" [metadata.files] @@ -488,6 +737,10 @@ chardet = [ {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "md5:0004b00caff7bb543a1d0d0bd0185a03"}, {file = "chardet-3.0.4.tar.gz", hash = "md5:7dd1ba7f9c77e32351b0a0cfacf4055c"}, ] +click = [ + {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, + {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, +] colorama = [ {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, @@ -496,6 +749,32 @@ docutils = [ {file = "docutils-0.16-py2.py3-none-any.whl", hash = "sha256:0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af"}, {file = "docutils-0.16.tar.gz", hash = "sha256:c2de3a60e9e7d07be26b7f2b00ca0309c207e06c100f9cc2a94931fc75a478fc"}, ] +fastapi = [ + {file = "fastapi-0.58.1-py3-none-any.whl", hash = "sha256:d7499761d5ca901cdf5b6b73018d14729593f8ab1ea22d241f82fa574fc406ad"}, + {file = "fastapi-0.58.1.tar.gz", hash = "sha256:92e59b77eef7d6eaa80b16d275adda06b5f33b12d777e3fc5521b2f7f4718e13"}, +] +h11 = [ + {file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"}, + {file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"}, +] +html2text = [ + {file = "html2text-2020.1.16-py3-none-any.whl", hash = "sha256:c7c629882da0cf377d66f073329ccf34a12ed2adf0169b9285ae4e63ef54c82b"}, + {file = "html2text-2020.1.16.tar.gz", hash = "sha256:e296318e16b059ddb97f7a8a1d6a5c1d7af4544049a01e261731d2d5cc277bbb"}, +] +httptools = [ + {file = "httptools-0.1.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:a2719e1d7a84bb131c4f1e0cb79705034b48de6ae486eb5297a139d6a3296dce"}, + {file = "httptools-0.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:fa3cd71e31436911a44620473e873a256851e1f53dee56669dae403ba41756a4"}, + {file = "httptools-0.1.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:86c6acd66765a934e8730bf0e9dfaac6fdcf2a4334212bd4a0a1c78f16475ca6"}, + {file = "httptools-0.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bc3114b9edbca5a1eb7ae7db698c669eb53eb8afbbebdde116c174925260849c"}, + {file = "httptools-0.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:ac0aa11e99454b6a66989aa2d44bca41d4e0f968e395a0a8f164b401fefe359a"}, + {file = "httptools-0.1.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:96da81e1992be8ac2fd5597bf0283d832287e20cb3cfde8996d2b00356d4e17f"}, + {file = "httptools-0.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:56b6393c6ac7abe632f2294da53f30d279130a92e8ae39d8d14ee2e1b05ad1f2"}, + {file = "httptools-0.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:96eb359252aeed57ea5c7b3d79839aaa0382c9d3149f7d24dd7172b1bcecb009"}, + {file = "httptools-0.1.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:fea04e126014169384dee76a153d4573d90d0cbd1d12185da089f73c78390437"}, + {file = "httptools-0.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3592e854424ec94bd17dc3e0c96a64e459ec4147e6d53c0a42d0ebcef9cb9c5d"}, + {file = "httptools-0.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a4b1b2012b28e68306575ad14ad5e9120b34fccd02a81eb08838d7e3bbb48be"}, + {file = "httptools-0.1.1.tar.gz", hash = "sha256:41b573cf33f64a8f8f3400d0a7faf48e1888582b6f6e02b82b9bd4f0bf7497ce"}, +] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, @@ -547,6 +826,29 @@ packaging = [ {file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"}, {file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"}, ] +pydantic = [ + {file = "pydantic-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2a6904e9f18dea58f76f16b95cba6a2f20b72d787abd84ecd67ebc526e61dce6"}, + {file = "pydantic-1.5.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da8099fca5ee339d5572cfa8af12cf0856ae993406f0b1eb9bb38c8a660e7416"}, + {file = "pydantic-1.5.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:68dece67bff2b3a5cc188258e46b49f676a722304f1c6148ae08e9291e284d98"}, + {file = "pydantic-1.5.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:ab863853cb502480b118187d670f753be65ec144e1654924bec33d63bc8b3ce2"}, + {file = "pydantic-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:2007eb062ed0e57875ce8ead12760a6e44bf5836e6a1a7ea81d71eeecf3ede0f"}, + {file = "pydantic-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:20a15a303ce1e4d831b4e79c17a4a29cb6740b12524f5bba3ea363bff65732bc"}, + {file = "pydantic-1.5.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:473101121b1bd454c8effc9fe66d54812fdc128184d9015c5aaa0d4e58a6d338"}, + {file = "pydantic-1.5.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:9be755919258d5d168aeffbe913ed6e8bd562e018df7724b68cabdee3371e331"}, + {file = "pydantic-1.5.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:b96ce81c4b5ca62ab81181212edfd057beaa41411cd9700fbcb48a6ba6564b4e"}, + {file = "pydantic-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:93b9f265329d9827f39f0fca68f5d72cc8321881cdc519a1304fa73b9f8a75bd"}, + {file = "pydantic-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e2c753d355126ddd1eefeb167fa61c7037ecd30b98e7ebecdc0d1da463b4ea09"}, + {file = "pydantic-1.5.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:8433dbb87246c0f562af75d00fa80155b74e4f6924b0db6a2078a3cd2f11c6c4"}, + {file = "pydantic-1.5.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:0a1cdf24e567d42dc762d3fed399bd211a13db2e8462af9dfa93b34c41648efb"}, + {file = "pydantic-1.5.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:8be325fc9da897029ee48d1b5e40df817d97fe969f3ac3fd2434ba7e198c55d5"}, + {file = "pydantic-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:3714a4056f5bdbecf3a41e0706ec9b228c9513eee2ad884dc2c568c4dfa540e9"}, + {file = "pydantic-1.5.1-py36.py37.py38-none-any.whl", hash = "sha256:70f27d2f0268f490fe3de0a9b6fca7b7492b8fd6623f9fecd25b221ebee385e3"}, + {file = "pydantic-1.5.1.tar.gz", hash = "sha256:f0018613c7a0d19df3240c2a913849786f21b6539b9f23d85ce4067489dfacfa"}, +] +pydash = [ + {file = "pydash-4.8.0-py2.py3-none-any.whl", hash = "sha256:611ad40e3b11fb57396cca4a55ea04641200a1dd632c3c7e2c14849bee386625"}, + {file = "pydash-4.8.0.tar.gz", hash = "sha256:546afa043ed1defa3122383bebe8b7072f43554ccc5f0c4360638f99e5ed7327"}, +] pygments = [ {file = "Pygments-2.6.1-py3-none-any.whl", hash = "sha256:ff7a40b4860b727ab48fad6360eb351cc1b33cbf9b15a0f689ca5353e9463324"}, {file = "Pygments-2.6.1.tar.gz", hash = "sha256:647344a061c249a3b74e230c739f434d7ea4d8b1d5f3721bc0f3558049b38f44"}, @@ -555,6 +857,10 @@ pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] +python-dotenv = [ + {file = "python-dotenv-0.13.0.tar.gz", hash = "sha256:3b9909bc96b0edc6b01586e1eed05e71174ef4e04c71da5786370cebea53ad74"}, + {file = "python_dotenv-0.13.0-py2.py3-none-any.whl", hash = "sha256:25c0ff1a3e12f4bde8d592cc254ab075cfe734fc5dd989036716fd17ee7e5ec7"}, +] pytz = [ {file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"}, {file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"}, @@ -575,6 +881,7 @@ sphinx = [ {file = "Sphinx-3.1.1-py3-none-any.whl", hash = "sha256:97c9e3bcce2f61d9f5edf131299ee9d1219630598d9f9a8791459a4d9e815be5"}, {file = "Sphinx-3.1.1.tar.gz", hash = "sha256:74fbead182a611ce1444f50218a1c5fc70b6cc547f64948f5182fb30a2a20258"}, ] +sphinx-markdown-builder = [] sphinxcontrib-applehelp = [ {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"}, {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"}, @@ -599,14 +906,63 @@ sphinxcontrib-serializinghtml = [ {file = "sphinxcontrib-serializinghtml-1.1.4.tar.gz", hash = "sha256:eaa0eccc86e982a9b939b2b82d12cc5d013385ba5eadcc7e4fed23f4405f77bc"}, {file = "sphinxcontrib_serializinghtml-1.1.4-py2.py3-none-any.whl", hash = "sha256:f242a81d423f59617a8e5cf16f5d4d74e28ee9a66f9e5b637a18082991db5a9a"}, ] +starlette = [ + {file = "starlette-0.13.4-py3-none-any.whl", hash = "sha256:0fb4b38d22945b46acb880fedee7ee143fd6c0542992501be8c45c0ed737dd1a"}, + {file = "starlette-0.13.4.tar.gz", hash = "sha256:04fe51d86fd9a594d9b71356ed322ccde5c9b448fc716ac74155e5821a922f8d"}, +] tzlocal = [ {file = "tzlocal-2.1-py2.py3-none-any.whl", hash = "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4"}, {file = "tzlocal-2.1.tar.gz", hash = "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44"}, ] +unify = [ + {file = "unify-0.5.tar.gz", hash = "sha256:8ddce812b2457212b7598fe574c9e6eb3ad69710f445391338270c7f8a71723c"}, +] +untokenize = [ + {file = "untokenize-0.1.1.tar.gz", hash = "md5:50d325dff09208c624cc603fad33bb0d"}, +] urllib3 = [ {file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"}, {file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"}, ] +uvicorn = [ + {file = "uvicorn-0.11.5-py3-none-any.whl", hash = "sha256:50577d599775dac2301bac8bd5b540d19a9560144143c5bdab13cba92783b6e7"}, + {file = "uvicorn-0.11.5.tar.gz", hash = "sha256:596eaa8645b6dbc24d6610e335f8ddf5f925b4c4b86fdc7146abb0bf0da65d17"}, +] +uvloop = [ + {file = "uvloop-0.14.0-cp35-cp35m-macosx_10_11_x86_64.whl", hash = "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd"}, + {file = "uvloop-0.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726"}, + {file = "uvloop-0.14.0-cp36-cp36m-macosx_10_11_x86_64.whl", hash = "sha256:b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7"}, + {file = "uvloop-0.14.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f07909cd9fc08c52d294b1570bba92186181ca01fe3dc9ffba68955273dd7362"}, + {file = "uvloop-0.14.0-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:afd5513c0ae414ec71d24f6f123614a80f3d27ca655a4fcf6cabe50994cc1891"}, + {file = "uvloop-0.14.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e7514d7a48c063226b7d06617cbb12a14278d4323a065a8d46a7962686ce2e95"}, + {file = "uvloop-0.14.0-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:bcac356d62edd330080aed082e78d4b580ff260a677508718f88016333e2c9c5"}, + {file = "uvloop-0.14.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09"}, + {file = "uvloop-0.14.0.tar.gz", hash = "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e"}, +] +websockets = [ + {file = "websockets-8.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c"}, + {file = "websockets-8.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170"}, + {file = "websockets-8.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8"}, + {file = "websockets-8.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb"}, + {file = "websockets-8.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5"}, + {file = "websockets-8.1-cp36-cp36m-win32.whl", hash = "sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a"}, + {file = "websockets-8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5"}, + {file = "websockets-8.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989"}, + {file = "websockets-8.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d"}, + {file = "websockets-8.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779"}, + {file = "websockets-8.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8"}, + {file = "websockets-8.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422"}, + {file = "websockets-8.1-cp37-cp37m-win32.whl", hash = "sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc"}, + {file = "websockets-8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308"}, + {file = "websockets-8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092"}, + {file = "websockets-8.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485"}, + {file = "websockets-8.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1"}, + {file = "websockets-8.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55"}, + {file = "websockets-8.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824"}, + {file = "websockets-8.1-cp38-cp38-win32.whl", hash = "sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36"}, + {file = "websockets-8.1-cp38-cp38-win_amd64.whl", hash = "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"}, + {file = "websockets-8.1.tar.gz", hash = "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f"}, +] 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 bc4928c3..d24450cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,11 +24,15 @@ packages = [ [tool.poetry.dependencies] python = "^3.7" +fastapi = "^0.58.1" +uvicorn = "^0.11.5" +pydantic = {extras = ["dotenv"], version = "^1.5.1"} apscheduler = { version = "^3.6.3", optional = true } [tool.poetry.dev-dependencies] yapf = "^0.30.0" sphinx = "^3.1.1" +sphinx-markdown-builder = { git = "https://github.com/nonebot/sphinx-markdown-builder.git" } [tool.poetry.extras] scheduler = ["apscheduler"] diff --git a/tests/.env b/tests/.env new file mode 100644 index 00000000..baf48fa8 --- /dev/null +++ b/tests/.env @@ -0,0 +1 @@ +ENVIRONMENT=dev diff --git a/tests/.env.dev b/tests/.env.dev new file mode 100644 index 00000000..7f675006 --- /dev/null +++ b/tests/.env.dev @@ -0,0 +1,4 @@ +DRIVER=nonebot.drivers.fastapi +HOST=0.0.0.0 +PORT=2333 +DEBUG=true diff --git a/tests/bot.py b/tests/bot.py index 8a4eb8e4..282fbb2f 100644 --- a/tests/bot.py +++ b/tests/bot.py @@ -4,14 +4,17 @@ import os import sys -sys.path.insert(0, os.path.abspath(os.path.dirname(os.path.dirname(__file__)))) +sys.path.insert(0, os.path.abspath("..")) import nonebot from nonebot.matcher import matchers +nonebot.init() +app = nonebot.get_asgi() + +nonebot.load_plugins("test_plugins") +print(nonebot.get_loaded_plugins()) +print(matchers) + if __name__ == "__main__": - nonebot.load_plugins(os.path.join(os.path.dirname(__file__), - "test_plugins")) - print(nonebot.get_loaded_plugins()) - print(matchers) - print(matchers[1][0].handlers) + nonebot.run(app="bot:app")