diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index ce958101..57251879 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -28,7 +28,43 @@ module.exports = { docsDir: "docs", lastUpdated: "上次更新", nav: [{ text: "API", link: "/api/" }], - sidebar: {} + sidebar: { + "/api/": [ + { + title: "NoneBot Api Reference", + path: "", + collapsable: false, + sidebarDepth: 3, + children: [ + { + title: "nonebot 模块", + path: "nonebot", + sidebar: "auto" + }, + { + title: "nonebot.typing 模块", + path: "typing", + sidebar: "auto" + }, + { + title: "nonebot.log 模块", + path: "log", + sidebar: "auto" + }, + { + title: "nonebot.exception 模块", + path: "exception", + sidebar: "auto" + }, + { + title: "nonebot.config 模块", + path: "config", + sidebar: "auto" + } + ] + } + ] + } }, plugins: ["@vuepress/plugin-back-to-top", "@vuepress/plugin-medium-zoom"] diff --git a/docs/.vuepress/enhanceApp.js b/docs/.vuepress/enhanceApp.js index 8452a868..800c2e5f 100644 --- a/docs/.vuepress/enhanceApp.js +++ b/docs/.vuepress/enhanceApp.js @@ -10,5 +10,20 @@ export default ({ router, // the router instance for the app siteData // site metadata }) => { - // ...apply enhancements for the site. -} + if (typeof process === "undefined" || process.env.VUE_ENV !== "server") { + router.onReady(() => { + const { app } = router; + app.$once("hook:mounted", () => { + // temporary fix for https://github.com/vuejs/vuepress/issues/2428 + setTimeout(() => { + const { hash } = document.location; + if (hash.length > 1) { + const id = hash.substring(1); + const element = document.getElementById(id); + if (element) element.scrollIntoView(); + } + }, 500); + }); + }); + } +}; diff --git a/docs/.vuepress/styles/palette.styl b/docs/.vuepress/styles/palette.styl index 238a5a9f..92cce343 100644 --- a/docs/.vuepress/styles/palette.styl +++ b/docs/.vuepress/styles/palette.styl @@ -4,7 +4,7 @@ * ref:https://v1.vuepress.vuejs.org/zh/config/#palette-styl */ -$accentColor = #d32f2f +$accentColor = #ea5252 $textColor = #2c3e50 $borderColor = #eaecef $codeBgColor = #282c34 diff --git a/docs/api/README.md b/docs/api/README.md index c9dd2074..1aaf25f7 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -10,4 +10,7 @@ * [nonebot.typing](typing.html) + * [nonebot.log](log.html) + + * [nonebot.config](config.html) diff --git a/docs/api/config.md b/docs/api/config.md index 475975b4..c160446d 100644 --- a/docs/api/config.md +++ b/docs/api/config.md @@ -1,32 +1,92 @@ # NoneBot.config 模块 -### _class_ `BaseConfig(_env_file='', _env_file_encoding=None)` +## _class_ `Env` 基类:`pydantic.env_settings.BaseSettings` +运行环境配置。大小写不敏感。 -### _class_ `Env(_env_file='', _env_file_encoding=None, *, environment='prod')` - -基类:`pydantic.env_settings.BaseSettings` +将会从 `nonebot.init 参数` > `环境变量` > `.env 环境配置文件` 的优先级读取配置。 -### _class_ `Config(_env_file='', _env_file_encoding=None, *, driver='nonebot.drivers.fastapi', host=IPv4Address('127.0.0.1'), port=8080, secret=None, debug=False, api_root={}, api_timeout=60.0, access_token=None, superusers={}, nickname='', command_start={'/'}, command_sep={'.'}, session_expire_timeout=datetime.timedelta(seconds=120), **values)` - -基类:[`nonebot.config.BaseConfig`](#nonebot.config.BaseConfig) - -NoneBot Config Object - -configs: - -### driver +### `environment` -* 类型: str +* 类型: `str` -* 默认值: "nonebot.drivers.fastapi" +* 默认值: `"prod"` * 说明: -nonebot 运行使用后端框架封装 Driver 。继承自 nonebot.driver.BaseDriver 。 +当前环境名。 NoneBot 将从 `.env.{environment}` 文件中加载配置。 + + +## _class_ `Config` + +基类:`nonebot.config.BaseConfig` + +NoneBot 主要配置。大小写不敏感。 + +除了 NoneBot 的配置项外,还可以自行添加配置项到 `.env.{environment}` 文件中。这些配置将会一起带入 `Config` 类中。 + + +### `driver` + + +* 类型: `str` + + +* 默认值: `"nonebot.drivers.fastapi"` + + +* 说明: +NoneBot 运行所使用的 `Driver` 。继承自 `nonebot.driver.BaseDriver` 。 + + +### `host` + + +* 类型: `IPvAnyAddress` + + +* 默认值: `127.0.0.1` + + +* 说明: +NoneBot 的 HTTP 和 WebSocket 服务端监听的 IP/主机名。 + + +### `port` + + +* 类型: `int` + + +* 默认值: `8080` + + +* 说明: +NoneBot 的 HTTP 和 WebSocket 服务端监听的端口。 + + +### `secret` + + +* 类型: `Optional[str]` + + +* 默认值: `None` + + +* 说明: +上报连接 NoneBot 所需的密钥。 + + +* 示例: + +```http +POST /cqhttp/ HTTP/1.1 +Authorization: Bearer kSLuTF2GC2Q4q4ugm3 +``` diff --git a/docs/api/exception.md b/docs/api/exception.md new file mode 100644 index 00000000..e04a0421 --- /dev/null +++ b/docs/api/exception.md @@ -0,0 +1,117 @@ +# NoneBot.exception 模块 + +## 异常 + +下列文档中的异常是所有 NoneBot 运行时可能会抛出的。 +这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。 + + +## _exception_ `IgnoredException` + +基类:`Exception` + + +* **说明** + + 指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。 + + + +* **参数** + + + * `reason`: 忽略事件的原因 + + + +## _exception_ `PausedException` + +基类:`Exception` + + +* **说明** + + 指示 NoneBot 结束当前 Handler 并等待下一条消息后继续下一个 Handler。 + 可用于用户输入新信息。 + + + +* **用法** + + 可以在 Handler 中通过 Matcher.pause() 抛出。 + + + +## _exception_ `RejectedException` + +基类:`Exception` + + +* **说明** + + 指示 NoneBot 结束当前 Handler 并等待下一条消息后重新运行当前 Handler。 + 可用于用户重新输入。 + + + +* **用法** + + 可以在 Handler 中通过 Matcher.reject() 抛出。 + + + +## _exception_ `FinishedException` + +基类:`Exception` + + +* **说明** + + 指示 NoneBot 结束当前 Handler 且后续 Handler 不再被运行。 + 可用于结束用户会话。 + + + +* **用法** + + 可以在 Handler 中通过 Matcher.finish() 抛出。 + + + +## _exception_ `ApiNotAvailable` + +基类:`Exception` + + +* **说明** + + 在 API 连接不可用时抛出。 + + + +## _exception_ `NetworkError` + +基类:`Exception` + + +* **说明** + + 在网络出现问题时抛出,如: API 请求地址不正确, API 请求无返回或返回状态非正常等。 + + + +## _exception_ `ActionFailed` + +基类:`Exception` + + +* **说明** + + API 请求成功返回数据,但 API 操作失败。 + + + +* **参数** + + + * `retcode`: 错误代码 diff --git a/docs/api/log.md b/docs/api/log.md new file mode 100644 index 00000000..d6f6048d --- /dev/null +++ b/docs/api/log.md @@ -0,0 +1,41 @@ +# NoneBot.log 模块 + +## 日志 + +NoneBot 使用标准库 [logging](https://docs.python.org/3/library/logging.html) 来记录日志信息。 + +自定义 logger 请参考 [logging](https://docs.python.org/3/library/logging.html) 文档。 + + +## `logger` + + +* **说明** + + NoneBot 日志记录器对象。 + + + +* **默认信息** + + + * 格式: `[%(asctime)s %(name)s] %(levelname)s: %(message)s` + + + * 等级: `DEBUG` / `INFO` ,根据 config 配置改变 + + + * 输出: 输出至 stdout + + + +* **用法** + + +```python +from nonebot.log import logger + +# 也可以这样 +import logging +logger = logging.getLogger("nonebot") +``` diff --git a/docs/api/nonebot.md b/docs/api/nonebot.md index e95dc56a..77a17cff 100644 --- a/docs/api/nonebot.md +++ b/docs/api/nonebot.md @@ -1,7 +1,7 @@ # NoneBot 模块 -### `get_driver()` +## `get_driver()` * **说明** @@ -32,7 +32,7 @@ driver = nonebot.get_driver() ``` -### `get_app()` +## `get_app()` * **说明** @@ -63,7 +63,7 @@ app = nonebot.get_app() ``` -### `get_asgi()` +## `get_asgi()` * **说明** @@ -94,7 +94,7 @@ asgi = nonebot.get_asgi() ``` -### `get_bots()` +## `get_bots()` * **说明** @@ -125,7 +125,7 @@ bots = nonebot.get_bots() ``` -### `init(*, _env_file=None, **kwargs)` +## `init(*, _env_file=None, **kwargs)` * **说明** @@ -163,7 +163,7 @@ nonebot.init(database=Database(...)) ``` -### `run(host=None, port=None, *args, **kwargs)` +## `run(host=None, port=None, *args, **kwargs)` * **说明** diff --git a/docs/api/typing.md b/docs/api/typing.md index a78ac660..71833b7a 100644 --- a/docs/api/typing.md +++ b/docs/api/typing.md @@ -9,7 +9,7 @@ 以下类型均可从 nonebot.typing 模块导入。 -### `Driver` +## `Driver` * **类型** @@ -25,7 +25,7 @@ -### `WebSocket` +## `WebSocket` * **类型** @@ -41,7 +41,7 @@ -### `Bot` +## `Bot` * **类型** @@ -57,7 +57,7 @@ -### `Event` +## `Event` * **类型** @@ -73,7 +73,7 @@ -### `Message` +## `Message` * **类型** @@ -89,7 +89,7 @@ -### `MessageSegment` +## `MessageSegment` * **类型** @@ -105,7 +105,7 @@ -### `PreProcessor` +## `PreProcessor` * **类型** @@ -121,7 +121,7 @@ -### `Matcher` +## `Matcher` * **类型** @@ -137,7 +137,7 @@ -### `Rule` +## `Rule` * **类型** @@ -153,7 +153,7 @@ -### `RuleChecker` +## `RuleChecker` * **类型** @@ -169,7 +169,7 @@ -### `Permission` +## `Permission` * **类型** @@ -185,7 +185,7 @@ -### `PermissionChecker` +## `PermissionChecker` * **类型** @@ -201,7 +201,7 @@ -### `Handler` +## `Handler` * **类型** @@ -217,7 +217,7 @@ -### `ArgsParser` +## `ArgsParser` * **类型** diff --git a/docs_build/README.rst b/docs_build/README.rst index 8a93c8d1..1ced2b53 100644 --- a/docs_build/README.rst +++ b/docs_build/README.rst @@ -4,4 +4,5 @@ NoneBot Api Reference :模块索引: - `nonebot `_ - `nonebot.typing `_ + - `nonebot.log `_ - `nonebot.config `_ diff --git a/docs_build/config.rst b/docs_build/config.rst index c34935d8..a9e7bc21 100644 --- a/docs_build/config.rst +++ b/docs_build/config.rst @@ -2,5 +2,5 @@ NoneBot.config 模块 =================== .. automodule:: nonebot.config - :members: + :members: Env, Config :show-inheritance: diff --git a/docs_build/exception.rst b/docs_build/exception.rst new file mode 100644 index 00000000..443d4ec4 --- /dev/null +++ b/docs_build/exception.rst @@ -0,0 +1,6 @@ +NoneBot.exception 模块 +====================== + +.. automodule:: nonebot.exception + :members: + :show-inheritance: diff --git a/docs_build/log.rst b/docs_build/log.rst new file mode 100644 index 00000000..d6839fc6 --- /dev/null +++ b/docs_build/log.rst @@ -0,0 +1,6 @@ +NoneBot.log 模块 +================= + +.. automodule:: nonebot.log + :members: + :show-inheritance: diff --git a/nonebot/config.py b/nonebot/config.py index 4850034b..2b99e459 100644 --- a/nonebot/config.py +++ b/nonebot/config.py @@ -9,7 +9,7 @@ from ipaddress import IPv4Address from pydantic import BaseSettings, IPvAnyAddress from pydantic.env_settings import SettingsError, env_file_sentinel, read_env_file -from nonebot.typing import Set, Dict, Union, Mapping, Optional +from nonebot.typing import Any, Set, Dict, Union, Mapping, Optional class BaseConfig(BaseSettings): @@ -73,9 +73,24 @@ class BaseConfig(BaseSettings): return d + def __getattr__(self, name: str) -> Any: + return self.__dict__.get(name) + class Env(BaseSettings): + """ + 运行环境配置。大小写不敏感。 + + 将会从 ``nonebot.init 参数`` > ``环境变量`` > ``.env 环境配置文件`` 的优先级读取配置。 + """ + environment: str = "prod" + """ + - 类型: ``str`` + - 默认值: ``"prod"`` + - 说明: + 当前环境名。 NoneBot 将从 ``.env.{environment}`` 文件中加载配置。 + """ class Config: env_file = ".env" @@ -83,23 +98,52 @@ class Env(BaseSettings): class Config(BaseConfig): """ - NoneBot Config Object + NoneBot 主要配置。大小写不敏感。 - configs: - - ### `driver` - - - 类型: `str` - - 默认值: `"nonebot.drivers.fastapi"` - - 说明: - nonebot 运行使用后端框架封装 Driver 。继承自 nonebot.driver.BaseDriver 。 + 除了 NoneBot 的配置项外,还可以自行添加配置项到 ``.env.{environment}`` 文件中。这些配置将会一起带入 ``Config`` 类中。 """ # nonebot configs driver: str = "nonebot.drivers.fastapi" + """ + - 类型: ``str`` + - 默认值: ``"nonebot.drivers.fastapi"`` + - 说明: + NoneBot 运行所使用的 ``Driver`` 。继承自 ``nonebot.driver.BaseDriver`` 。 + """ host: IPvAnyAddress = IPv4Address("127.0.0.1") # type: ignore + """ + - 类型: ``IPvAnyAddress`` + - 默认值: ``127.0.0.1`` + - 说明: + NoneBot 的 HTTP 和 WebSocket 服务端监听的 IP/主机名。 + """ port: int = 8080 + """ + - 类型: ``int`` + - 默认值: ``8080`` + - 说明: + NoneBot 的 HTTP 和 WebSocket 服务端监听的端口。 + """ secret: Optional[str] = None + """ + - 类型: ``Optional[str]`` + - 默认值: ``None`` + - 说明: + 上报连接 NoneBot 所需的密钥。 + - 示例: + + .. code-block:: http + + POST /cqhttp/ HTTP/1.1 + Authorization: Bearer kSLuTF2GC2Q4q4ugm3 + """ debug: bool = False + """ + - 类型: ``bool`` + - 默认值: ``False`` + - 说明: + 是否以调试模式运行 NoneBot。 + """ # bot connection configs api_root: Dict[str, str] = {} diff --git a/nonebot/exception.py b/nonebot/exception.py index cc485b7b..1a0eeb10 100644 --- a/nonebot/exception.py +++ b/nonebot/exception.py @@ -1,49 +1,108 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +""" +异常 +==== + +下列文档中的异常是所有 NoneBot 运行时可能会抛出的。 +这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。 +""" from nonebot.typing import Optional class IgnoredException(Exception): """ - Raised by event_preprocessor indicating that - the bot should ignore the event + :说明: + + 指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。 + + :参数: + + * ``reason``: 忽略事件的原因 + """ def __init__(self, reason): - """ - :param reason: reason to ignore the event - """ self.reason = reason + def __repr__(self): + return f"" + + def __str__(self): + return self.__repr__() + class PausedException(Exception): - """Block a message from further handling and try to receive a new message""" + """ + :说明: + + 指示 NoneBot 结束当前 Handler 并等待下一条消息后继续下一个 Handler。 + 可用于用户输入新信息。 + + :用法: + + 可以在 Handler 中通过 Matcher.pause() 抛出。 + """ pass class RejectedException(Exception): - """Reject a message and return current handler back""" + """ + :说明: + + 指示 NoneBot 结束当前 Handler 并等待下一条消息后重新运行当前 Handler。 + 可用于用户重新输入。 + + :用法: + + 可以在 Handler 中通过 Matcher.reject() 抛出。 + """ pass class FinishedException(Exception): - """Finish handling a message""" + """ + :说明: + + 指示 NoneBot 结束当前 Handler 且后续 Handler 不再被运行。 + 可用于结束用户会话。 + + :用法: + + 可以在 Handler 中通过 Matcher.finish() 抛出。 + """ pass class ApiNotAvailable(Exception): - """Api is not available""" + """ + :说明: + + 在 API 连接不可用时抛出。 + """ pass class NetworkError(Exception): - """There is something error with the network""" + """ + :说明: + + 在网络出现问题时抛出,如: API 请求地址不正确, API 请求无返回或返回状态非正常等。 + """ pass class ActionFailed(Exception): - """The action call returned a failed response""" + """ + :说明: + + API 请求成功返回数据,但 API 操作失败。 + + :参数: + + * ``retcode``: 错误代码 + """ def __init__(self, retcode: Optional[int]): self.retcode = retcode diff --git a/nonebot/log.py b/nonebot/log.py index 272eaeda..ae03d2f3 100644 --- a/nonebot/log.py +++ b/nonebot/log.py @@ -1,11 +1,42 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +""" +日志 +==== + +NoneBot 使用标准库 `logging`_ 来记录日志信息。 + +自定义 logger 请参考 `logging`_ 文档。 + +.. _logging: + https://docs.python.org/3/library/logging.html +""" import sys import logging logger = logging.getLogger("nonebot") -"""nonebot logger""" +""" +:说明: + + NoneBot 日志记录器对象。 + +:默认信息: + + * 格式: ``[%(asctime)s %(name)s] %(levelname)s: %(message)s`` + * 等级: ``DEBUG`` / ``INFO`` ,根据 config 配置改变 + * 输出: 输出至 stdout + +:用法: + +.. code-block:: python + + from nonebot.log import logger + + # 也可以这样 + import logging + logger = logging.getLogger("nonebot") +""" default_handler = logging.StreamHandler(sys.stdout) default_handler.setFormatter( diff --git a/poetry.lock b/poetry.lock index d857d4f0..3fa1228b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -600,7 +600,7 @@ unify = "*" yapf = "*" [package.source] -reference = "85ffe5c872e0ad57bfd1b5432d49e03a2f900a8f" +reference = "a70465ccfe577aee1612c987d20c0db93036e5d6" type = "git" url = "https://github.com/nonebot/sphinx-markdown-builder.git" [[package]] @@ -852,6 +852,7 @@ test = [] [metadata] content-hash = "4d16d7ad0930bc9851802bc149f843c4e990a987e89414d765579ea8dccc8d6e" +lock-version = "1.0" python-versions = "^3.7" [metadata.files] diff --git a/tests/.env.dev b/tests/.env.dev index 0749d9c9..f169a095 100644 --- a/tests/.env.dev +++ b/tests/.env.dev @@ -3,7 +3,7 @@ HOST=0.0.0.0 PORT=2333 DEBUG=true -COMMAND_START={"", "/", "#"} -COMMAND_SEP={"/", "."} +COMMAND_START=["", "/", "#"] +COMMAND_SEP=["/", "."] CUSTOM_CONFIG={"custom": 1} diff --git a/tests/test_plugins/test_message.py b/tests/test_plugins/test_message.py index 0ef9f938..d68adb78 100644 --- a/tests/test_plugins/test_message.py +++ b/tests/test_plugins/test_message.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -from nonebot.rule import Rule from nonebot.typing import Event from nonebot.plugin import on_message from nonebot.adapters.cqhttp import Bot @@ -14,6 +13,7 @@ async def test_handler(bot: Bot, event: Event, state: dict): print("Test Matcher Received:", event) print("Current State:", state) state["event"] = event + await bot.send_private_msg(message="Received", user_id=event.user_id) @test_message.receive() diff --git a/tests/test_plugins/test_metaevent.py b/tests/test_plugins/test_metaevent.py index 88f6a82f..a165cf10 100644 --- a/tests/test_plugins/test_metaevent.py +++ b/tests/test_plugins/test_metaevent.py @@ -5,7 +5,7 @@ from nonebot.plugin import on_metaevent from nonebot.typing import Bot, Event -def heartbeat(bot: Bot, event: Event) -> bool: +async def heartbeat(bot: Bot, event: Event, state: dict) -> bool: return event.detail_type == "heartbeat"