mirror of
https://github.com/nonebot/nonebot2.git
synced 2025-09-07 04:26:45 +00:00
🔀 Merge pull request #691
:construction_workerusing: nb-autodoc to generate api docs
This commit is contained in:
@ -1,31 +1,37 @@
|
||||
"""
|
||||
"""本模块主要定义了 NoneBot 启动所需函数,供 bot 入口文件调用。
|
||||
|
||||
## 快捷导入
|
||||
|
||||
为方便使用,`nonebot` 模块从子模块导入了部分内容
|
||||
为方便使用,本模块从子模块导入了部分内容,以下内容可以直接通过本模块导入:
|
||||
|
||||
- `on_message` => `nonebot.plugin.on_message`
|
||||
- `on_notice` => `nonebot.plugin.on_notice`
|
||||
- `on_request` => `nonebot.plugin.on_request`
|
||||
- `on_metaevent` => `nonebot.plugin.on_metaevent`
|
||||
- `on_startswith` => `nonebot.plugin.on_startswith`
|
||||
- `on_endswith` => `nonebot.plugin.on_endswith`
|
||||
- `on_keyword` => `nonebot.plugin.on_keyword`
|
||||
- `on_command` => `nonebot.plugin.on_command`
|
||||
- `on_shell_command` => `nonebot.plugin.on_shell_command`
|
||||
- `on_regex` => `nonebot.plugin.on_regex`
|
||||
- `CommandGroup` => `nonebot.plugin.CommandGroup`
|
||||
- `Matchergroup` => `nonebot.plugin.MatcherGroup`
|
||||
- `load_plugin` => `nonebot.plugin.load_plugin`
|
||||
- `load_plugins` => `nonebot.plugin.load_plugins`
|
||||
- `load_all_plugins` => `nonebot.plugin.load_all_plugins`
|
||||
- `load_from_json` => `nonebot.plugin.load_from_json`
|
||||
- `load_from_toml` => `nonebot.plugin.load_from_toml`
|
||||
- `load_builtin_plugin` => `nonebot.plugin.load_builtin_plugin`
|
||||
- `load_builtin_plugins` => `nonebot.plugin.load_builtin_plugins`
|
||||
- `get_plugin` => `nonebot.plugin.get_plugin`
|
||||
- `get_loaded_plugins` => `nonebot.plugin.get_loaded_plugins`
|
||||
- `export` => `nonebot.plugin.export`
|
||||
- `require` => `nonebot.plugin.require`
|
||||
- `on` => {ref}``on` <nonebot.plugin.on.on>`
|
||||
- `on_metaevent` => {ref}``on_metaevent` <nonebot.plugin.on.on_metaevent>`
|
||||
- `on_message` => {ref}``on_message` <nonebot.plugin.on.on_message>`
|
||||
- `on_notice` => {ref}``on_notice` <nonebot.plugin.on.on_notice>`
|
||||
- `on_request` => {ref}``on_request` <nonebot.plugin.on.on_request>`
|
||||
- `on_startswith` => {ref}``on_startswith` <nonebot.plugin.on.on_startswith>`
|
||||
- `on_endswith` => {ref}``on_endswith` <nonebot.plugin.on.on_endswith>`
|
||||
- `on_keyword` => {ref}``on_keyword` <nonebot.plugin.on.on_keyword>`
|
||||
- `on_command` => {ref}``on_command` <nonebot.plugin.on.on_command>`
|
||||
- `on_shell_command` => {ref}``on_shell_command` <nonebot.plugin.on.on_shell_command>`
|
||||
- `on_regex` => {ref}``on_regex` <nonebot.plugin.on.on_regex>`
|
||||
- `CommandGroup` => {ref}``CommandGroup` <nonebot.plugin.on.CommandGroup>`
|
||||
- `Matchergroup` => {ref}``MatcherGroup` <nonebot.plugin.on.MatcherGroup>`
|
||||
- `load_plugin` => {ref}``load_plugin` <nonebot.plugin.load.load_plugin>`
|
||||
- `load_plugins` => {ref}``load_plugins` <nonebot.plugin.load.load_plugins>`
|
||||
- `load_all_plugins` => {ref}``load_all_plugins` <nonebot.plugin.load.load_all_plugins>`
|
||||
- `load_from_json` => {ref}``load_from_json` <nonebot.plugin.load.load_from_json>`
|
||||
- `load_from_toml` => {ref}``load_from_toml` <nonebot.plugin.load.load_from_toml>`
|
||||
- `load_builtin_plugin` => {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>`
|
||||
- `load_builtin_plugins` => {ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>`
|
||||
- `get_plugin` => {ref}``get_plugin` <nonebot.plugin.plugin.get_plugin>`
|
||||
- `get_loaded_plugins` => {ref}``get_loaded_plugins` <nonebot.plugin.plugin.get_loaded_plugins>`
|
||||
- `export` => {ref}``export` <nonebot.plugin.export.export>`
|
||||
- `require` => {ref}``require` <nonebot.plugin.load.require>`
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot 模块
|
||||
"""
|
||||
|
||||
import importlib
|
||||
@ -51,14 +57,15 @@ _driver: Optional[Driver] = None
|
||||
|
||||
|
||||
def get_driver() -> Driver:
|
||||
"""
|
||||
获取全局 Driver 对象。可用于在计划任务的回调中获取当前 Driver 对象。
|
||||
"""获取全局 {ref}`nonebot.drivers.Driver` 实例。
|
||||
|
||||
可用于在计划任务的回调等情形中获取当前 {ref}`nonebot.drivers.Driver` 实例。
|
||||
|
||||
返回:
|
||||
Driver: 全局 Driver 对象
|
||||
全局 {ref}`nonebot.drivers.Driver` 对象
|
||||
|
||||
异常:
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -71,14 +78,14 @@ def get_driver() -> Driver:
|
||||
|
||||
|
||||
def get_app() -> Any:
|
||||
"""
|
||||
获取全局 Driver 对应 Server App 对象。
|
||||
"""获取全局 {ref}`nonebot.drivers.ReverseDriver` 对应的 Server App 对象。
|
||||
|
||||
返回:
|
||||
Any: Server App 对象
|
||||
Server App 对象
|
||||
|
||||
异常:
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
AssertionError: 全局 Driver 对象不是 {ref}`nonebot.drivers.ReverseDriver` 类型
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -93,14 +100,14 @@ def get_app() -> Any:
|
||||
|
||||
|
||||
def get_asgi() -> Any:
|
||||
"""
|
||||
获取全局 Driver 对应 Asgi 对象。
|
||||
"""获取全局 {ref}`nonebot.drivers.ReverseDriver` 对应 [ASGI](https://asgi.readthedocs.io/) 对象。
|
||||
|
||||
返回:
|
||||
Any: Asgi 对象
|
||||
ASGI 对象
|
||||
|
||||
异常:
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
AssertionError: 全局 Driver 对象不是 {ref}`nonebot.drivers.ReverseDriver` 类型
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -115,23 +122,25 @@ def get_asgi() -> Any:
|
||||
|
||||
|
||||
def get_bot(self_id: Optional[str] = None) -> Bot:
|
||||
"""
|
||||
当提供 self_id 时,此函数是 get_bots()[self_id] 的简写;当不提供时,返回一个 Bot。
|
||||
"""获取一个连接到 NoneBot 的 {ref}`nonebot.adapters._bot.Bot` 对象。
|
||||
|
||||
当提供 `self_id` 时,此函数是 `get_bots()[self_id]` 的简写;
|
||||
当不提供时,返回一个 {ref}`nonebot.adapters._bot.Bot`。
|
||||
|
||||
参数:
|
||||
self_id: 用来识别 Bot 的 ID
|
||||
self_id: 用来识别 {ref}`nonebot.adapters._bot.Bot` 的 {ref}`nonebot.adapters._bot.Bot.self_id` 属性
|
||||
|
||||
返回:
|
||||
Bot: Bot 对象
|
||||
{ref}`nonebot.adapters._bot.Bot` 对象
|
||||
|
||||
异常:
|
||||
KeyError: 对应 ID 的 Bot 不存在
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
ValueError: 没有传入 ID 且没有 Bot 可用
|
||||
KeyError: 对应 self_id 的 Bot 不存在
|
||||
ValueError: 没有传入 self_id 且没有 Bot 可用
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
assert nonebot.get_bot('12345') == nonebot.get_bots()['12345']
|
||||
assert nonebot.get_bot("12345") == nonebot.get_bots()["12345"]
|
||||
|
||||
another_unspecified_bot = nonebot.get_bot()
|
||||
```
|
||||
@ -147,14 +156,13 @@ def get_bot(self_id: Optional[str] = None) -> Bot:
|
||||
|
||||
|
||||
def get_bots() -> Dict[str, Bot]:
|
||||
"""
|
||||
获取所有通过 ws 连接 NoneBot 的 Bot 对象。
|
||||
"""获取所有连接到 NoneBot 的 {ref}`nonebot.adapters._bot.Bot` 对象。
|
||||
|
||||
返回:
|
||||
Dict[str, Bot]: 一个以字符串 ID 为键,Bot 对象为值的字典
|
||||
一个以 {ref}`nonebot.adapters._bot.Bot.self_id` 为键,{ref}`nonebot.adapters._bot.Bot` 对象为值的字典
|
||||
|
||||
异常:
|
||||
ValueError: 全局 Driver 对象尚未初始化 (nonebot.init 尚未调用)
|
||||
ValueError: 全局 {ref}`nonebot.drivers.Driver` 对象尚未初始化 ({ref}`nonebot.init <nonebot.init>` 尚未调用)
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -196,17 +204,16 @@ def _resolve_combine_expr(obj_str: str) -> Type[Driver]:
|
||||
return combine_driver(DriverClass, *mixins)
|
||||
|
||||
|
||||
def init(*, _env_file: Optional[str] = None, **kwargs):
|
||||
"""
|
||||
初始化 NoneBot 以及 全局 Driver 对象。
|
||||
def init(*, _env_file: Optional[str] = None, **kwargs: Any) -> None:
|
||||
"""初始化 NoneBot 以及 全局 {ref}`nonebot.drivers.Driver` 对象。
|
||||
|
||||
NoneBot 将会从 .env 文件中读取环境信息,并使用相应的 env 文件配置。
|
||||
|
||||
你也可以传入自定义的 _env_file 来指定 NoneBot 从该文件读取配置。
|
||||
也可以传入自定义的 `_env_file` 来指定 NoneBot 从该文件读取配置。
|
||||
|
||||
参数:
|
||||
_env_file: 配置文件名,默认从 .env.{env_name} 中读取配置
|
||||
**kwargs: 任意变量,将会存储到 Config 对象里
|
||||
_env_file: 配置文件名,默认从 `.env.{env_name}` 中读取配置
|
||||
kwargs: 任意变量,将会存储到 {ref}`nonebot.drivers.Driver.config` 对象里
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -236,12 +243,11 @@ def init(*, _env_file: Optional[str] = None, **kwargs):
|
||||
|
||||
|
||||
def run(*args: Any, **kwargs: Any) -> None:
|
||||
"""
|
||||
启动 NoneBot,即运行全局 Driver 对象。
|
||||
"""启动 NoneBot,即运行全局 {ref}`nonebot.drivers.Driver` 对象。
|
||||
|
||||
参数:
|
||||
*args: 传入 Driver.run 的位置参数
|
||||
**kwargs: 传入 Driver.run 的命名参数
|
||||
args: 传入 {ref}`nonebot.drivers.Driver.run` 的位置参数
|
||||
kwargs: 传入 {ref}`nonebot.drivers.Driver.run` 的命名参数
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -253,6 +259,7 @@ def run(*args: Any, **kwargs: Any) -> None:
|
||||
|
||||
|
||||
import nonebot.params as params
|
||||
from nonebot.plugin import on as on
|
||||
from nonebot.plugin import export as export
|
||||
from nonebot.plugin import require as require
|
||||
from nonebot.plugin import on_regex as on_regex
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""
|
||||
## 协议适配基类
|
||||
"""本模块定义了协议适配基类,各协议请继承以下基类。
|
||||
|
||||
各协议请继承以下基类,并使用 `driver.register_adapter` 注册适配器
|
||||
使用 {ref}`nonebot.drivers.Driver.register_adapter` 注册适配器。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot.adapters 模块
|
||||
"""
|
||||
|
||||
from typing import Iterable
|
||||
@ -25,3 +28,11 @@ from ._adapter import Adapter as Adapter
|
||||
from ._message import Message as Message
|
||||
from ._message import MessageSegment as MessageSegment
|
||||
from ._template import MessageTemplate as MessageTemplate
|
||||
|
||||
__autodoc__ = {
|
||||
"_bot": True,
|
||||
"_event": True,
|
||||
"_adapter": True,
|
||||
"_message": True,
|
||||
"_template": True,
|
||||
}
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.adapters._adapter 模块
|
||||
"""
|
||||
import abc
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Any, Dict, AsyncGenerator
|
||||
@ -18,56 +23,89 @@ from ._bot import Bot
|
||||
|
||||
|
||||
class Adapter(abc.ABC):
|
||||
"""协议适配器基类。
|
||||
|
||||
通常,在 Adapter 中编写协议通信相关代码,如: 建立通信连接、处理接收与发送 data 等。
|
||||
|
||||
参数:
|
||||
driver: {ref}`nonebot.drivers.Driver` 实例
|
||||
kwargs: 其他由 {ref}`nonebot.drivers.Driver.register_adapter` 传入的额外参数
|
||||
"""
|
||||
|
||||
def __init__(self, driver: Driver, **kwargs: Any):
|
||||
self.driver: Driver = driver
|
||||
"""{ref}`nonebot.drivers.Driver` 实例"""
|
||||
self.bots: Dict[str, Bot] = {}
|
||||
"""本协议适配器已建立连接的 {ref}`nonebot.adapters._bot.Bot` 实例"""
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def get_name(cls) -> str:
|
||||
"""当前协议适配器的名称"""
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def config(self) -> Config:
|
||||
"""全局 NoneBot 配置"""
|
||||
return self.driver.config
|
||||
|
||||
def bot_connect(self, bot: Bot) -> None:
|
||||
"""告知 NoneBot 建立了一个新的 {ref}`nonebot.adapters._bot.Bot` 连接。
|
||||
|
||||
当有新的 {ref}`nonebot.adapters._bot.Bot` 实例连接建立成功时调用。
|
||||
|
||||
参数:
|
||||
bot: {ref}`nonebot.adapters._bot.Bot` 实例
|
||||
"""
|
||||
self.driver._bot_connect(bot)
|
||||
self.bots[bot.self_id] = bot
|
||||
|
||||
def bot_disconnect(self, bot: Bot) -> None:
|
||||
"""告知 NoneBot {ref}`nonebot.adapters._bot.Bot` 连接已断开。
|
||||
|
||||
当有 {ref}`nonebot.adapters._bot.Bot` 实例连接断开时调用。
|
||||
|
||||
参数:
|
||||
bot: {ref}`nonebot.adapters._bot.Bot` 实例
|
||||
"""
|
||||
self.driver._bot_disconnect(bot)
|
||||
self.bots.pop(bot.self_id, None)
|
||||
|
||||
def setup_http_server(self, setup: HTTPServerSetup):
|
||||
"""设置一个 HTTP 服务器路由配置"""
|
||||
if not isinstance(self.driver, ReverseDriver):
|
||||
raise TypeError("Current driver does not support http server")
|
||||
self.driver.setup_http_server(setup)
|
||||
|
||||
def setup_websocket_server(self, setup: WebSocketServerSetup):
|
||||
"""设置一个 WebSocket 服务器路由配置"""
|
||||
if not isinstance(self.driver, ReverseDriver):
|
||||
raise TypeError("Current driver does not support websocket server")
|
||||
self.driver.setup_websocket_server(setup)
|
||||
|
||||
async def request(self, setup: Request) -> Response:
|
||||
"""进行一个 HTTP 客户端请求"""
|
||||
if not isinstance(self.driver, ForwardDriver):
|
||||
raise TypeError("Current driver does not support http client")
|
||||
return await self.driver.request(setup)
|
||||
|
||||
@asynccontextmanager
|
||||
async def websocket(self, setup: Request) -> AsyncGenerator[WebSocket, None]:
|
||||
"""建立一个 WebSocket 客户端连接请求"""
|
||||
if not isinstance(self.driver, ForwardDriver):
|
||||
raise TypeError("Current driver does not support websocket client")
|
||||
async with self.driver.websocket(setup) as ws:
|
||||
yield ws
|
||||
|
||||
@abc.abstractmethod
|
||||
async def _call_api(self, bot: Bot, api: str, **data) -> Any:
|
||||
"""
|
||||
`adapter` 实际调用 api 的逻辑实现函数,实现该方法以调用 api。
|
||||
async def _call_api(self, bot: Bot, api: str, **data: Any) -> Any:
|
||||
"""`Adapter` 实际调用 api 的逻辑实现函数,实现该方法以调用 api。
|
||||
|
||||
参数:
|
||||
api: API 名称
|
||||
**data: API 数据
|
||||
data: API 数据
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
__autodoc__ = {"Adapter._call_api": True}
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 2
|
||||
description: nonebot.adapters._bot 模块
|
||||
"""
|
||||
import abc
|
||||
import asyncio
|
||||
from functools import partial
|
||||
@ -21,26 +26,23 @@ class _ApiCall(Protocol):
|
||||
|
||||
|
||||
class Bot(abc.ABC):
|
||||
"""
|
||||
Bot 基类。用于处理上报消息,并提供 API 调用接口。
|
||||
"""Bot 基类。
|
||||
|
||||
用于处理上报消息,并提供 API 调用接口。
|
||||
|
||||
参数:
|
||||
adapter: 协议适配器实例
|
||||
self_id: 机器人 ID
|
||||
"""
|
||||
|
||||
_calling_api_hook: Set[T_CallingAPIHook] = set()
|
||||
"""
|
||||
call_api 时执行的函数
|
||||
"""
|
||||
"""call_api 时执行的函数"""
|
||||
_called_api_hook: Set[T_CalledAPIHook] = set()
|
||||
"""
|
||||
call_api 后执行的函数
|
||||
"""
|
||||
"""call_api 后执行的函数"""
|
||||
|
||||
def __init__(self, adapter: "Adapter", self_id: str):
|
||||
"""
|
||||
参数:
|
||||
self_id: 机器人 ID
|
||||
request: request 连接对象
|
||||
"""
|
||||
self.adapter: "Adapter" = adapter
|
||||
"""协议适配器实例"""
|
||||
self.self_id: str = self_id
|
||||
"""机器人 ID"""
|
||||
|
||||
@ -49,19 +51,20 @@ class Bot(abc.ABC):
|
||||
|
||||
@property
|
||||
def type(self) -> str:
|
||||
"""协议适配器名称"""
|
||||
return self.adapter.get_name()
|
||||
|
||||
@property
|
||||
def config(self) -> Config:
|
||||
"""全局 NoneBot 配置"""
|
||||
return self.adapter.config
|
||||
|
||||
async def call_api(self, api: str, **data: Any) -> Any:
|
||||
"""
|
||||
调用机器人 API 接口,可以通过该函数或直接通过 bot 属性进行调用
|
||||
"""调用机器人 API 接口,可以通过该函数或直接通过 bot 属性进行调用
|
||||
|
||||
参数:
|
||||
api: API 名称
|
||||
**data: API 数据
|
||||
data: API 数据
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -121,41 +124,44 @@ class Bot(abc.ABC):
|
||||
|
||||
@abc.abstractmethod
|
||||
async def send(
|
||||
self, event: "Event", message: Union[str, "Message", "MessageSegment"], **kwargs
|
||||
self,
|
||||
event: "Event",
|
||||
message: Union[str, "Message", "MessageSegment"],
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""
|
||||
调用机器人基础发送消息接口
|
||||
"""调用机器人基础发送消息接口
|
||||
|
||||
参数:
|
||||
event: 上报事件
|
||||
message: 要发送的消息
|
||||
kwargs: 任意额外参数
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def on_calling_api(cls, func: T_CallingAPIHook) -> T_CallingAPIHook:
|
||||
"""
|
||||
调用 api 预处理。
|
||||
"""调用 api 预处理。
|
||||
|
||||
参数:
|
||||
bot: 当前 bot 对象
|
||||
api: 调用的 api 名称
|
||||
data: api 调用的参数字典
|
||||
钩子函数参数:
|
||||
|
||||
- bot: 当前 bot 对象
|
||||
- api: 调用的 api 名称
|
||||
- data: api 调用的参数字典
|
||||
"""
|
||||
cls._calling_api_hook.add(func)
|
||||
return func
|
||||
|
||||
@classmethod
|
||||
def on_called_api(cls, func: T_CalledAPIHook) -> T_CalledAPIHook:
|
||||
"""
|
||||
调用 api 后处理。
|
||||
"""调用 api 后处理。
|
||||
|
||||
参数:
|
||||
bot: 当前 bot 对象
|
||||
exception: 调用 api 时发生的错误
|
||||
api: 调用的 api 名称
|
||||
data: api 调用的参数字典
|
||||
result: api 调用的返回
|
||||
钩子函数参数:
|
||||
|
||||
- bot: 当前 bot 对象
|
||||
- exception: 调用 api 时发生的错误
|
||||
- api: 调用的 api 名称
|
||||
- data: api 调用的参数字典
|
||||
- result: api 调用的返回
|
||||
"""
|
||||
cls._called_api_hook.add(func)
|
||||
return func
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 3
|
||||
description: nonebot.adapters._event 模块
|
||||
"""
|
||||
import abc
|
||||
|
||||
from pydantic import BaseModel
|
||||
@ -16,31 +21,26 @@ class Event(abc.ABC, BaseModel):
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_type(self) -> str:
|
||||
"""
|
||||
获取事件类型的方法,类型通常为 NoneBot 内置的四种类型。
|
||||
"""
|
||||
"""获取事件类型的方法,类型通常为 NoneBot 内置的四种类型。"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_event_name(self) -> str:
|
||||
"""
|
||||
获取事件名称的方法。
|
||||
"""
|
||||
"""获取事件名称的方法。"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_event_description(self) -> str:
|
||||
"""
|
||||
获取事件描述的方法,通常为事件具体内容。
|
||||
"""
|
||||
"""获取事件描述的方法,通常为事件具体内容。"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"[{self.get_event_name()}]: {self.get_event_description()}"
|
||||
|
||||
def get_log_string(self) -> str:
|
||||
"""
|
||||
获取事件日志信息的方法,通常你不需要修改这个方法,只有当希望 NoneBot 隐藏该事件日志时,可以抛出 `NoLogException` 异常。
|
||||
"""获取事件日志信息的方法。
|
||||
|
||||
通常你不需要修改这个方法,只有当希望 NoneBot 隐藏该事件日志时,可以抛出 `NoLogException` 异常。
|
||||
|
||||
异常:
|
||||
NoLogException
|
||||
@ -49,34 +49,27 @@ class Event(abc.ABC, BaseModel):
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_user_id(self) -> str:
|
||||
"""
|
||||
获取事件主体 id 的方法,通常是用户 id 。
|
||||
"""
|
||||
"""获取事件主体 id 的方法,通常是用户 id 。"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_session_id(self) -> str:
|
||||
"""
|
||||
获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。
|
||||
"""
|
||||
"""获取会话 id 的方法,用于判断当前事件属于哪一个会话,通常是用户 id、群组 id 组合。"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_message(self) -> "Message":
|
||||
"""
|
||||
获取事件消息内容的方法。
|
||||
"""
|
||||
"""获取事件消息内容的方法。"""
|
||||
raise NotImplementedError
|
||||
|
||||
def get_plaintext(self) -> str:
|
||||
"""
|
||||
获取消息纯文本的方法,通常不需要修改,默认通过 `get_message().extract_plain_text` 获取。
|
||||
"""获取消息纯文本的方法。
|
||||
|
||||
通常不需要修改,默认通过 `get_message().extract_plain_text` 获取。
|
||||
"""
|
||||
return self.get_message().extract_plain_text()
|
||||
|
||||
@abc.abstractmethod
|
||||
def is_tome(self) -> bool:
|
||||
"""
|
||||
获取事件是否与机器人有关的方法。
|
||||
"""
|
||||
"""获取事件是否与机器人有关的方法。"""
|
||||
raise NotImplementedError
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 4
|
||||
description: nonebot.adapters._message 模块
|
||||
"""
|
||||
import abc
|
||||
from copy import deepcopy
|
||||
from dataclasses import field, asdict, dataclass
|
||||
@ -28,17 +33,14 @@ class MessageSegment(Mapping, abc.ABC, Generic[TM]):
|
||||
"""消息段基类"""
|
||||
|
||||
type: str
|
||||
"""
|
||||
消息段类型
|
||||
"""
|
||||
"""消息段类型"""
|
||||
data: Dict[str, Any] = field(default_factory=lambda: {})
|
||||
"""
|
||||
消息段数据
|
||||
"""
|
||||
"""消息段数据"""
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def get_message_class(cls) -> Type[TM]:
|
||||
"""获取消息数组类型"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
@ -87,11 +89,16 @@ class MessageSegment(Mapping, abc.ABC, Generic[TM]):
|
||||
|
||||
@abc.abstractmethod
|
||||
def is_text(self) -> bool:
|
||||
"""当前消息段是否为纯文本"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Message(List[TMS], abc.ABC):
|
||||
"""消息数组"""
|
||||
"""消息数组
|
||||
|
||||
参数:
|
||||
message: 消息内容
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self: TM,
|
||||
@ -99,10 +106,6 @@ class Message(List[TMS], abc.ABC):
|
||||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
参数:
|
||||
message: 消息内容
|
||||
"""
|
||||
super().__init__(*args, **kwargs)
|
||||
if message is None:
|
||||
return
|
||||
@ -115,8 +118,9 @@ class Message(List[TMS], abc.ABC):
|
||||
|
||||
@classmethod
|
||||
def template(cls: Type[TM], format_string: Union[str, TM]) -> MessageTemplate[TM]:
|
||||
"""
|
||||
根据创建消息模板, 用法和 `str.format` 大致相同, 但是可以输出消息对象, 并且支持以 `Message` 对象作为消息模板
|
||||
"""创建消息模板。
|
||||
|
||||
用法和 `str.format` 大致相同, 但是可以输出消息对象, 并且支持以 `Message` 对象作为消息模板
|
||||
|
||||
并且提供了拓展的格式化控制符, 可以用适用于该消息类型的 `MessageSegment` 的工厂方法创建消息
|
||||
|
||||
@ -140,13 +144,14 @@ class Message(List[TMS], abc.ABC):
|
||||
format_string: 格式化字符串
|
||||
|
||||
返回:
|
||||
MessageFormatter[TM]: 消息格式化器
|
||||
消息格式化器
|
||||
"""
|
||||
return MessageTemplate(format_string, cls)
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def get_segment_class(cls) -> Type[TMS]:
|
||||
"""获取消息段类型"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __str__(self):
|
||||
@ -163,6 +168,7 @@ class Message(List[TMS], abc.ABC):
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def _construct(msg: Union[str, Mapping, Iterable[Mapping], Any]) -> Iterable[TMS]:
|
||||
"""构造消息数组"""
|
||||
raise NotImplementedError
|
||||
|
||||
def __add__(self: TM, other: Union[str, Mapping, Iterable[Mapping]]) -> TM:
|
||||
@ -249,8 +255,7 @@ class Message(List[TMS], abc.ABC):
|
||||
return len(self[value]) if isinstance(value, str) else super().count(value)
|
||||
|
||||
def append(self: TM, obj: Union[str, TMS]) -> TM:
|
||||
"""
|
||||
添加一个消息段到消息数组末尾
|
||||
"""添加一个消息段到消息数组末尾。
|
||||
|
||||
参数:
|
||||
obj: 要添加的消息段
|
||||
@ -264,8 +269,7 @@ class Message(List[TMS], abc.ABC):
|
||||
return self
|
||||
|
||||
def extend(self: TM, obj: Union[TM, Iterable[TMS]]) -> TM:
|
||||
"""
|
||||
拼接一个消息数组或多个消息段到消息数组末尾
|
||||
"""拼接一个消息数组或多个消息段到消息数组末尾。
|
||||
|
||||
参数:
|
||||
obj: 要添加的消息数组
|
||||
@ -278,8 +282,9 @@ class Message(List[TMS], abc.ABC):
|
||||
return deepcopy(self)
|
||||
|
||||
def extract_plain_text(self: "Message[MessageSegment]") -> str:
|
||||
"""
|
||||
提取消息内纯文本消息
|
||||
"""
|
||||
"""提取消息内纯文本消息"""
|
||||
|
||||
return "".join(str(seg) for seg in self if seg.is_text())
|
||||
|
||||
|
||||
__autodoc__ = {"MessageSegment.__str__": True}
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 5
|
||||
description: nonebot.adapters._template 模块
|
||||
"""
|
||||
import inspect
|
||||
import functools
|
||||
from string import Formatter
|
||||
@ -31,7 +36,12 @@ FormatSpecFunc_T = TypeVar("FormatSpecFunc_T", bound=FormatSpecFunc)
|
||||
|
||||
|
||||
class MessageTemplate(Formatter, Generic[TF]):
|
||||
"""消息模板格式化实现类"""
|
||||
"""消息模板格式化实现类。
|
||||
|
||||
参数:
|
||||
template: 模板
|
||||
factory: 消息构造类型,默认为 `str`
|
||||
"""
|
||||
|
||||
@overload
|
||||
def __init__(
|
||||
@ -46,13 +56,6 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
...
|
||||
|
||||
def __init__(self, template, factory=str) -> None:
|
||||
"""
|
||||
创建一个模板
|
||||
|
||||
参数:
|
||||
template: 模板
|
||||
factory: 消息构造类型,默认为 `str`
|
||||
"""
|
||||
self.template: TF = template
|
||||
self.factory: Type[TF] = factory
|
||||
self.format_specs: Dict[str, FormatSpecFunc] = {}
|
||||
@ -67,9 +70,7 @@ class MessageTemplate(Formatter, Generic[TF]):
|
||||
return spec
|
||||
|
||||
def format(self, *args: Any, **kwargs: Any) -> TF:
|
||||
"""
|
||||
根据模板和参数生成消息对象
|
||||
"""
|
||||
"""根据模板和参数生成消息对象"""
|
||||
msg = self.factory()
|
||||
if isinstance(self.template, str):
|
||||
msg += self.vformat(self.template, args, kwargs)
|
||||
|
@ -1,9 +1,12 @@
|
||||
"""
|
||||
## 配置
|
||||
"""本模块定义了 NoneBot 本身运行所需的配置项。
|
||||
|
||||
NoneBot 使用 [`pydantic`](https://pydantic-docs.helpmanual.io/) 以及 [`python-dotenv`](https://saurabh-kumar.com/python-dotenv/) 来读取配置。
|
||||
|
||||
配置项需符合特殊格式或 json 序列化格式。详情见 [`pydantic Field Type`](https://pydantic-docs.helpmanual.io/usage/types/) 文档。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.config 模块
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
@ -11,7 +14,7 @@ from datetime import timedelta
|
||||
from ipaddress import IPv4Address
|
||||
from typing import Any, Set, Dict, Tuple, Union, Mapping, Optional
|
||||
|
||||
from pydantic import BaseSettings, IPvAnyAddress
|
||||
from pydantic import BaseSettings, IPvAnyAddress, validator
|
||||
from pydantic.env_settings import (
|
||||
SettingsError,
|
||||
EnvSettingsSource,
|
||||
@ -121,15 +124,15 @@ class BaseConfig(BaseSettings):
|
||||
|
||||
|
||||
class Env(BaseConfig):
|
||||
"""
|
||||
运行环境配置。大小写不敏感。
|
||||
"""运行环境配置。大小写不敏感。
|
||||
|
||||
将会从 `nonebot.init 参数` > `环境变量` > `.env 环境配置文件` 的优先级读取配置。
|
||||
将会从 `环境变量` > `.env 环境配置文件` 的优先级读取环境信息。
|
||||
"""
|
||||
|
||||
environment: str = "prod"
|
||||
"""
|
||||
当前环境名。 NoneBot 将从 `.env.{environment}` 文件中加载配置。
|
||||
"""当前环境名。
|
||||
|
||||
NoneBot 将从 `.env.{environment}` 文件中加载配置。
|
||||
"""
|
||||
|
||||
class Config:
|
||||
@ -138,36 +141,37 @@ class Env(BaseConfig):
|
||||
|
||||
|
||||
class Config(BaseConfig):
|
||||
"""
|
||||
NoneBot 主要配置。大小写不敏感。
|
||||
"""NoneBot 主要配置。大小写不敏感。
|
||||
|
||||
除了 NoneBot 的配置项外,还可以自行添加配置项到 `.env.{environment}` 文件中。
|
||||
这些配置将会在 json 反序列化后一起带入 `Config` 类中。
|
||||
|
||||
配置方法参考: [配置](https://v2.nonebot.dev/docs/tutorial/configuration)
|
||||
"""
|
||||
|
||||
_common_config: dict
|
||||
_env_file: str
|
||||
_common_config: Dict[str, Any]
|
||||
|
||||
# nonebot configs
|
||||
driver: str = "~fastapi"
|
||||
"""
|
||||
NoneBot 运行所使用的 `Driver` 。继承自 `nonebot.drivers.Driver` 。
|
||||
"""NoneBot 运行所使用的 `Driver` 。继承自 {ref}`nonebot.drivers.Driver` 。
|
||||
|
||||
配置格式为 `<module>[:<Driver>][+<module>[:<Mixin>]]*`。
|
||||
|
||||
`~` 为 `nonebot.drivers.` 的缩写。
|
||||
"""
|
||||
host: IPvAnyAddress = IPv4Address("127.0.0.1") # type: ignore
|
||||
"""
|
||||
NoneBot 的 HTTP 和 WebSocket 服务端监听的 IP/主机名。
|
||||
"""
|
||||
"""NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的 IP/主机名。"""
|
||||
port: int = 8080
|
||||
"""
|
||||
NoneBot 的 HTTP 和 WebSocket 服务端监听的端口。
|
||||
"""
|
||||
"""NoneBot {ref}`nonebot.drivers.ReverseDriver` 服务端监听的端口。"""
|
||||
log_level: Union[int, str] = "INFO"
|
||||
"""
|
||||
配置 NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称,参考 [`loguru 日志等级`](https://loguru.readthedocs.io/en/stable/api/logger.html#levels)。
|
||||
"""NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称
|
||||
|
||||
参考 [`loguru 日志等级`](https://loguru.readthedocs.io/en/stable/api/logger.html#levels)。
|
||||
|
||||
:::tip 提示
|
||||
日志等级名称应为大写,如 `INFO`。
|
||||
:::
|
||||
|
||||
用法:
|
||||
```conf
|
||||
@ -178,14 +182,11 @@ class Config(BaseConfig):
|
||||
|
||||
# bot connection configs
|
||||
api_timeout: Optional[float] = 30.0
|
||||
"""
|
||||
API 请求超时时间,单位: 秒。
|
||||
"""
|
||||
"""API 请求超时时间,单位: 秒。"""
|
||||
|
||||
# bot runtime configs
|
||||
superusers: Set[str] = set()
|
||||
"""
|
||||
机器人超级用户。
|
||||
"""机器人超级用户。
|
||||
|
||||
用法:
|
||||
```conf
|
||||
@ -193,20 +194,25 @@ class Config(BaseConfig):
|
||||
```
|
||||
"""
|
||||
nickname: Set[str] = set()
|
||||
"""
|
||||
机器人昵称。
|
||||
"""
|
||||
"""机器人昵称。"""
|
||||
command_start: Set[str] = {"/"}
|
||||
"""
|
||||
命令的起始标记,用于判断一条消息是不是命令。
|
||||
"""命令的起始标记,用于判断一条消息是不是命令。
|
||||
|
||||
用法:
|
||||
```conf
|
||||
COMMAND_START=["/", ""]
|
||||
```
|
||||
"""
|
||||
command_sep: Set[str] = {"."}
|
||||
"""
|
||||
命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。
|
||||
"""命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。
|
||||
|
||||
用法:
|
||||
```conf
|
||||
COMMAND_SEP=["."]
|
||||
```
|
||||
"""
|
||||
session_expire_timeout: timedelta = timedelta(minutes=2)
|
||||
"""
|
||||
等待用户回复的超时时间。
|
||||
"""等待用户回复的超时时间。
|
||||
|
||||
用法:
|
||||
```conf
|
||||
@ -226,3 +232,9 @@ class Config(BaseConfig):
|
||||
class Config:
|
||||
extra = "allow"
|
||||
env_file = ".env.prod"
|
||||
|
||||
|
||||
__autodoc__ = {
|
||||
"CustomEnvSettings": False,
|
||||
"BaseConfig": False,
|
||||
}
|
||||
|
@ -1,20 +1,42 @@
|
||||
"""本模块包含了 NoneBot 事件处理过程中使用到的常量。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 9
|
||||
description: nonebot.consts 模块
|
||||
"""
|
||||
from typing_extensions import Literal
|
||||
|
||||
# used by Matcher
|
||||
RECEIVE_KEY = "_receive_{id}"
|
||||
LAST_RECEIVE_KEY = "_last_receive"
|
||||
ARG_KEY = "{key}"
|
||||
REJECT_TARGET = "_current_target"
|
||||
REJECT_CACHE_TARGET = "_next_target"
|
||||
RECEIVE_KEY: Literal["_receive_{id}"] = "_receive_{id}"
|
||||
"""`receive` 存储 key"""
|
||||
LAST_RECEIVE_KEY: Literal["_last_receive"] = "_last_receive"
|
||||
"""`last_receive` 存储 key"""
|
||||
ARG_KEY: Literal["{key}"] = "{key}"
|
||||
"""`arg` 存储 key"""
|
||||
REJECT_TARGET: Literal["_current_target"] = "_current_target"
|
||||
"""当前 `reject` 目标存储 key"""
|
||||
REJECT_CACHE_TARGET: Literal["_next_target"] = "_next_target"
|
||||
"""下一个 `reject` 目标存储 key"""
|
||||
|
||||
# used by Rule
|
||||
PREFIX_KEY = "_prefix"
|
||||
PREFIX_KEY: Literal["_prefix"] = "_prefix"
|
||||
"""命令前缀存储 key"""
|
||||
|
||||
CMD_KEY = "command"
|
||||
RAW_CMD_KEY = "raw_command"
|
||||
CMD_ARG_KEY = "command_arg"
|
||||
CMD_KEY: Literal["command"] = "command"
|
||||
"""命令元组存储 key"""
|
||||
RAW_CMD_KEY: Literal["raw_command"] = "raw_command"
|
||||
"""命令文本存储 key"""
|
||||
CMD_ARG_KEY: Literal["command_arg"] = "command_arg"
|
||||
"""命令参数存储 key"""
|
||||
|
||||
SHELL_ARGS = "_args"
|
||||
SHELL_ARGV = "_argv"
|
||||
SHELL_ARGS: Literal["_args"] = "_args"
|
||||
"""shell 命令 parse 后参数字典存储 key"""
|
||||
SHELL_ARGV: Literal["_argv"] = "_argv"
|
||||
"""shell 命令原始参数列表存储 key"""
|
||||
|
||||
REGEX_MATCHED = "_matched"
|
||||
REGEX_GROUP = "_matched_groups"
|
||||
REGEX_DICT = "_matched_dict"
|
||||
REGEX_MATCHED: Literal["_matched"] = "_matched"
|
||||
"""正则匹配结果存储 key"""
|
||||
REGEX_GROUP: Literal["_matched_groups"] = "_matched_groups"
|
||||
"""正则匹配 group 元组存储 key"""
|
||||
REGEX_DICT: Literal["_matched_dict"] = "_matched_dict"
|
||||
"""正则匹配 group 字典存储 key"""
|
||||
|
@ -1,7 +1,8 @@
|
||||
"""
|
||||
## 依赖注入处理模块
|
||||
"""本模块模块实现了依赖注入的定义与处理。
|
||||
|
||||
该模块实现了依赖注入的定义与处理。
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot.dependencies 模块
|
||||
"""
|
||||
|
||||
import abc
|
||||
@ -23,6 +24,11 @@ R = TypeVar("R")
|
||||
|
||||
|
||||
class Param(abc.ABC, FieldInfo):
|
||||
"""依赖注入的基本单元 —— 参数。
|
||||
|
||||
继承自 `pydantic.fields.FieldInfo`,用于描述参数信息(不包括参数名)。
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: "Dependent", name: str, param: inspect.Parameter
|
||||
@ -45,6 +51,16 @@ class CustomConfig(BaseConfig):
|
||||
|
||||
|
||||
class Dependent(Generic[R]):
|
||||
"""依赖注入容器
|
||||
|
||||
参数:
|
||||
call: 依赖注入的可调用对象,可以是任何 Callable 对象
|
||||
pre_checkers: 依赖注入解析前的参数检查
|
||||
params: 具名参数列表
|
||||
parameterless: 匿名参数列表
|
||||
allow_types: 允许的参数类型
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@ -192,3 +208,6 @@ class Dependent(Generic[R]):
|
||||
values[field.name] = value
|
||||
|
||||
return values
|
||||
|
||||
|
||||
__autodoc__ = {"CustomConfig": False}
|
||||
|
@ -1,3 +1,8 @@
|
||||
"""
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.dependencies.utils 模块
|
||||
"""
|
||||
import inspect
|
||||
from typing import Any, Dict, Callable
|
||||
|
||||
@ -6,6 +11,7 @@ from pydantic.typing import ForwardRef, evaluate_forwardref
|
||||
|
||||
|
||||
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
|
||||
"""获取可调用对象签名"""
|
||||
signature = inspect.signature(call)
|
||||
globalns = getattr(call, "__globals__", {})
|
||||
typed_params = [
|
||||
@ -22,6 +28,7 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
|
||||
|
||||
|
||||
def get_typed_annotation(param: inspect.Parameter, globalns: Dict[str, Any]) -> Any:
|
||||
"""获取参数的类型注解"""
|
||||
annotation = param.annotation
|
||||
if isinstance(annotation, str):
|
||||
annotation = ForwardRef(annotation)
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""
|
||||
## 后端驱动适配基类
|
||||
"""本模块定义了驱动适配器基类。
|
||||
|
||||
各驱动请继承以下基类
|
||||
各驱动请继承以下基类。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot.drivers 模块
|
||||
"""
|
||||
|
||||
import abc
|
||||
@ -35,57 +38,38 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class Driver(abc.ABC):
|
||||
"""
|
||||
Driver 基类。
|
||||
"""Driver 基类。
|
||||
|
||||
参数:
|
||||
env: 包含环境信息的 Env 对象
|
||||
config: 包含配置信息的 Config 对象
|
||||
"""
|
||||
|
||||
_adapters: Dict[str, "Adapter"] = {}
|
||||
"""
|
||||
已注册的适配器列表
|
||||
"""
|
||||
"""已注册的适配器列表"""
|
||||
_bot_connection_hook: Set[T_BotConnectionHook] = set()
|
||||
"""
|
||||
Bot 连接建立时执行的函数
|
||||
"""
|
||||
"""Bot 连接建立时执行的函数"""
|
||||
_bot_disconnection_hook: Set[T_BotDisconnectionHook] = set()
|
||||
"""
|
||||
Bot 连接断开时执行的函数
|
||||
"""
|
||||
"""Bot 连接断开时执行的函数"""
|
||||
|
||||
def __init__(self, env: Env, config: Config):
|
||||
"""
|
||||
参数:
|
||||
env: 包含环境信息的 Env 对象
|
||||
config: 包含配置信息的 Config 对象
|
||||
"""
|
||||
self.env: str = env.environment
|
||||
"""
|
||||
环境名称
|
||||
"""
|
||||
"""环境名称"""
|
||||
self.config: Config = config
|
||||
"""
|
||||
配置对象
|
||||
"""
|
||||
"""全局配置对象"""
|
||||
self._clients: Dict[str, "Bot"] = {}
|
||||
"""
|
||||
已连接的 Bot
|
||||
"""
|
||||
|
||||
@property
|
||||
def bots(self) -> Dict[str, "Bot"]:
|
||||
"""
|
||||
获取当前所有已连接的 Bot
|
||||
"""
|
||||
"""获取当前所有已连接的 Bot"""
|
||||
return self._clients
|
||||
|
||||
def register_adapter(self, adapter: Type["Adapter"], **kwargs) -> None:
|
||||
"""
|
||||
注册一个协议适配器
|
||||
"""注册一个协议适配器
|
||||
|
||||
参数:
|
||||
name: 适配器名称,用于在连接时进行识别
|
||||
adapter: 适配器 Class
|
||||
**kwargs: 其他传递给适配器的参数
|
||||
adapter: 适配器类
|
||||
kwargs: 其他传递给适配器的参数
|
||||
"""
|
||||
name = adapter.get_name()
|
||||
if name in self._adapters:
|
||||
@ -121,36 +105,36 @@ class Driver(abc.ABC):
|
||||
|
||||
@abc.abstractmethod
|
||||
def on_startup(self, func: Callable) -> Callable:
|
||||
"""注册一个在驱动启动时运行的函数"""
|
||||
"""注册一个在驱动器启动时执行的函数"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def on_shutdown(self, func: Callable) -> Callable:
|
||||
"""注册一个在驱动停止时运行的函数"""
|
||||
"""注册一个在驱动器停止时执行的函数"""
|
||||
raise NotImplementedError
|
||||
|
||||
def on_bot_connect(self, func: T_BotConnectionHook) -> T_BotConnectionHook:
|
||||
"""
|
||||
装饰一个函数使他在 bot 通过 WebSocket 连接成功时执行。
|
||||
"""装饰一个函数使他在 bot 连接成功时执行。
|
||||
|
||||
参数:
|
||||
bot: 当前连接上的 Bot 对象
|
||||
钩子函数参数:
|
||||
|
||||
- bot: 当前连接上的 Bot 对象
|
||||
"""
|
||||
self._bot_connection_hook.add(func)
|
||||
return func
|
||||
|
||||
def on_bot_disconnect(self, func: T_BotDisconnectionHook) -> T_BotDisconnectionHook:
|
||||
"""
|
||||
装饰一个函数使他在 bot 通过 WebSocket 连接断开时执行。
|
||||
"""装饰一个函数使他在 bot 连接断开时执行。
|
||||
|
||||
参数:
|
||||
bot: 当前连接上的 Bot 对象
|
||||
钩子函数参数:
|
||||
|
||||
- bot: 当前连接上的 Bot 对象
|
||||
"""
|
||||
self._bot_disconnection_hook.add(func)
|
||||
return func
|
||||
|
||||
def _bot_connect(self, bot: "Bot") -> None:
|
||||
"""在 WebSocket 连接成功后,调用该函数来注册 bot 对象"""
|
||||
"""在连接成功后,调用该函数来注册 bot 对象"""
|
||||
if bot.self_id in self._clients:
|
||||
raise RuntimeError(f"Duplicate bot connection with id {bot.self_id}")
|
||||
self._clients[bot.self_id] = bot
|
||||
@ -169,7 +153,7 @@ class Driver(abc.ABC):
|
||||
asyncio.create_task(_run_hook(bot))
|
||||
|
||||
def _bot_disconnect(self, bot: "Bot") -> None:
|
||||
"""在 WebSocket 连接断开后,调用该函数来注销 bot 对象"""
|
||||
"""在连接断开后,调用该函数来注销 bot 对象"""
|
||||
if bot.self_id in self._clients:
|
||||
del self._clients[bot.self_id]
|
||||
|
||||
@ -188,32 +172,33 @@ class Driver(abc.ABC):
|
||||
|
||||
|
||||
class ForwardMixin(abc.ABC):
|
||||
"""客户端混入基类。"""
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def type(self) -> str:
|
||||
"""客户端驱动类型名称"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
async def request(self, setup: Request) -> Response:
|
||||
"""发送一个 HTTP 请求"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
@asynccontextmanager
|
||||
async def websocket(self, setup: Request) -> AsyncGenerator[WebSocket, None]:
|
||||
"""发起一个 WebSocket 连接"""
|
||||
raise NotImplementedError
|
||||
yield # used for static type checking's generator detection
|
||||
|
||||
|
||||
class ForwardDriver(Driver, ForwardMixin):
|
||||
"""
|
||||
Forward Driver 基类。将客户端框架封装,以满足适配器使用。
|
||||
"""
|
||||
"""客户端基类。将客户端框架封装,以满足适配器使用。"""
|
||||
|
||||
|
||||
class ReverseDriver(Driver):
|
||||
"""
|
||||
Reverse Driver 基类。将后端框架封装,以满足适配器使用。
|
||||
"""
|
||||
"""服务端基类。将后端框架封装,以满足适配器使用。"""
|
||||
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
@ -229,20 +214,26 @@ class ReverseDriver(Driver):
|
||||
|
||||
@abc.abstractmethod
|
||||
def setup_http_server(self, setup: "HTTPServerSetup") -> None:
|
||||
"""设置一个 HTTP 服务器路由配置"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def setup_websocket_server(self, setup: "WebSocketServerSetup") -> None:
|
||||
"""设置一个 WebSocket 服务器路由配置"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def combine_driver(driver: Type[Driver], *mixins: Type[ForwardMixin]) -> Type[Driver]:
|
||||
"""将一个驱动器和多个混入类合并。"""
|
||||
# check first
|
||||
assert issubclass(driver, Driver), "`driver` must be subclass of Driver"
|
||||
assert all(
|
||||
map(lambda m: issubclass(m, ForwardMixin), mixins)
|
||||
), "`mixins` must be subclass of ForwardMixin"
|
||||
|
||||
if not mixins:
|
||||
return driver
|
||||
|
||||
class CombinedDriver(*mixins, driver, ForwardDriver): # type: ignore
|
||||
@property
|
||||
def type(self) -> str:
|
||||
@ -257,6 +248,8 @@ def combine_driver(driver: Type[Driver], *mixins: Type[ForwardMixin]) -> Type[Dr
|
||||
|
||||
@dataclass
|
||||
class HTTPServerSetup:
|
||||
"""HTTP 服务器路由配置。"""
|
||||
|
||||
path: URL # path should not be absolute, check it by URL.is_absolute() == False
|
||||
method: str
|
||||
name: str
|
||||
@ -265,6 +258,8 @@ class HTTPServerSetup:
|
||||
|
||||
@dataclass
|
||||
class WebSocketServerSetup:
|
||||
"""WebSocket 服务器路由配置。"""
|
||||
|
||||
path: URL # path should not be absolute, check it by URL.is_absolute() == False
|
||||
name: str
|
||||
handle_func: Callable[[WebSocket], Awaitable[Any]]
|
||||
|
@ -1,10 +1,21 @@
|
||||
"""
|
||||
## AIOHTTP 驱动适配
|
||||
"""[AIOHTTP](https://aiohttp.readthedocs.io/en/stable/) 驱动适配器。
|
||||
|
||||
```bash
|
||||
nb driver install aiohttp
|
||||
# 或者
|
||||
pip install nonebot2[aiohttp]
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
本驱动仅支持客户端连接
|
||||
:::
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 2
|
||||
description: nonebot.drivers.aiohttp 模块
|
||||
"""
|
||||
|
||||
from typing import AsyncGenerator
|
||||
from typing import Type, AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from nonebot.typing import overrides
|
||||
@ -12,7 +23,12 @@ from nonebot.drivers import Request, Response
|
||||
from nonebot.exception import WebSocketClosed
|
||||
from nonebot.drivers._block_driver import BlockDriver
|
||||
from nonebot.drivers import WebSocket as BaseWebSocket
|
||||
from nonebot.drivers import HTTPVersion, ForwardMixin, combine_driver
|
||||
from nonebot.drivers import (
|
||||
HTTPVersion,
|
||||
ForwardMixin,
|
||||
ForwardDriver,
|
||||
combine_driver,
|
||||
)
|
||||
|
||||
try:
|
||||
import aiohttp
|
||||
@ -23,6 +39,8 @@ except ImportError:
|
||||
|
||||
|
||||
class Mixin(ForwardMixin):
|
||||
"""AIOHTTP Mixin"""
|
||||
|
||||
@property
|
||||
@overrides(ForwardMixin)
|
||||
def type(self) -> str:
|
||||
@ -84,6 +102,8 @@ class Mixin(ForwardMixin):
|
||||
|
||||
|
||||
class WebSocket(BaseWebSocket):
|
||||
"""AIOHTTP Websocket Wrapper"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
@ -138,4 +158,5 @@ class WebSocket(BaseWebSocket):
|
||||
await self.websocket.send_bytes(data)
|
||||
|
||||
|
||||
Driver = combine_driver(BlockDriver, Mixin)
|
||||
Driver: Type[ForwardDriver] = combine_driver(BlockDriver, Mixin) # type: ignore
|
||||
"""AIOHTTP Driver"""
|
||||
|
@ -1,9 +1,12 @@
|
||||
"""
|
||||
## FastAPI 驱动适配
|
||||
"""[FastAPI](https://fastapi.tiangolo.com/) 驱动适配
|
||||
|
||||
本驱动同时支持服务端以及客户端连接
|
||||
:::tip 提示
|
||||
本驱动仅支持服务端连接
|
||||
:::
|
||||
|
||||
后端使用方法请参考: [`FastAPI 文档`](https://fastapi.tiangolo.com/)
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.drivers.fastapi 模块
|
||||
"""
|
||||
|
||||
import logging
|
||||
@ -39,53 +42,33 @@ def catch_closed(func):
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
"""
|
||||
FastAPI 驱动框架设置,详情参考 FastAPI 文档
|
||||
"""
|
||||
"""FastAPI 驱动框架设置,详情参考 FastAPI 文档"""
|
||||
|
||||
fastapi_openapi_url: Optional[str] = None
|
||||
"""
|
||||
`openapi.json` 地址,默认为 `None` 即关闭
|
||||
"""
|
||||
"""`openapi.json` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_docs_url: Optional[str] = None
|
||||
"""
|
||||
`swagger` 地址,默认为 `None` 即关闭
|
||||
"""
|
||||
"""`swagger` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_redoc_url: Optional[str] = None
|
||||
"""
|
||||
`redoc` 地址,默认为 `None` 即关闭
|
||||
"""
|
||||
"""`redoc` 地址,默认为 `None` 即关闭"""
|
||||
fastapi_include_adapter_schema: bool = True
|
||||
"""
|
||||
是否包含适配器路由的 schema,默认为 `True`
|
||||
"""
|
||||
"""是否包含适配器路由的 schema,默认为 `True`"""
|
||||
fastapi_reload: bool = False
|
||||
"""
|
||||
开启/关闭冷重载
|
||||
"""
|
||||
"""开启/关闭冷重载"""
|
||||
fastapi_reload_dirs: Optional[List[str]] = None
|
||||
"""
|
||||
重载监控文件夹列表,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""重载监控文件夹列表,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_delay: Optional[float] = None
|
||||
"""
|
||||
重载延迟,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""重载延迟,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_includes: Optional[List[str]] = None
|
||||
"""
|
||||
要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
fastapi_reload_excludes: Optional[List[str]] = None
|
||||
"""
|
||||
不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
||||
|
||||
|
||||
class Driver(ReverseDriver):
|
||||
"""FastAPI 驱动框架。包含反向 Server 功能。"""
|
||||
"""FastAPI 驱动框架。"""
|
||||
|
||||
def __init__(self, env: Env, config: NoneBotConfig):
|
||||
super(Driver, self).__init__(env, config)
|
||||
@ -254,6 +237,8 @@ class Driver(ReverseDriver):
|
||||
|
||||
|
||||
class FastAPIWebSocket(BaseWebSocket):
|
||||
"""FastAPI WebSocket Wrapper"""
|
||||
|
||||
@overrides(BaseWebSocket)
|
||||
def __init__(self, *, request: BaseRequest, websocket: WebSocket):
|
||||
super().__init__(request=request)
|
||||
@ -294,3 +279,6 @@ class FastAPIWebSocket(BaseWebSocket):
|
||||
@overrides(BaseWebSocket)
|
||||
async def send_bytes(self, data: bytes) -> None:
|
||||
await self.websocket.send({"type": "websocket.send", "bytes": data})
|
||||
|
||||
|
||||
__autodoc__ = {"catch_closed": False}
|
||||
|
@ -1,4 +1,20 @@
|
||||
from typing import AsyncGenerator
|
||||
"""[HTTPX](https://www.python-httpx.org/) 驱动适配
|
||||
|
||||
```bash
|
||||
nb driver install httpx
|
||||
# 或者
|
||||
pip install nonebot2[httpx]
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
本驱动仅支持客户端 HTTP 连接
|
||||
:::
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 3
|
||||
description: nonebot.drivers.httpx 模块
|
||||
"""
|
||||
from typing import Type, AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from nonebot.typing import overrides
|
||||
@ -9,6 +25,7 @@ from nonebot.drivers import (
|
||||
WebSocket,
|
||||
HTTPVersion,
|
||||
ForwardMixin,
|
||||
ForwardDriver,
|
||||
combine_driver,
|
||||
)
|
||||
|
||||
@ -21,6 +38,8 @@ except ImportError:
|
||||
|
||||
|
||||
class Mixin(ForwardMixin):
|
||||
"""HTTPX Mixin"""
|
||||
|
||||
@property
|
||||
@overrides(ForwardMixin)
|
||||
def type(self) -> str:
|
||||
@ -57,4 +76,5 @@ class Mixin(ForwardMixin):
|
||||
yield ws
|
||||
|
||||
|
||||
Driver = combine_driver(BlockDriver, Mixin)
|
||||
Driver: Type[ForwardDriver] = combine_driver(BlockDriver, Mixin) # type: ignore
|
||||
"""HTTPX Driver"""
|
||||
|
@ -1,7 +1,18 @@
|
||||
"""
|
||||
## Quart 驱动适配
|
||||
"""[Quart](https://pgjones.gitlab.io/quart/index.html) 驱动适配
|
||||
|
||||
后端使用方法请参考: [`Quart 文档`](https://pgjones.gitlab.io/quart/index.html)
|
||||
```bash
|
||||
nb driver install quart
|
||||
# 或者
|
||||
pip install nonebot2[quart]
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
本驱动仅支持服务端连接
|
||||
:::
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 5
|
||||
description: nonebot.drivers.quart 模块
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@ -47,39 +58,25 @@ def catch_closed(func):
|
||||
|
||||
|
||||
class Config(BaseSettings):
|
||||
"""
|
||||
Quart 驱动框架设置
|
||||
"""
|
||||
"""Quart 驱动框架设置"""
|
||||
|
||||
quart_reload: bool = False
|
||||
"""
|
||||
开启/关闭冷重载
|
||||
"""
|
||||
"""开启/关闭冷重载"""
|
||||
quart_reload_dirs: Optional[List[str]] = None
|
||||
"""
|
||||
重载监控文件夹列表,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""重载监控文件夹列表,默认为 uvicorn 默认值"""
|
||||
quart_reload_delay: Optional[float] = None
|
||||
"""
|
||||
重载延迟,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""重载延迟,默认为 uvicorn 默认值"""
|
||||
quart_reload_includes: Optional[List[str]] = None
|
||||
"""
|
||||
要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
quart_reload_excludes: Optional[List[str]] = None
|
||||
"""
|
||||
不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值
|
||||
"""
|
||||
"""不要监听的文件列表,支持 glob pattern,默认为 uvicorn 默认值"""
|
||||
|
||||
class Config:
|
||||
extra = "ignore"
|
||||
|
||||
|
||||
class Driver(ReverseDriver):
|
||||
"""
|
||||
Quart 驱动框架
|
||||
"""
|
||||
"""Quart 驱动框架"""
|
||||
|
||||
def __init__(self, env: Env, config: NoneBotConfig):
|
||||
super().__init__(env, config)
|
||||
@ -239,6 +236,8 @@ class Driver(ReverseDriver):
|
||||
|
||||
|
||||
class WebSocket(BaseWebSocket):
|
||||
"""Quart WebSocket Wrapper"""
|
||||
|
||||
def __init__(self, *, request: BaseRequest, websocket: QuartWebSocket):
|
||||
super().__init__(request=request)
|
||||
self.websocket = websocket
|
||||
@ -280,3 +279,6 @@ class WebSocket(BaseWebSocket):
|
||||
@overrides(BaseWebSocket)
|
||||
async def send_bytes(self, data: bytes):
|
||||
await self.websocket.send(data)
|
||||
|
||||
|
||||
__autodoc__ = {"catch_closed": False}
|
||||
|
@ -1,6 +1,22 @@
|
||||
"""[websockets](https://websockets.readthedocs.io/) 驱动适配
|
||||
|
||||
```bash
|
||||
nb driver install websockets
|
||||
# 或者
|
||||
pip install nonebot2[websockets]
|
||||
```
|
||||
|
||||
:::tip 提示
|
||||
本驱动仅支持客户端 WebSocket 连接
|
||||
:::
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 4
|
||||
description: nonebot.drivers.websockets 模块
|
||||
"""
|
||||
import logging
|
||||
from functools import wraps
|
||||
from typing import AsyncGenerator
|
||||
from typing import Type, AsyncGenerator
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from nonebot.typing import overrides
|
||||
@ -9,7 +25,7 @@ from nonebot.drivers import Request, Response
|
||||
from nonebot.exception import WebSocketClosed
|
||||
from nonebot.drivers._block_driver import BlockDriver
|
||||
from nonebot.drivers import WebSocket as BaseWebSocket
|
||||
from nonebot.drivers import ForwardMixin, combine_driver
|
||||
from nonebot.drivers import ForwardMixin, ForwardDriver, combine_driver
|
||||
|
||||
try:
|
||||
from websockets.exceptions import ConnectionClosed
|
||||
@ -38,6 +54,8 @@ def catch_closed(func):
|
||||
|
||||
|
||||
class Mixin(ForwardMixin):
|
||||
"""Websockets Mixin"""
|
||||
|
||||
@property
|
||||
@overrides(ForwardMixin)
|
||||
def type(self) -> str:
|
||||
@ -60,6 +78,8 @@ class Mixin(ForwardMixin):
|
||||
|
||||
|
||||
class WebSocket(BaseWebSocket):
|
||||
"""Websockets WebSocket Wrapper"""
|
||||
|
||||
@overrides(BaseWebSocket)
|
||||
def __init__(self, *, request: Request, websocket: WebSocketClientProtocol):
|
||||
super().__init__(request=request)
|
||||
@ -103,4 +123,5 @@ class WebSocket(BaseWebSocket):
|
||||
await self.websocket.send(data)
|
||||
|
||||
|
||||
Driver = combine_driver(BlockDriver, Mixin)
|
||||
Driver: Type[ForwardDriver] = combine_driver(BlockDriver, Mixin) # type: ignore
|
||||
"""Websockets Driver"""
|
||||
|
@ -1,8 +1,32 @@
|
||||
"""
|
||||
## 异常
|
||||
"""本模块包含了所有 NoneBot 运行时可能会抛出的异常。
|
||||
|
||||
下列文档中的异常是所有 NoneBot 运行时可能会抛出的。
|
||||
这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。
|
||||
|
||||
```bash
|
||||
NoneBotException
|
||||
├── ParserExit
|
||||
├── ProcessException
|
||||
| ├── IgnoredException
|
||||
| ├── MockApiException
|
||||
| └── StopPropagation
|
||||
├── MatcherException
|
||||
| ├── SkippedException
|
||||
| | └── TypeMisMatch
|
||||
| ├── PausedException
|
||||
| ├── RejectedException
|
||||
| └── FinishedException
|
||||
├── AdapterException
|
||||
| ├── NoLogException
|
||||
| ├── ApiNotAvailable
|
||||
| ├── NetworkError
|
||||
| └── ActionFailed
|
||||
└── DriverException
|
||||
└── WebSocketClosed
|
||||
```
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 10
|
||||
description: nonebot.exception 模块
|
||||
"""
|
||||
|
||||
from typing import Any, Optional
|
||||
@ -11,16 +35,12 @@ from pydantic.fields import ModelField
|
||||
|
||||
|
||||
class NoneBotException(Exception):
|
||||
"""
|
||||
所有 NoneBot 发生的异常基类。
|
||||
"""
|
||||
"""所有 NoneBot 发生的异常基类。"""
|
||||
|
||||
|
||||
# Rule Exception
|
||||
class ParserExit(NoneBotException):
|
||||
"""
|
||||
`shell command` 处理消息失败时返回的异常
|
||||
"""
|
||||
"""{ref}`nonebot.rule.shell_command` 处理消息失败时返回的异常"""
|
||||
|
||||
def __init__(self, status: int = 0, message: Optional[str] = None):
|
||||
self.status = status
|
||||
@ -35,21 +55,18 @@ class ParserExit(NoneBotException):
|
||||
|
||||
# Processor Exception
|
||||
class ProcessException(NoneBotException):
|
||||
"""
|
||||
事件处理过程中发生的异常基类。
|
||||
"""
|
||||
"""事件处理过程中发生的异常基类。"""
|
||||
|
||||
|
||||
class IgnoredException(ProcessException):
|
||||
"""
|
||||
指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。
|
||||
"""指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。
|
||||
|
||||
参数:
|
||||
reason: 忽略事件的原因
|
||||
"""
|
||||
|
||||
def __init__(self, reason):
|
||||
self.reason = reason
|
||||
def __init__(self, reason: Any):
|
||||
self.reason: Any = reason
|
||||
|
||||
def __repr__(self):
|
||||
return f"<IgnoredException, reason={self.reason}>"
|
||||
@ -59,8 +76,7 @@ class IgnoredException(ProcessException):
|
||||
|
||||
|
||||
class MockApiException(ProcessException):
|
||||
"""
|
||||
指示 NoneBot 阻止本次 API 调用或修改本次调用返回值,并返回自定义内容。可由 api hook 抛出。
|
||||
"""指示 NoneBot 阻止本次 API 调用或修改本次调用返回值,并返回自定义内容。可由 api hook 抛出。
|
||||
|
||||
参数:
|
||||
result: 返回的内容
|
||||
@ -77,34 +93,46 @@ class MockApiException(ProcessException):
|
||||
|
||||
|
||||
class StopPropagation(ProcessException):
|
||||
"""
|
||||
指示 NoneBot 终止事件向下层传播。
|
||||
"""指示 NoneBot 终止事件向下层传播。
|
||||
|
||||
在 {ref}`nonebot.matcher.Matcher.block` 为 `True`
|
||||
或使用 {ref}`nonebot.matcher.Matcher.stop_propagation` 方法时抛出。
|
||||
|
||||
用法:
|
||||
在 `Matcher.block == True` 时抛出。
|
||||
```python
|
||||
matcher = on_notice(block=True)
|
||||
# 或者
|
||||
@matcher.handle()
|
||||
async def handler(matcher: Matcher):
|
||||
matcher.stop_propagation()
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
# Matcher Exceptions
|
||||
class MatcherException(NoneBotException):
|
||||
"""
|
||||
所有 Matcher 发生的异常基类。
|
||||
"""
|
||||
"""所有 Matcher 发生的异常基类。"""
|
||||
|
||||
|
||||
class SkippedException(MatcherException):
|
||||
"""
|
||||
指示 NoneBot 立即结束当前 `Handler` 的处理,继续处理下一个 `Handler`。
|
||||
"""指示 NoneBot 立即结束当前 `Handler` 的处理,继续处理下一个 `Handler`。
|
||||
|
||||
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.skip` 抛出。
|
||||
|
||||
用法:
|
||||
可以在 `Handler` 中通过 `Matcher.skip()` 抛出。
|
||||
```python
|
||||
def always_skip():
|
||||
Matcher.skip()
|
||||
|
||||
@matcher.handle()
|
||||
async def handler(dependency = Depends(always_skip)):
|
||||
...
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
class TypeMisMatch(SkippedException):
|
||||
"""
|
||||
当前 `Handler` 的参数类型不匹配。
|
||||
"""
|
||||
"""当前 `Handler` 的参数类型不匹配。"""
|
||||
|
||||
def __init__(self, param: ModelField, value: Any):
|
||||
self.param: ModelField = param
|
||||
@ -118,91 +146,85 @@ class TypeMisMatch(SkippedException):
|
||||
|
||||
|
||||
class PausedException(MatcherException):
|
||||
"""
|
||||
指示 NoneBot 结束当前 `Handler` 并等待下一条消息后继续下一个 `Handler`。
|
||||
可用于用户输入新信息。
|
||||
"""指示 NoneBot 结束当前 `Handler` 并等待下一条消息后继续下一个 `Handler`。可用于用户输入新信息。
|
||||
|
||||
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.pause` 抛出。
|
||||
|
||||
用法:
|
||||
可以在 `Handler` 中通过 `Matcher.pause()` 抛出。
|
||||
```python
|
||||
@matcher.handle()
|
||||
async def handler():
|
||||
await matcher.pause("some message")
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
class RejectedException(MatcherException):
|
||||
"""
|
||||
指示 NoneBot 结束当前 `Handler` 并等待下一条消息后重新运行当前 `Handler`。
|
||||
可用于用户重新输入。
|
||||
"""指示 NoneBot 结束当前 `Handler` 并等待下一条消息后重新运行当前 `Handler`。可用于用户重新输入。
|
||||
|
||||
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.reject` 抛出。
|
||||
|
||||
用法:
|
||||
可以在 `Handler` 中通过 `Matcher.reject()` 抛出。
|
||||
```python
|
||||
@matcher.handle()
|
||||
async def handler():
|
||||
await matcher.reject("some message")
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
class FinishedException(MatcherException):
|
||||
"""
|
||||
指示 NoneBot 结束当前 `Handler` 且后续 `Handler` 不再被运行。
|
||||
可用于结束用户会话。
|
||||
"""指示 NoneBot 结束当前 `Handler` 且后续 `Handler` 不再被运行。可用于结束用户会话。
|
||||
|
||||
可以在 `Handler` 中通过 {ref}`nonebot.matcher.Matcher.finish` 抛出。
|
||||
|
||||
用法:
|
||||
可以在 `Handler` 中通过 `Matcher.finish()` 抛出。
|
||||
```python
|
||||
@matcher.handle()
|
||||
async def handler():
|
||||
await matcher.finish("some message")
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
# Adapter Exceptions
|
||||
class AdapterException(NoneBotException):
|
||||
"""
|
||||
代表 `Adapter` 抛出的异常,所有的 `Adapter` 都要在内部继承自这个 `Exception`
|
||||
"""代表 `Adapter` 抛出的异常,所有的 `Adapter` 都要在内部继承自这个 `Exception`
|
||||
|
||||
参数:
|
||||
adapter_name: 标识 adapter
|
||||
"""
|
||||
|
||||
def __init__(self, adapter_name: str) -> None:
|
||||
self.adapter_name = adapter_name
|
||||
self.adapter_name: str = adapter_name
|
||||
|
||||
|
||||
class NoLogException(AdapterException):
|
||||
"""
|
||||
指示 NoneBot 对当前 `Event` 进行处理但不显示 Log 信息,可在 `get_log_string` 时抛出
|
||||
"""
|
||||
"""指示 NoneBot 对当前 `Event` 进行处理但不显示 Log 信息。
|
||||
|
||||
pass
|
||||
可在 {ref}`nonebot.adapters._event.Event.get_log_string` 时抛出
|
||||
"""
|
||||
|
||||
|
||||
class ApiNotAvailable(AdapterException):
|
||||
"""
|
||||
在 API 连接不可用时抛出。
|
||||
"""
|
||||
|
||||
pass
|
||||
"""在 API 连接不可用时抛出。"""
|
||||
|
||||
|
||||
class NetworkError(AdapterException):
|
||||
"""
|
||||
在网络出现问题时抛出,如: API 请求地址不正确, API 请求无返回或返回状态非正常等。
|
||||
"""
|
||||
|
||||
pass
|
||||
"""在网络出现问题时抛出,如: API 请求地址不正确, API 请求无返回或返回状态非正常等。"""
|
||||
|
||||
|
||||
class ActionFailed(AdapterException):
|
||||
"""
|
||||
API 请求成功返回数据,但 API 操作失败。
|
||||
"""
|
||||
|
||||
pass
|
||||
"""API 请求成功返回数据,但 API 操作失败。"""
|
||||
|
||||
|
||||
# Driver Exceptions
|
||||
class DriverException(NoneBotException):
|
||||
"""
|
||||
`Driver` 抛出的异常基类
|
||||
"""
|
||||
"""`Driver` 抛出的异常基类"""
|
||||
|
||||
|
||||
class WebSocketClosed(DriverException):
|
||||
"""
|
||||
WebSocket 连接已关闭
|
||||
"""
|
||||
"""WebSocket 连接已关闭"""
|
||||
|
||||
def __init__(self, code: int, reason: Optional[str] = None):
|
||||
self.code = code
|
||||
|
@ -1,11 +1,15 @@
|
||||
"""
|
||||
## 日志
|
||||
"""本模块定义了 NoneBot 的日志记录 Logger。
|
||||
|
||||
NoneBot 使用 [`loguru`][loguru] 来记录日志信息。
|
||||
|
||||
自定义 logger 请参考 [`loguru`][loguru] 文档。
|
||||
自定义 logger 请参考 [自定义日志](https://v2.nonebot.dev/docs/tutorial/custom-logger)
|
||||
以及 [`loguru`][loguru] 文档。
|
||||
|
||||
[loguru]: https://github.com/Delgan/loguru
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 7
|
||||
description: nonebot.log 模块
|
||||
"""
|
||||
|
||||
import sys
|
||||
@ -23,14 +27,13 @@ if TYPE_CHECKING:
|
||||
|
||||
# logger = logging.getLogger("nonebot")
|
||||
logger: "Logger" = loguru.logger
|
||||
"""
|
||||
NoneBot 日志记录器对象。
|
||||
"""NoneBot 日志记录器对象。
|
||||
|
||||
默认信息:
|
||||
|
||||
- 格式: `[%(asctime)s %(name)s] %(levelname)s: %(message)s`
|
||||
- 等级: `INFO` ,根据 `config.log_level` 配置改变
|
||||
- 输出: 输出至 stdout
|
||||
- 格式: `[%(asctime)s %(name)s] %(levelname)s: %(message)s`
|
||||
- 等级: `INFO` ,根据 `config.log_level` 配置改变
|
||||
- 输出: 输出至 stdout
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -80,14 +83,16 @@ class LoguruHandler(logging.Handler): # pragma: no cover
|
||||
|
||||
|
||||
logger.remove()
|
||||
default_filter = Filter()
|
||||
default_format = (
|
||||
default_filter: Filter = Filter()
|
||||
"""默认日志等级过滤器"""
|
||||
default_format: str = (
|
||||
"<g>{time:MM-DD HH:mm:ss}</g> "
|
||||
"[<lvl>{level}</lvl>] "
|
||||
"<c><u>{name}</u></c> | "
|
||||
# "<c>{function}:{line}</c>| "
|
||||
"{message}"
|
||||
)
|
||||
"""默认日志格式"""
|
||||
logger_id = logger.add(
|
||||
sys.stdout,
|
||||
level=0,
|
||||
@ -96,3 +101,5 @@ logger_id = logger.add(
|
||||
filter=default_filter,
|
||||
format=default_format,
|
||||
)
|
||||
|
||||
__autodoc__ = {"Filter": False, "LoguruHandler": False}
|
||||
|
@ -1,7 +1,8 @@
|
||||
"""
|
||||
## 事件响应器
|
||||
"""本模块实现事件响应器的创建与运行,并提供一些快捷方法来帮助用户更好的与机器人进行对话。
|
||||
|
||||
该模块实现事件响应器的创建与运行,并提供一些快捷方法来帮助用户更好的与机器人进行对话 。
|
||||
FrontMatter:
|
||||
sidebar_position: 3
|
||||
description: nonebot.matcher 模块
|
||||
"""
|
||||
|
||||
from types import ModuleType
|
||||
@ -64,9 +65,7 @@ if TYPE_CHECKING:
|
||||
T = TypeVar("T")
|
||||
|
||||
matchers: Dict[int, List[Type["Matcher"]]] = defaultdict(list)
|
||||
"""
|
||||
用于存储当前所有的事件响应器
|
||||
"""
|
||||
"""用于存储当前所有的事件响应器"""
|
||||
current_bot: ContextVar[Bot] = ContextVar("current_bot")
|
||||
current_event: ContextVar[Event] = ContextVar("current_event")
|
||||
current_matcher: ContextVar["Matcher"] = ContextVar("current_matcher")
|
||||
@ -103,68 +102,38 @@ class Matcher(metaclass=MatcherMeta):
|
||||
"""事件响应器类"""
|
||||
|
||||
plugin: Optional["Plugin"] = None
|
||||
"""
|
||||
事件响应器所在插件
|
||||
"""
|
||||
"""事件响应器所在插件"""
|
||||
module: Optional[ModuleType] = None
|
||||
"""
|
||||
事件响应器所在插件模块
|
||||
"""
|
||||
"""事件响应器所在插件模块"""
|
||||
plugin_name: Optional[str] = None
|
||||
"""
|
||||
事件响应器所在插件名
|
||||
"""
|
||||
"""事件响应器所在插件名"""
|
||||
module_name: Optional[str] = None
|
||||
"""
|
||||
事件响应器所在点分割插件模块路径
|
||||
"""
|
||||
"""事件响应器所在点分割插件模块路径"""
|
||||
|
||||
type: str = ""
|
||||
"""
|
||||
事件响应器类型
|
||||
"""
|
||||
"""事件响应器类型"""
|
||||
rule: Rule = Rule()
|
||||
"""
|
||||
事件响应器匹配规则
|
||||
"""
|
||||
"""事件响应器匹配规则"""
|
||||
permission: Permission = Permission()
|
||||
"""
|
||||
事件响应器触发权限
|
||||
"""
|
||||
"""事件响应器触发权限"""
|
||||
handlers: List[Dependent[Any]] = []
|
||||
"""
|
||||
事件响应器拥有的事件处理函数列表
|
||||
"""
|
||||
"""事件响应器拥有的事件处理函数列表"""
|
||||
priority: int = 1
|
||||
"""
|
||||
事件响应器优先级
|
||||
"""
|
||||
"""事件响应器优先级"""
|
||||
block: bool = False
|
||||
"""
|
||||
事件响应器是否阻止事件传播
|
||||
"""
|
||||
"""事件响应器是否阻止事件传播"""
|
||||
temp: bool = False
|
||||
"""
|
||||
事件响应器是否为临时
|
||||
"""
|
||||
"""事件响应器是否为临时"""
|
||||
expire_time: Optional[datetime] = None
|
||||
"""
|
||||
事件响应器过期时间点
|
||||
"""
|
||||
"""事件响应器过期时间点"""
|
||||
|
||||
_default_state: T_State = {}
|
||||
"""
|
||||
事件响应器默认状态
|
||||
"""
|
||||
"""事件响应器默认状态"""
|
||||
|
||||
_default_type_updater: Optional[Dependent[str]] = None
|
||||
"""
|
||||
事件响应器类型更新函数
|
||||
"""
|
||||
"""事件响应器类型更新函数"""
|
||||
_default_permission_updater: Optional[Dependent[Permission]] = None
|
||||
"""
|
||||
事件响应器权限更新函数
|
||||
"""
|
||||
"""事件响应器权限更新函数"""
|
||||
|
||||
HANDLER_PARAM_TYPES = [
|
||||
params.DependParam,
|
||||
@ -177,7 +146,6 @@ class Matcher(metaclass=MatcherMeta):
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
"""实例化 Matcher 以便运行"""
|
||||
self.handlers = self.handlers.copy()
|
||||
self.state = self._default_state.copy()
|
||||
|
||||
@ -272,15 +240,16 @@ class Matcher(metaclass=MatcherMeta):
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
检查是否满足触发权限
|
||||
"""检查是否满足触发权限
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
event: 上报事件
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
|
||||
返回:
|
||||
bool: 是否满足权限
|
||||
是否满足权限
|
||||
"""
|
||||
event_type = event.get_type()
|
||||
return event_type == (cls.type or event_type) and await cls.permission(
|
||||
@ -296,16 +265,17 @@ class Matcher(metaclass=MatcherMeta):
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
检查是否满足匹配规则
|
||||
"""检查是否满足匹配规则
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
event: 上报事件
|
||||
state: 当前状态
|
||||
stack: 异步上下文栈
|
||||
dependency_cache: 依赖缓存
|
||||
|
||||
返回:
|
||||
bool: 是否满足匹配规则
|
||||
是否满足匹配规则
|
||||
"""
|
||||
event_type = event.get_type()
|
||||
return event_type == (cls.type or event_type) and await cls.rule(
|
||||
@ -314,8 +284,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def type_updater(cls, func: T_TypeUpdater) -> T_TypeUpdater:
|
||||
"""
|
||||
装饰一个函数来更改当前事件响应器的默认响应事件类型更新函数
|
||||
"""装饰一个函数来更改当前事件响应器的默认响应事件类型更新函数
|
||||
|
||||
参数:
|
||||
func: 响应事件类型更新函数
|
||||
@ -327,8 +296,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def permission_updater(cls, func: T_PermissionUpdater) -> T_PermissionUpdater:
|
||||
"""
|
||||
装饰一个函数来更改当前事件响应器的默认会话权限更新函数
|
||||
"""装饰一个函数来更改当前事件响应器的默认会话权限更新函数
|
||||
|
||||
参数:
|
||||
func: 会话权限更新函数
|
||||
@ -354,8 +322,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
def handle(
|
||||
cls, parameterless: Optional[List[Any]] = None
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""
|
||||
装饰一个函数来向事件响应器直接添加一个处理函数
|
||||
"""装饰一个函数来向事件响应器直接添加一个处理函数
|
||||
|
||||
参数:
|
||||
parameterless: 非参数类型依赖列表
|
||||
@ -371,8 +338,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
def receive(
|
||||
cls, id: str = "", parameterless: Optional[List[Any]] = None
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""
|
||||
装饰一个函数来指示 NoneBot 在接收用户新的一条消息后继续运行该函数
|
||||
"""装饰一个函数来指示 NoneBot 在接收用户新的一条消息后继续运行该函数
|
||||
|
||||
参数:
|
||||
id: 消息 ID
|
||||
@ -410,8 +376,9 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
parameterless: Optional[List[Any]] = None,
|
||||
) -> Callable[[T_Handler], T_Handler]:
|
||||
"""
|
||||
装饰一个函数来指示 NoneBot 当要获取的 `key` 不存在时接收用户新的一条消息再运行该函数,如果 `key` 已存在则直接继续运行
|
||||
"""装饰一个函数来指示 NoneBot 获取一个参数 `key`
|
||||
|
||||
当要获取的 `key` 不存在时接收用户新的一条消息再运行该函数,如果 `key` 已存在则直接继续运行
|
||||
|
||||
参数:
|
||||
key: 参数名
|
||||
@ -452,12 +419,11 @@ class Matcher(metaclass=MatcherMeta):
|
||||
message: Union[str, Message, MessageSegment, MessageTemplate],
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""
|
||||
发送一条消息给当前交互用户
|
||||
"""发送一条消息给当前交互用户
|
||||
|
||||
参数:
|
||||
message: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
bot = current_bot.get()
|
||||
event = current_event.get()
|
||||
@ -474,12 +440,11 @@ class Matcher(metaclass=MatcherMeta):
|
||||
message: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
发送一条消息给当前交互用户并结束当前事件响应器
|
||||
"""发送一条消息给当前交互用户并结束当前事件响应器
|
||||
|
||||
参数:
|
||||
message: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
if message is not None:
|
||||
await cls.send(message, **kwargs)
|
||||
@ -491,12 +456,11 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续下一个处理函数
|
||||
"""发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续下一个处理函数
|
||||
|
||||
参数:
|
||||
prompt: 消息内容
|
||||
**kwargs`: bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
if prompt is not None:
|
||||
await cls.send(prompt, **kwargs)
|
||||
@ -508,12 +472,12 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
最近使用 `got` / `receive` 接收的消息不符合预期,发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
"""最近使用 `got` / `receive` 接收的消息不符合预期,
|
||||
发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
|
||||
参数:
|
||||
prompt: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
if prompt is not None:
|
||||
await cls.send(prompt, **kwargs)
|
||||
@ -526,13 +490,13 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
最近使用 `got` 接收的消息不符合预期,发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
"""最近使用 `got` 接收的消息不符合预期,
|
||||
发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
|
||||
参数:
|
||||
key: 参数名
|
||||
prompt: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
matcher = current_matcher.get()
|
||||
matcher.set_target(ARG_KEY.format(key=key))
|
||||
@ -547,13 +511,13 @@ class Matcher(metaclass=MatcherMeta):
|
||||
prompt: Optional[Union[str, Message, MessageSegment, MessageTemplate]] = None,
|
||||
**kwargs,
|
||||
) -> NoReturn:
|
||||
"""
|
||||
最近使用 `got` 接收的消息不符合预期,发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
"""最近使用 `got` 接收的消息不符合预期,
|
||||
发送一条消息给当前交互用户并暂停事件响应器,在接收用户新的一条消息后继续当前处理函数
|
||||
|
||||
参数:
|
||||
id: 消息 id
|
||||
prompt: 消息内容
|
||||
**kwargs: `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
kwargs: {ref}`nonebot.adapters._bot.Bot.send` 的参数,请参考对应 adapter 的 bot 对象 api
|
||||
"""
|
||||
matcher = current_matcher.get()
|
||||
matcher.set_target(RECEIVE_KEY.format(id=id))
|
||||
@ -563,22 +527,40 @@ class Matcher(metaclass=MatcherMeta):
|
||||
|
||||
@classmethod
|
||||
def skip(cls) -> NoReturn:
|
||||
"""跳过当前事件处理函数,继续下一个处理函数
|
||||
|
||||
通常在事件处理函数的依赖中使用。
|
||||
"""
|
||||
raise SkippedException
|
||||
|
||||
def get_receive(self, id: str, default: T = None) -> Union[Event, T]:
|
||||
"""获取一个 `receive` 事件
|
||||
|
||||
如果没有找到对应的事件,返回 `default` 值
|
||||
"""
|
||||
return self.state.get(RECEIVE_KEY.format(id=id), default)
|
||||
|
||||
def set_receive(self, id: str, event: Event) -> None:
|
||||
"""设置一个 `receive` 事件"""
|
||||
self.state[RECEIVE_KEY.format(id=id)] = event
|
||||
self.state[LAST_RECEIVE_KEY] = event
|
||||
|
||||
def get_last_receive(self, default: T = None) -> Union[Event, T]:
|
||||
"""获取最近一次 `receive` 事件
|
||||
|
||||
如果没有事件,返回 `default` 值
|
||||
"""
|
||||
return self.state.get(LAST_RECEIVE_KEY, default)
|
||||
|
||||
def get_arg(self, key: str, default: T = None) -> Union[Message, T]:
|
||||
"""获取一个 `got` 消息
|
||||
|
||||
如果没有找到对应的消息,返回 `default` 值
|
||||
"""
|
||||
return self.state.get(ARG_KEY.format(key=key), default)
|
||||
|
||||
def set_arg(self, key: str, message: Message) -> None:
|
||||
"""设置一个 `got` 消息"""
|
||||
self.state[ARG_KEY.format(key=key)] = message
|
||||
|
||||
def set_target(self, target: str, cache: bool = True) -> None:
|
||||
@ -591,9 +573,7 @@ class Matcher(metaclass=MatcherMeta):
|
||||
return self.state.get(REJECT_TARGET, default)
|
||||
|
||||
def stop_propagation(self):
|
||||
"""
|
||||
阻止事件传播
|
||||
"""
|
||||
"""阻止事件传播"""
|
||||
self.block = True
|
||||
|
||||
async def update_type(self, bot: Bot, event: Event) -> str:
|
||||
@ -714,3 +694,14 @@ class Matcher(metaclass=MatcherMeta):
|
||||
)
|
||||
except FinishedException:
|
||||
pass
|
||||
|
||||
|
||||
__autodoc__ = {
|
||||
"MatcherMeta": False,
|
||||
"Matcher.get_target": False,
|
||||
"Matcher.set_target": False,
|
||||
"Matcher.update_type": False,
|
||||
"Matcher.update_permission": False,
|
||||
"Matcher.resolve_reject": False,
|
||||
"Matcher.simple_run": False,
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""
|
||||
## 事件处理
|
||||
"""本模块定义了事件处理主要流程。
|
||||
|
||||
NoneBot 内部处理并按优先级分发事件给所有事件响应器,提供了多个插槽以进行事件的预处理等。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 2
|
||||
description: nonebot.message 模块
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@ -67,9 +70,7 @@ RUN_POSTPCS_PARAMS = [
|
||||
|
||||
|
||||
def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
|
||||
"""
|
||||
事件预处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之前执行。
|
||||
"""
|
||||
"""事件预处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之前执行。"""
|
||||
_event_preprocessors.add(
|
||||
Dependent[None].parse(call=func, allow_types=EVENT_PCS_PARAMS)
|
||||
)
|
||||
@ -77,9 +78,7 @@ def event_preprocessor(func: T_EventPreProcessor) -> T_EventPreProcessor:
|
||||
|
||||
|
||||
def event_postprocessor(func: T_EventPostProcessor) -> T_EventPostProcessor:
|
||||
"""
|
||||
事件后处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之后执行。
|
||||
"""
|
||||
"""事件后处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之后执行。"""
|
||||
_event_postprocessors.add(
|
||||
Dependent[None].parse(call=func, allow_types=EVENT_PCS_PARAMS)
|
||||
)
|
||||
@ -87,9 +86,7 @@ def event_postprocessor(func: T_EventPostProcessor) -> T_EventPostProcessor:
|
||||
|
||||
|
||||
def run_preprocessor(func: T_RunPreProcessor) -> T_RunPreProcessor:
|
||||
"""
|
||||
运行预处理。装饰一个函数,使它在每次事件响应器运行前执行。
|
||||
"""
|
||||
"""运行预处理。装饰一个函数,使它在每次事件响应器运行前执行。"""
|
||||
_run_preprocessors.add(
|
||||
Dependent[None].parse(call=func, allow_types=RUN_PREPCS_PARAMS)
|
||||
)
|
||||
@ -97,9 +94,7 @@ def run_preprocessor(func: T_RunPreProcessor) -> T_RunPreProcessor:
|
||||
|
||||
|
||||
def run_postprocessor(func: T_RunPostProcessor) -> T_RunPostProcessor:
|
||||
"""
|
||||
运行后处理。装饰一个函数,使它在每次事件响应器运行后执行。
|
||||
"""
|
||||
"""运行后处理。装饰一个函数,使它在每次事件响应器运行后执行。"""
|
||||
_run_postprocessors.add(
|
||||
Dependent[None].parse(call=func, allow_types=RUN_POSTPCS_PARAMS)
|
||||
)
|
||||
@ -232,8 +227,7 @@ async def _run_matcher(
|
||||
|
||||
|
||||
async def handle_event(bot: "Bot", event: "Event") -> None:
|
||||
"""
|
||||
处理一个事件。调用该函数以实现分发事件。
|
||||
"""处理一个事件。调用该函数以实现分发事件。
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
|
@ -1,3 +1,10 @@
|
||||
"""本模块定义了依赖注入的各类参数。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 4
|
||||
description: nonebot.params 模块
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import inspect
|
||||
import warnings
|
||||
@ -55,8 +62,7 @@ def Depends(
|
||||
*,
|
||||
use_cache: bool = True,
|
||||
) -> Any:
|
||||
"""
|
||||
参数依赖注入装饰器
|
||||
"""子依赖装饰器
|
||||
|
||||
参数:
|
||||
dependency: 依赖函数。默认为参数的类型注释。
|
||||
@ -81,6 +87,8 @@ def Depends(
|
||||
|
||||
|
||||
class DependParam(Param):
|
||||
"""子依赖参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls,
|
||||
@ -176,6 +184,8 @@ class _BotChecker(Param):
|
||||
|
||||
|
||||
class BotParam(Param):
|
||||
"""{ref}`nonebot.adapters._bot.Bot` 参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -217,6 +227,8 @@ class _EventChecker(Param):
|
||||
|
||||
|
||||
class EventParam(Param):
|
||||
"""{ref}`nonebot.adapters._event.Event` 参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -250,6 +262,7 @@ async def _event_type(event: Event) -> str:
|
||||
|
||||
|
||||
def EventType() -> str:
|
||||
"""{ref}`nonebot.adapters._event.Event` 类型参数"""
|
||||
return Depends(_event_type)
|
||||
|
||||
|
||||
@ -258,6 +271,7 @@ async def _event_message(event: Event) -> Message:
|
||||
|
||||
|
||||
def EventMessage() -> Any:
|
||||
"""{ref}`nonebot.adapters._event.Event` 消息参数"""
|
||||
return Depends(_event_message)
|
||||
|
||||
|
||||
@ -266,6 +280,7 @@ async def _event_plain_text(event: Event) -> str:
|
||||
|
||||
|
||||
def EventPlainText() -> str:
|
||||
"""{ref}`nonebot.adapters._event.Event` 纯文本消息参数"""
|
||||
return Depends(_event_plain_text)
|
||||
|
||||
|
||||
@ -274,6 +289,7 @@ async def _event_to_me(event: Event) -> bool:
|
||||
|
||||
|
||||
def EventToMe() -> bool:
|
||||
"""{ref}`nonebot.adapters._event.Event` `to_me` 参数"""
|
||||
return Depends(_event_to_me)
|
||||
|
||||
|
||||
@ -282,11 +298,14 @@ class StateInner(T_State):
|
||||
|
||||
|
||||
def State() -> T_State:
|
||||
warnings.warn("State() is deprecated, use T_State instead", DeprecationWarning)
|
||||
"""**Deprecated**: 事件处理状态参数,请直接使用 {ref}`nonebot.typing.T_State`"""
|
||||
warnings.warn("State() is deprecated, use `T_State` instead", DeprecationWarning)
|
||||
return StateInner()
|
||||
|
||||
|
||||
class StateParam(Param):
|
||||
"""事件处理状态参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -308,7 +327,8 @@ def _command(state: T_State) -> Message:
|
||||
|
||||
|
||||
def Command() -> Tuple[str, ...]:
|
||||
return Depends(_command, use_cache=False)
|
||||
"""消息命令元组"""
|
||||
return Depends(_command)
|
||||
|
||||
|
||||
def _raw_command(state: T_State) -> Message:
|
||||
@ -316,7 +336,8 @@ def _raw_command(state: T_State) -> Message:
|
||||
|
||||
|
||||
def RawCommand() -> str:
|
||||
return Depends(_raw_command, use_cache=False)
|
||||
"""消息命令文本"""
|
||||
return Depends(_raw_command)
|
||||
|
||||
|
||||
def _command_arg(state: T_State) -> Message:
|
||||
@ -324,7 +345,8 @@ def _command_arg(state: T_State) -> Message:
|
||||
|
||||
|
||||
def CommandArg() -> Any:
|
||||
return Depends(_command_arg, use_cache=False)
|
||||
"""消息命令参数"""
|
||||
return Depends(_command_arg)
|
||||
|
||||
|
||||
def _shell_command_args(state: T_State) -> Any:
|
||||
@ -332,6 +354,7 @@ def _shell_command_args(state: T_State) -> Any:
|
||||
|
||||
|
||||
def ShellCommandArgs():
|
||||
"""shell 命令解析后的参数字典"""
|
||||
return Depends(_shell_command_args, use_cache=False)
|
||||
|
||||
|
||||
@ -340,6 +363,7 @@ def _shell_command_argv(state: T_State) -> List[str]:
|
||||
|
||||
|
||||
def ShellCommandArgv() -> Any:
|
||||
"""shell 命令原始参数列表"""
|
||||
return Depends(_shell_command_argv, use_cache=False)
|
||||
|
||||
|
||||
@ -348,6 +372,7 @@ def _regex_matched(state: T_State) -> str:
|
||||
|
||||
|
||||
def RegexMatched() -> str:
|
||||
"""正则匹配结果"""
|
||||
return Depends(_regex_matched, use_cache=False)
|
||||
|
||||
|
||||
@ -356,6 +381,7 @@ def _regex_group(state: T_State):
|
||||
|
||||
|
||||
def RegexGroup() -> Tuple[Any, ...]:
|
||||
"""正则匹配结果 group 元组"""
|
||||
return Depends(_regex_group, use_cache=False)
|
||||
|
||||
|
||||
@ -364,10 +390,13 @@ def _regex_dict(state: T_State):
|
||||
|
||||
|
||||
def RegexDict() -> Dict[str, Any]:
|
||||
"""正则匹配结果 group 字典"""
|
||||
return Depends(_regex_dict, use_cache=False)
|
||||
|
||||
|
||||
class MatcherParam(Param):
|
||||
"""事件响应器实例参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -382,6 +411,8 @@ class MatcherParam(Param):
|
||||
|
||||
|
||||
def Received(id: Optional[str] = None, default: Any = None) -> Any:
|
||||
"""`receive` 事件参数"""
|
||||
|
||||
def _received(matcher: "Matcher"):
|
||||
return matcher.get_receive(id or "", default)
|
||||
|
||||
@ -389,6 +420,8 @@ def Received(id: Optional[str] = None, default: Any = None) -> Any:
|
||||
|
||||
|
||||
def LastReceived(default: Any = None) -> Any:
|
||||
"""`last_receive` 事件参数"""
|
||||
|
||||
def _last_received(matcher: "Matcher") -> Any:
|
||||
return matcher.get_last_receive(default)
|
||||
|
||||
@ -404,18 +437,23 @@ class ArgInner:
|
||||
|
||||
|
||||
def Arg(key: Optional[str] = None) -> Any:
|
||||
"""`got` 的 Arg 参数消息"""
|
||||
return ArgInner(key, "message")
|
||||
|
||||
|
||||
def ArgStr(key: Optional[str] = None) -> str:
|
||||
"""`got` 的 Arg 参数消息文本"""
|
||||
return ArgInner(key, "str") # type: ignore
|
||||
|
||||
|
||||
def ArgPlainText(key: Optional[str] = None) -> str:
|
||||
"""`got` 的 Arg 参数消息纯文本"""
|
||||
return ArgInner(key, "plaintext") # type: ignore
|
||||
|
||||
|
||||
class ArgParam(Param):
|
||||
"""`got` 的 Arg 参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -436,6 +474,8 @@ class ArgParam(Param):
|
||||
|
||||
|
||||
class ExceptionParam(Param):
|
||||
"""`run_postprocessor` 的异常参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -450,6 +490,8 @@ class ExceptionParam(Param):
|
||||
|
||||
|
||||
class DefaultParam(Param):
|
||||
"""默认值参数"""
|
||||
|
||||
@classmethod
|
||||
def _check_param(
|
||||
cls, dependent: Dependent, name: str, param: inspect.Parameter
|
||||
@ -462,3 +504,9 @@ class DefaultParam(Param):
|
||||
|
||||
|
||||
from nonebot.matcher import Matcher
|
||||
|
||||
__autodoc__ = {
|
||||
"DependsInner": False,
|
||||
"StateInner": False,
|
||||
"ArgInner": False,
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
"""
|
||||
## 权限
|
||||
"""本模块是 {ref}`nonebot.matcher.Matcher.permission` 的类型定义。
|
||||
|
||||
每个 `Matcher` 拥有一个 `Permission` ,其中是 `PermissionChecker` 的集合,只要有一个 `PermissionChecker` 检查结果为 `True` 时就会继续运行。
|
||||
每个 {ref}`nonebot.matcher.Matcher` 拥有一个 {ref}`nonebot.permission.Permission` ,
|
||||
其中是 `PermissionChecker` 的集合,只要有一个 `PermissionChecker` 检查结果为 `True` 时就会继续运行。
|
||||
|
||||
::: tip 提示
|
||||
`PermissionChecker` 既可以是 async function 也可以是 sync function
|
||||
:::
|
||||
FrontMatter:
|
||||
sidebar_position: 6
|
||||
description: nonebot.permission 模块
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
@ -15,7 +15,7 @@ from typing import Any, Set, Tuple, Union, NoReturn, Optional, Coroutine
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.dependencies import Dependent
|
||||
from nonebot.exception import SkippedException
|
||||
from nonebot.typing import T_Handler, T_DependencyCache, T_PermissionChecker
|
||||
from nonebot.typing import T_DependencyCache, T_PermissionChecker
|
||||
from nonebot.params import (
|
||||
BotParam,
|
||||
EventType,
|
||||
@ -33,15 +33,18 @@ async def _run_coro_with_catch(coro: Coroutine[Any, Any, Any]):
|
||||
|
||||
|
||||
class Permission:
|
||||
"""
|
||||
`Matcher` 规则类,当事件传递时,在 `Matcher` 运行前进行检查。
|
||||
"""{ref}`nonebot.matcher.Matcher` 权限类。
|
||||
|
||||
当事件传递时,在 {ref}`nonebot.matcher.Matcher` 运行前进行检查。
|
||||
|
||||
参数:
|
||||
checkers: PermissionChecker
|
||||
|
||||
用法:
|
||||
```python
|
||||
Permission(async_function) | sync_function
|
||||
# 等价于
|
||||
from nonebot.utils import run_sync
|
||||
Permission(async_function, run_sync(sync_function))
|
||||
Permission(async_function, sync_function)
|
||||
```
|
||||
"""
|
||||
|
||||
@ -55,11 +58,6 @@ class Permission:
|
||||
]
|
||||
|
||||
def __init__(self, *checkers: Union[T_PermissionChecker, Dependent[bool]]) -> None:
|
||||
"""
|
||||
参数:
|
||||
*checkers: PermissionChecker
|
||||
"""
|
||||
|
||||
self.checkers: Set[Dependent[bool]] = set(
|
||||
checker
|
||||
if isinstance(checker, Dependent)
|
||||
@ -68,9 +66,7 @@ class Permission:
|
||||
)
|
||||
for checker in checkers
|
||||
)
|
||||
"""
|
||||
存储 `PermissionChecker`
|
||||
"""
|
||||
"""存储 `PermissionChecker`"""
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
@ -79,8 +75,7 @@ class Permission:
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
检查是否满足某个权限
|
||||
"""检查是否满足某个权限
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
@ -120,44 +115,73 @@ class Permission:
|
||||
|
||||
|
||||
class Message:
|
||||
"""检查是否为消息事件"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, type: str = EventType()) -> bool:
|
||||
return type == "message"
|
||||
|
||||
|
||||
class Notice:
|
||||
"""检查是否为通知事件"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, type: str = EventType()) -> bool:
|
||||
return type == "notice"
|
||||
|
||||
|
||||
class Request:
|
||||
"""检查是否为请求事件"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, type: str = EventType()) -> bool:
|
||||
return type == "request"
|
||||
|
||||
|
||||
class MetaEvent:
|
||||
"""检查是否为元事件"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, type: str = EventType()) -> bool:
|
||||
return type == "meta_event"
|
||||
|
||||
|
||||
MESSAGE = Permission(Message())
|
||||
MESSAGE: Permission = Permission(Message())
|
||||
"""匹配任意 `message` 类型事件
|
||||
|
||||
仅在需要同时捕获不同类型事件时使用,优先使用 message type 的 Matcher。
|
||||
"""
|
||||
匹配任意 `message` 类型事件,仅在需要同时捕获不同类型事件时使用。优先使用 message type 的 Matcher。
|
||||
NOTICE: Permission = Permission(Notice())
|
||||
"""匹配任意 `notice` 类型事件
|
||||
|
||||
仅在需要同时捕获不同类型事件时使用,优先使用 notice type 的 Matcher。
|
||||
"""
|
||||
NOTICE = Permission(Notice())
|
||||
REQUEST: Permission = Permission(Request())
|
||||
"""匹配任意 `request` 类型事件
|
||||
|
||||
仅在需要同时捕获不同类型事件时使用,优先使用 request type 的 Matcher。
|
||||
"""
|
||||
匹配任意 `notice` 类型事件,仅在需要同时捕获不同类型事件时使用。优先使用 notice type 的 Matcher。
|
||||
"""
|
||||
REQUEST = Permission(Request())
|
||||
"""
|
||||
匹配任意 `request` 类型事件,仅在需要同时捕获不同类型事件时使用。优先使用 request type 的 Matcher。
|
||||
"""
|
||||
METAEVENT = Permission(MetaEvent())
|
||||
"""
|
||||
匹配任意 `meta_event` 类型事件,仅在需要同时捕获不同类型事件时使用。优先使用 meta_event type 的 Matcher。
|
||||
METAEVENT: Permission = Permission(MetaEvent())
|
||||
"""匹配任意 `meta_event` 类型事件
|
||||
|
||||
仅在需要同时捕获不同类型事件时使用,优先使用 meta_event type 的 Matcher。
|
||||
"""
|
||||
|
||||
|
||||
class User:
|
||||
"""检查当前事件是否属于指定会话
|
||||
|
||||
参数:
|
||||
users: 会话 ID 元组
|
||||
perm: 需同时满足的权限
|
||||
"""
|
||||
|
||||
__slots__ = ("users", "perm")
|
||||
|
||||
def __init__(
|
||||
self, users: Tuple[str, ...], perm: Optional[Permission] = None
|
||||
) -> None:
|
||||
@ -172,18 +196,21 @@ class User:
|
||||
|
||||
|
||||
def USER(*users: str, perm: Optional[Permission] = None):
|
||||
"""
|
||||
`event` 的 `session_id` 在白名单内且满足 perm
|
||||
"""匹配当前事件属于指定会话
|
||||
|
||||
参数:
|
||||
*user: 白名单
|
||||
perm: 需要同时满足的权限
|
||||
user: 会话白名单
|
||||
perm: 需要同时满足的权限
|
||||
"""
|
||||
|
||||
return Permission(User(users, perm))
|
||||
|
||||
|
||||
class SuperUser:
|
||||
"""检查当前事件是否是消息事件且属于超级管理员"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, bot: Bot, event: Event) -> bool:
|
||||
return event.get_type() == "message" and (
|
||||
f"{bot.adapter.get_name().split(maxsplit=1)[0].lower()}:{event.get_user_id()}"
|
||||
@ -192,7 +219,7 @@ class SuperUser:
|
||||
)
|
||||
|
||||
|
||||
SUPERUSER = Permission(SuperUser())
|
||||
"""
|
||||
匹配任意超级用户消息类型事件
|
||||
"""
|
||||
SUPERUSER: Permission = Permission(SuperUser())
|
||||
"""匹配任意超级用户消息类型事件"""
|
||||
|
||||
__autodoc__ = {"Permission.__call__": True}
|
||||
|
@ -1,7 +1,37 @@
|
||||
"""
|
||||
## 插件
|
||||
"""本模块为 NoneBot 插件开发提供便携的定义函数。
|
||||
|
||||
为 NoneBot 插件开发提供便携的定义函数。
|
||||
## 快捷导入
|
||||
|
||||
为方便使用,本模块从子模块导入了部分内容,以下内容可以直接通过本模块导入:
|
||||
|
||||
- `on` => {ref}``on` <nonebot.plugin.on.on>`
|
||||
- `on_metaevent` => {ref}``on_metaevent` <nonebot.plugin.on.on_metaevent>`
|
||||
- `on_message` => {ref}``on_message` <nonebot.plugin.on.on_message>`
|
||||
- `on_notice` => {ref}``on_notice` <nonebot.plugin.on.on_notice>`
|
||||
- `on_request` => {ref}``on_request` <nonebot.plugin.on.on_request>`
|
||||
- `on_startswith` => {ref}``on_startswith` <nonebot.plugin.on.on_startswith>`
|
||||
- `on_endswith` => {ref}``on_endswith` <nonebot.plugin.on.on_endswith>`
|
||||
- `on_keyword` => {ref}``on_keyword` <nonebot.plugin.on.on_keyword>`
|
||||
- `on_command` => {ref}``on_command` <nonebot.plugin.on.on_command>`
|
||||
- `on_shell_command` => {ref}``on_shell_command` <nonebot.plugin.on.on_shell_command>`
|
||||
- `on_regex` => {ref}``on_regex` <nonebot.plugin.on.on_regex>`
|
||||
- `CommandGroup` => {ref}``CommandGroup` <nonebot.plugin.on.CommandGroup>`
|
||||
- `Matchergroup` => {ref}``MatcherGroup` <nonebot.plugin.on.MatcherGroup>`
|
||||
- `load_plugin` => {ref}``load_plugin` <nonebot.plugin.load.load_plugin>`
|
||||
- `load_plugins` => {ref}``load_plugins` <nonebot.plugin.load.load_plugins>`
|
||||
- `load_all_plugins` => {ref}``load_all_plugins` <nonebot.plugin.load.load_all_plugins>`
|
||||
- `load_from_json` => {ref}``load_from_json` <nonebot.plugin.load.load_from_json>`
|
||||
- `load_from_toml` => {ref}``load_from_toml` <nonebot.plugin.load.load_from_toml>`
|
||||
- `load_builtin_plugin` => {ref}``load_builtin_plugin` <nonebot.plugin.load.load_builtin_plugin>`
|
||||
- `load_builtin_plugins` => {ref}``load_builtin_plugins` <nonebot.plugin.load.load_builtin_plugins>`
|
||||
- `get_plugin` => {ref}``get_plugin` <nonebot.plugin.plugin.get_plugin>`
|
||||
- `get_loaded_plugins` => {ref}``get_loaded_plugins` <nonebot.plugin.plugin.get_loaded_plugins>`
|
||||
- `export` => {ref}``export` <nonebot.plugin.export.export>`
|
||||
- `require` => {ref}``require` <nonebot.plugin.load.require>`
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 0
|
||||
description: nonebot.plugin 模块
|
||||
"""
|
||||
|
||||
from typing import List, Optional
|
||||
|
@ -1,9 +1,17 @@
|
||||
"""本模块定义了插件导出的内容对象。
|
||||
|
||||
在新版插件系统中,推荐优先使用直接 import 所需要的插件内容。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 4
|
||||
description: nonebot.plugin.export 模块
|
||||
"""
|
||||
|
||||
from . import _current_plugin
|
||||
|
||||
|
||||
class Export(dict):
|
||||
"""
|
||||
插件导出内容以使得其他插件可以获得。
|
||||
"""插件导出内容以使得其他插件可以获得。
|
||||
|
||||
用法:
|
||||
```python
|
||||
@ -42,9 +50,7 @@ class Export(dict):
|
||||
|
||||
|
||||
def export() -> Export:
|
||||
"""
|
||||
获取插件的导出内容对象
|
||||
"""
|
||||
"""获取当前插件的导出内容对象"""
|
||||
plugin = _current_plugin.get()
|
||||
if not plugin:
|
||||
raise RuntimeError("Export outside of the plugin!")
|
||||
|
@ -1,3 +1,9 @@
|
||||
"""本模块定义插件加载接口。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 1
|
||||
description: nonebot.plugin.load 模块
|
||||
"""
|
||||
import json
|
||||
import warnings
|
||||
from typing import Set, Iterable, Optional
|
||||
@ -11,8 +17,7 @@ from .plugin import Plugin, get_plugin
|
||||
|
||||
|
||||
def load_plugin(module_path: str) -> Optional[Plugin]:
|
||||
"""
|
||||
使用 `PluginManager` 加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。
|
||||
"""加载单个插件,可以是本地插件或是通过 `pip` 安装的插件。
|
||||
|
||||
参数:
|
||||
module_path: 插件名称 `path.to.your.plugin`
|
||||
@ -24,11 +29,10 @@ def load_plugin(module_path: str) -> Optional[Plugin]:
|
||||
|
||||
|
||||
def load_plugins(*plugin_dir: str) -> Set[Plugin]:
|
||||
"""
|
||||
导入目录下多个插件,以 `_` 开头的插件不会被导入!
|
||||
"""导入文件夹下多个插件,以 `_` 开头的插件不会被导入!
|
||||
|
||||
参数:
|
||||
plugin_dir: 插件路径
|
||||
plugin_dir: 文件夹路径
|
||||
"""
|
||||
manager = PluginManager(search_path=plugin_dir)
|
||||
_managers.append(manager)
|
||||
@ -38,12 +42,11 @@ def load_plugins(*plugin_dir: str) -> Set[Plugin]:
|
||||
def load_all_plugins(
|
||||
module_path: Iterable[str], plugin_dir: Iterable[str]
|
||||
) -> Set[Plugin]:
|
||||
"""
|
||||
导入指定列表中的插件以及指定目录下多个插件,以 `_` 开头的插件不会被导入!
|
||||
"""导入指定列表中的插件以及指定目录下多个插件,以 `_` 开头的插件不会被导入!
|
||||
|
||||
参数:
|
||||
module_path: 指定插件集合
|
||||
plugin_dir: 指定插件路径集合
|
||||
plugin_dir: 指定文件夹路径集合
|
||||
"""
|
||||
manager = PluginManager(module_path, plugin_dir)
|
||||
_managers.append(manager)
|
||||
@ -51,12 +54,23 @@ def load_all_plugins(
|
||||
|
||||
|
||||
def load_from_json(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
|
||||
"""
|
||||
导入指定 json 文件中的 `plugins` 以及 `plugin_dirs` 下多个插件,以 `_` 开头的插件不会被导入!
|
||||
"""导入指定 json 文件中的 `plugins` 以及 `plugin_dirs` 下多个插件,以 `_` 开头的插件不会被导入!
|
||||
|
||||
参数:
|
||||
file_path: 指定 json 文件路径
|
||||
encoding: 指定 json 文件编码
|
||||
|
||||
用法:
|
||||
```json title=plugins.json
|
||||
{
|
||||
"plugins": ["some_plugin"],
|
||||
"plugin_dirs": ["some_dir"]
|
||||
}
|
||||
```
|
||||
|
||||
```python
|
||||
nonebot.load_from_json("plugins.json")
|
||||
```
|
||||
"""
|
||||
with open(file_path, "r", encoding=encoding) as f:
|
||||
data = json.load(f)
|
||||
@ -68,13 +82,22 @@ def load_from_json(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
|
||||
|
||||
|
||||
def load_from_toml(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
|
||||
"""
|
||||
导入指定 toml 文件 `[tool.nonebot]` 中的 `plugins` 以及 `plugin_dirs` 下多个插件,
|
||||
以 `_` 开头的插件不会被导入!
|
||||
"""导入指定 toml 文件 `[tool.nonebot]` 中的 `plugins` 以及 `plugin_dirs` 下多个插件,以 `_` 开头的插件不会被导入!
|
||||
|
||||
参数:
|
||||
file_path: 指定 toml 文件路径
|
||||
encoding: 指定 toml 文件编码
|
||||
|
||||
用法:
|
||||
```toml title=pyproject.toml
|
||||
[tool.nonebot]
|
||||
plugins = ["some_plugin"]
|
||||
plugin_dirs = ["some_dir"]
|
||||
```
|
||||
|
||||
```python
|
||||
nonebot.load_from_toml("pyproject.toml")
|
||||
```
|
||||
"""
|
||||
with open(file_path, "r", encoding=encoding) as f:
|
||||
data = tomlkit.parse(f.read()) # type: ignore
|
||||
@ -97,25 +120,30 @@ def load_from_toml(file_path: str, encoding: str = "utf-8") -> Set[Plugin]:
|
||||
|
||||
|
||||
def load_builtin_plugin(name: str) -> Optional[Plugin]:
|
||||
"""
|
||||
导入 NoneBot 内置插件
|
||||
"""导入 NoneBot 内置插件。
|
||||
|
||||
参数:
|
||||
name: 插件名称
|
||||
"""
|
||||
return load_plugin(f"nonebot.plugins.{name}")
|
||||
|
||||
|
||||
def load_builtin_plugins(*plugins) -> Set[Plugin]:
|
||||
"""
|
||||
导入多个 NoneBot 内置插件
|
||||
"""导入多个 NoneBot 内置插件。
|
||||
|
||||
参数:
|
||||
plugins: 插件名称列表
|
||||
"""
|
||||
return load_all_plugins([f"nonebot.plugins.{p}" for p in plugins], [])
|
||||
|
||||
|
||||
def require(name: str) -> Export:
|
||||
"""
|
||||
获取一个插件的导出内容
|
||||
"""获取一个插件的导出内容。
|
||||
|
||||
如果为 `load_plugins` 文件夹导入的插件,则为文件(夹)名。
|
||||
|
||||
参数:
|
||||
name: 插件名,与 `load_plugin` 参数一致。如果为 `load_plugins` 导入的插件,则为文件(夹)名。
|
||||
name: 插件名,即 {ref}`nonebot.plugin.plugin.Plugin.name`。
|
||||
|
||||
异常:
|
||||
RuntimeError: 插件无法加载
|
||||
|
@ -1,3 +1,11 @@
|
||||
"""本模块实现插件加载流程。
|
||||
|
||||
参考: [import hooks](https://docs.python.org/3/reference/import.html#import-hooks), [PEP302](https://www.python.org/dev/peps/pep-0302/)
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 5
|
||||
description: nonebot.plugin.manager 模块
|
||||
"""
|
||||
import sys
|
||||
import pkgutil
|
||||
import importlib
|
||||
|
@ -1,3 +1,9 @@
|
||||
"""本模块定义事件响应器便携定义函数。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 2
|
||||
description: nonebot.plugin.on 模块
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import inspect
|
||||
|
@ -1,3 +1,9 @@
|
||||
"""本模块定义插件对象。
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 3
|
||||
description: nonebot.plugin.plugin 模块
|
||||
"""
|
||||
from types import ModuleType
|
||||
from dataclasses import field, dataclass
|
||||
from typing import TYPE_CHECKING, Set, Dict, Type, Optional
|
||||
@ -10,9 +16,7 @@ if TYPE_CHECKING:
|
||||
from .manager import PluginManager
|
||||
|
||||
plugins: Dict[str, "Plugin"] = {}
|
||||
"""
|
||||
已加载的插件
|
||||
"""
|
||||
"""已加载的插件"""
|
||||
|
||||
|
||||
@dataclass(eq=False)
|
||||
@ -20,53 +24,36 @@ class Plugin(object):
|
||||
"""存储插件信息"""
|
||||
|
||||
name: str
|
||||
"""
|
||||
插件名称,使用 文件/文件夹 名称作为插件名
|
||||
"""
|
||||
"""插件名称,使用 文件/文件夹 名称作为插件名"""
|
||||
module: ModuleType
|
||||
"""
|
||||
插件模块对象
|
||||
"""
|
||||
"""插件模块对象"""
|
||||
module_name: str
|
||||
"""
|
||||
点分割模块路径
|
||||
"""
|
||||
"""点分割模块路径"""
|
||||
manager: "PluginManager"
|
||||
"""
|
||||
导入该插件的插件管理器
|
||||
"""
|
||||
"""导入该插件的插件管理器"""
|
||||
export: Export = field(default_factory=Export)
|
||||
"""
|
||||
插件内定义的导出内容
|
||||
"""
|
||||
"""插件内定义的导出内容"""
|
||||
matcher: Set[Type[Matcher]] = field(default_factory=set)
|
||||
"""
|
||||
插件内定义的 `Matcher`
|
||||
"""
|
||||
"""插件内定义的 `Matcher`"""
|
||||
parent_plugin: Optional["Plugin"] = None
|
||||
"""
|
||||
父插件
|
||||
"""
|
||||
"""父插件"""
|
||||
sub_plugins: Set["Plugin"] = field(default_factory=set)
|
||||
"""
|
||||
子插件集合
|
||||
"""
|
||||
"""子插件集合"""
|
||||
|
||||
|
||||
def get_plugin(name: str) -> Optional[Plugin]:
|
||||
"""
|
||||
获取当前导入的某个插件。
|
||||
"""获取已经导入的某个插件。
|
||||
|
||||
如果为 `load_plugins` 文件夹导入的插件,则为文件(夹)名。
|
||||
|
||||
参数:
|
||||
name: 插件名,与 `load_plugin` 参数一致。如果为 `load_plugins` 导入的插件,则为文件(夹)名。
|
||||
name: 插件名,即 {ref}`nonebot.plugin.plugin.Plugin.name`。
|
||||
"""
|
||||
return plugins.get(name)
|
||||
|
||||
|
||||
def get_loaded_plugins() -> Set[Plugin]:
|
||||
"""
|
||||
获取当前已导入的所有插件。
|
||||
"""
|
||||
"""获取当前已导入的所有插件。"""
|
||||
return set(plugins.values())
|
||||
|
||||
|
||||
|
195
nonebot/rule.py
195
nonebot/rule.py
@ -1,11 +1,11 @@
|
||||
"""
|
||||
## 规则
|
||||
"""本模块是 {ref}`nonebot.matcher.Matcher.rule` 的类型定义。
|
||||
|
||||
每个事件响应器 `Matcher` 拥有一个匹配规则 `Rule` ,其中是 `RuleChecker` 的集合,只有当所有 `RuleChecker` 检查结果为 `True` 时继续运行。
|
||||
每个事件响应器 {ref}`nonebot.matcher.Matcher` 拥有一个匹配规则 {ref}`nonebot.rule.Rule`
|
||||
其中是 `RuleChecker` 的集合,只有当所有 `RuleChecker` 检查结果为 `True` 时继续运行。
|
||||
|
||||
::: tip 提示
|
||||
`RuleChecker` 既可以是 async function 也可以是 sync function
|
||||
:::
|
||||
FrontMatter:
|
||||
sidebar_position: 5
|
||||
description: nonebot.rule 模块
|
||||
"""
|
||||
|
||||
import re
|
||||
@ -42,6 +42,7 @@ from nonebot.params import (
|
||||
BotParam,
|
||||
EventToMe,
|
||||
EventType,
|
||||
CommandArg,
|
||||
EventParam,
|
||||
StateParam,
|
||||
DependParam,
|
||||
@ -61,15 +62,18 @@ CMD_RESULT = TypedDict(
|
||||
|
||||
|
||||
class Rule:
|
||||
"""
|
||||
`Matcher` 规则类,当事件传递时,在 `Matcher` 运行前进行检查。
|
||||
"""{ref}`nonebot.matcher.Matcher` 规则类。
|
||||
|
||||
当事件传递时,在 {ref}`nonebot.matcher.Matcher` 运行前进行检查。
|
||||
|
||||
参数:
|
||||
*checkers: RuleChecker
|
||||
|
||||
用法:
|
||||
```python
|
||||
Rule(async_function) & sync_function
|
||||
# 等价于
|
||||
from nonebot.utils import run_sync
|
||||
Rule(async_function, run_sync(sync_function))
|
||||
Rule(async_function, sync_function)
|
||||
```
|
||||
"""
|
||||
|
||||
@ -84,11 +88,6 @@ class Rule:
|
||||
]
|
||||
|
||||
def __init__(self, *checkers: Union[T_RuleChecker, Dependent[bool]]) -> None:
|
||||
"""
|
||||
参数:
|
||||
*checkers: RuleChecker
|
||||
|
||||
"""
|
||||
self.checkers: Set[Dependent[bool]] = set(
|
||||
checker
|
||||
if isinstance(checker, Dependent)
|
||||
@ -97,9 +96,7 @@ class Rule:
|
||||
)
|
||||
for checker in checkers
|
||||
)
|
||||
"""
|
||||
存储 `RuleChecker`
|
||||
"""
|
||||
"""存储 `RuleChecker`"""
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
@ -109,8 +106,7 @@ class Rule:
|
||||
stack: Optional[AsyncExitStack] = None,
|
||||
dependency_cache: Optional[T_DependencyCache] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
检查是否符合所有规则
|
||||
"""检查是否符合所有规则
|
||||
|
||||
参数:
|
||||
bot: Bot 对象
|
||||
@ -186,6 +182,15 @@ class TrieRule:
|
||||
|
||||
|
||||
class StartswithRule:
|
||||
"""检查消息纯文本是否以指定字符串开头。
|
||||
|
||||
参数:
|
||||
msg: 指定消息开头字符串元组
|
||||
ignorecase: 是否忽略大小写
|
||||
"""
|
||||
|
||||
__slots__ = ("msg", "ignorecase")
|
||||
|
||||
def __init__(self, msg: Tuple[str, ...], ignorecase: bool = False):
|
||||
self.msg = msg
|
||||
self.ignorecase = ignorecase
|
||||
@ -205,11 +210,11 @@ class StartswithRule:
|
||||
|
||||
|
||||
def startswith(msg: Union[str, Tuple[str, ...]], ignorecase: bool = False) -> Rule:
|
||||
"""
|
||||
匹配消息开头
|
||||
"""匹配消息纯文本开头。
|
||||
|
||||
参数:
|
||||
msg: 消息开头字符串
|
||||
msg: 指定消息开头字符串元组
|
||||
ignorecase: 是否忽略大小写
|
||||
"""
|
||||
if isinstance(msg, str):
|
||||
msg = (msg,)
|
||||
@ -218,6 +223,15 @@ def startswith(msg: Union[str, Tuple[str, ...]], ignorecase: bool = False) -> Ru
|
||||
|
||||
|
||||
class EndswithRule:
|
||||
"""检查消息纯文本是否以指定字符串结尾。
|
||||
|
||||
参数:
|
||||
msg: 指定消息结尾字符串元组
|
||||
ignorecase: 是否忽略大小写
|
||||
"""
|
||||
|
||||
__slots__ = ("msg", "ignorecase")
|
||||
|
||||
def __init__(self, msg: Tuple[str, ...], ignorecase: bool = False):
|
||||
self.msg = msg
|
||||
self.ignorecase = ignorecase
|
||||
@ -237,11 +251,11 @@ class EndswithRule:
|
||||
|
||||
|
||||
def endswith(msg: Union[str, Tuple[str, ...]], ignorecase: bool = False) -> Rule:
|
||||
"""
|
||||
匹配消息结尾
|
||||
"""匹配消息纯文本结尾。
|
||||
|
||||
参数:
|
||||
msg: 消息结尾字符串
|
||||
msg: 指定消息开头字符串元组
|
||||
ignorecase: 是否忽略大小写
|
||||
"""
|
||||
if isinstance(msg, str):
|
||||
msg = (msg,)
|
||||
@ -250,6 +264,14 @@ def endswith(msg: Union[str, Tuple[str, ...]], ignorecase: bool = False) -> Rule
|
||||
|
||||
|
||||
class KeywordsRule:
|
||||
"""检查消息纯文本是否包含指定关键字。
|
||||
|
||||
参数:
|
||||
keywords: 指定关键字元组
|
||||
"""
|
||||
|
||||
__slots__ = ("keywords",)
|
||||
|
||||
def __init__(self, *keywords: str):
|
||||
self.keywords = keywords
|
||||
|
||||
@ -262,17 +284,24 @@ class KeywordsRule:
|
||||
|
||||
|
||||
def keyword(*keywords: str) -> Rule:
|
||||
"""
|
||||
匹配消息关键词
|
||||
"""匹配消息纯文本关键词。
|
||||
|
||||
参数:
|
||||
*keywords: 关键词
|
||||
keywords: 指定关键字元组
|
||||
"""
|
||||
|
||||
return Rule(KeywordsRule(*keywords))
|
||||
|
||||
|
||||
class CommandRule:
|
||||
"""检查消息是否为指定命令。
|
||||
|
||||
参数:
|
||||
cmds: 指定命令元组列表
|
||||
"""
|
||||
|
||||
__slots__ = ("cmds",)
|
||||
|
||||
def __init__(self, cmds: List[Tuple[str, ...]]):
|
||||
self.cmds = cmds
|
||||
|
||||
@ -284,22 +313,26 @@ class CommandRule:
|
||||
|
||||
|
||||
def command(*cmds: Union[str, Tuple[str, ...]]) -> Rule:
|
||||
"""
|
||||
命令形式匹配,根据配置里提供的 `command_start`, `command_sep` 判断消息是否为命令。
|
||||
"""匹配消息命令。
|
||||
|
||||
可以通过 `state["_prefix"]["command"]` 获取匹配成功的命令(例:`("test",)`),通过 `state["_prefix"]["raw_command"]` 获取匹配成功的原始命令文本(例:`"/test"`)。
|
||||
根据配置里提供的 {ref}``command_start` <nonebot.config.Config.command_start>`,
|
||||
{ref}``command_sep` <nonebot.config.Config.command_sep>` 判断消息是否为命令。
|
||||
|
||||
可以通过 {ref}`nonebot.params.Command` 获取匹配成功的命令(例: `("test",)`),
|
||||
通过 {ref}`nonebot.params.RawCommand` 获取匹配成功的原始命令文本(例: `"/test"`),
|
||||
通过 {ref}`nonebot.params.CommandArg` 获取匹配成功的命令参数。
|
||||
|
||||
参数:
|
||||
*cmds: 命令内容
|
||||
cmds: 命令文本或命令元组
|
||||
|
||||
用法:
|
||||
使用默认 `command_start`, `command_sep` 配置
|
||||
|
||||
命令 `("test",)` 可以匹配:`/test` 开头的消息
|
||||
命令 `("test", "sub")` 可以匹配”`/test.sub` 开头的消息
|
||||
命令 `("test",)` 可以匹配: `/test` 开头的消息
|
||||
命令 `("test", "sub")` 可以匹配: `/test.sub` 开头的消息
|
||||
|
||||
::: tip 提示
|
||||
命令内容与后续消息间无需空格!
|
||||
:::tip 提示
|
||||
命令内容与后续消息间无需空格!
|
||||
:::
|
||||
"""
|
||||
|
||||
@ -324,8 +357,11 @@ def command(*cmds: Union[str, Tuple[str, ...]]) -> Rule:
|
||||
|
||||
|
||||
class ArgumentParser(ArgParser):
|
||||
"""
|
||||
`shell_like` 命令参数解析器,解析出错时不会退出程序。
|
||||
"""`shell_like` 命令参数解析器,解析出错时不会退出程序。
|
||||
|
||||
用法:
|
||||
用法与 `argparse.ArgumentParser` 相同,
|
||||
参考文档: [argparse](https://docs.python.org/3/library/argparse.html)
|
||||
"""
|
||||
|
||||
def _print_message(self, message, file=None):
|
||||
@ -350,6 +386,15 @@ class ArgumentParser(ArgParser):
|
||||
|
||||
|
||||
class ShellCommandRule:
|
||||
"""检查消息是否为指定 shell 命令。
|
||||
|
||||
参数:
|
||||
cmds: 指定命令元组列表
|
||||
parser: 可选参数解析器
|
||||
"""
|
||||
|
||||
__slots__ = ("cmds", "parser")
|
||||
|
||||
def __init__(self, cmds: List[Tuple[str, ...]], parser: Optional[ArgumentParser]):
|
||||
self.cmds = cmds
|
||||
self.parser = parser
|
||||
@ -358,12 +403,11 @@ class ShellCommandRule:
|
||||
self,
|
||||
state: T_State,
|
||||
cmd: Optional[Tuple[str, ...]] = Command(),
|
||||
msg: Message = EventMessage(),
|
||||
msg: Optional[Message] = CommandArg(),
|
||||
) -> bool:
|
||||
if cmd in self.cmds:
|
||||
if cmd in self.cmds and msg is not None:
|
||||
message = str(msg)
|
||||
strip_message = message[len(state[PREFIX_KEY][RAW_CMD_KEY]) :].lstrip()
|
||||
state[SHELL_ARGV] = shlex.split(strip_message)
|
||||
state[SHELL_ARGV] = shlex.split(message)
|
||||
if self.parser:
|
||||
try:
|
||||
args = self.parser.parse_args(state[SHELL_ARGV])
|
||||
@ -378,18 +422,24 @@ class ShellCommandRule:
|
||||
def shell_command(
|
||||
*cmds: Union[str, Tuple[str, ...]], parser: Optional[ArgumentParser] = None
|
||||
) -> Rule:
|
||||
"""
|
||||
支持 `shell_like` 解析参数的命令形式匹配,根据配置里提供的 `command_start`, `command_sep` 判断消息是否为命令。
|
||||
"""匹配 `shell_like` 形式的消息命令。
|
||||
|
||||
可以通过 `state["_prefix"]["command"]` 获取匹配成功的命令(例:`("test",)`),通过 `state["_prefix"]["raw_command"]` 获取匹配成功的原始命令文本(例:`"/test"`)。
|
||||
根据配置里提供的 {ref}``command_start` <nonebot.config.Config.command_start>`,
|
||||
{ref}``command_sep` <nonebot.config.Config.command_sep>` 判断消息是否为命令。
|
||||
|
||||
可以通过 `state["argv"]` 获取用户输入的原始参数列表
|
||||
可以通过 {ref}`nonebot.params.Command` 获取匹配成功的命令(例: `("test",)`),
|
||||
通过 {ref}`nonebot.params.RawCommand` 获取匹配成功的原始命令文本(例: `"/test"`),
|
||||
通过 {ref}`nonebot.params.ShellCommandArgv` 获取解析前的参数列表(例: `["arg", "-h"]`),
|
||||
通过 {ref}`nonebot.params.ShellCommandArgs` 获取解析后的参数字典(例: `{"arg": "arg", "h": True}`)。
|
||||
|
||||
添加 `parser` 参数后, 可以自动处理消息并将结果保存在 `state["args"]` 中。
|
||||
:::warning 警告
|
||||
如果参数解析失败,则通过 {ref}`nonebot.params.ShellCommandArgs`
|
||||
获取的将是 {ref}`nonebot.exception.ParserExit` 异常。
|
||||
:::
|
||||
|
||||
参数:
|
||||
*cmds: 命令内容
|
||||
parser: `nonebot.rule.ArgumentParser` 对象
|
||||
cmds: 命令文本或命令元组
|
||||
parser: {ref}`nonebot.rule.ArgumentParser` 对象
|
||||
|
||||
用法:
|
||||
使用默认 `command_start`, `command_sep` 配置,更多示例参考 `argparse` 标准库文档。
|
||||
@ -403,8 +453,8 @@ def shell_command(
|
||||
rule = shell_command("ls", parser=parser)
|
||||
```
|
||||
|
||||
::: tip 提示
|
||||
命令内容与后续消息间无需空格!
|
||||
:::tip 提示
|
||||
命令内容与后续消息间无需空格!
|
||||
:::
|
||||
"""
|
||||
if parser is not None and not isinstance(parser, ArgumentParser):
|
||||
@ -431,6 +481,15 @@ def shell_command(
|
||||
|
||||
|
||||
class RegexRule:
|
||||
"""检查消息字符串是否符合指定正则表达式。
|
||||
|
||||
参数:
|
||||
regex: 正则表达式
|
||||
flags: 正则表达式标记
|
||||
"""
|
||||
|
||||
__slots__ = ("regex", "flags")
|
||||
|
||||
def __init__(self, regex: str, flags: int = 0):
|
||||
self.regex = regex
|
||||
self.flags = flags
|
||||
@ -454,32 +513,46 @@ class RegexRule:
|
||||
|
||||
|
||||
def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule:
|
||||
"""
|
||||
根据正则表达式进行匹配。
|
||||
"""匹配符合正则表达式的消息字符串。
|
||||
|
||||
可以通过 `state["_matched"]` `state["_matched_groups"]` `state["_matched_dict"]`
|
||||
获取正则表达式匹配成功的文本。
|
||||
可以通过 {ref}`nonebot.params.RegexMatched` 获取匹配成功的字符串,
|
||||
通过 {ref}`nonebot.params.RegexGroup` 获取匹配成功的 group 元组,
|
||||
通过 {ref}`nonebot.params.RegexDict` 获取匹配成功的 group 字典。
|
||||
|
||||
参数:
|
||||
regex: 正则表达式
|
||||
flags: 正则标志
|
||||
flags: 正则表达式标记
|
||||
|
||||
::: tip 提示
|
||||
:::tip 提示
|
||||
正则表达式匹配使用 search 而非 match,如需从头匹配请使用 `r"^xxx"` 来确保匹配开头
|
||||
:::
|
||||
|
||||
:::tip 提示
|
||||
正则表达式匹配使用 `EventMessage` 的 `str` 字符串,而非 `EventMessage` 的 `PlainText` 纯文本字符串
|
||||
:::
|
||||
"""
|
||||
|
||||
return Rule(RegexRule(regex, flags))
|
||||
|
||||
|
||||
class ToMeRule:
|
||||
"""检查事件是否与机器人有关。"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
async def __call__(self, to_me: bool = EventToMe()) -> bool:
|
||||
return to_me
|
||||
|
||||
|
||||
def to_me() -> Rule:
|
||||
"""
|
||||
通过 `event.is_tome()` 判断事件是否与机器人有关
|
||||
"""
|
||||
"""匹配与机器人有关的事件。"""
|
||||
|
||||
return Rule(ToMeRule())
|
||||
|
||||
|
||||
__autodoc__ = {
|
||||
"Rule.__call__": True,
|
||||
"TrieRule": False,
|
||||
"ArgumentParser.exit": False,
|
||||
"ArgumentParser.parse_args": False,
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
"""
|
||||
## 类型
|
||||
"""本模块定义了 NoneBot 模块中共享的一些类型。
|
||||
|
||||
下面的文档中,「类型」部分使用 Python 的 Type Hint 语法,见 [`PEP 484`](https://www.python.org/dev/peps/pep-0484/)、[`PEP 526`](https://www.python.org/dev/peps/pep-0526/) 和 [`typing`](https://docs.python.org/3/library/typing.html)。
|
||||
下面的文档中,「类型」部分使用 Python 的 Type Hint 语法,
|
||||
参考 [`PEP 484`](https://www.python.org/dev/peps/pep-0484/),
|
||||
[`PEP 526`](https://www.python.org/dev/peps/pep-0526/) 和
|
||||
[`typing`](https://docs.python.org/3/library/typing.html)。
|
||||
|
||||
除了 Python 内置的类型,下面还出现了如下 NoneBot 自定类型,实际上它们是 Python 内置类型的别名。
|
||||
|
||||
以下类型均可从 nonebot.typing 模块导入。
|
||||
FrontMatter:
|
||||
sidebar_position: 11
|
||||
description: nonebot.typing 模块
|
||||
"""
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
@ -21,13 +25,15 @@ from typing import (
|
||||
if TYPE_CHECKING:
|
||||
from asyncio import Task
|
||||
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.permission import Permission
|
||||
|
||||
T_Wrapped = TypeVar("T_Wrapped", bound=Callable)
|
||||
|
||||
|
||||
def overrides(InterfaceClass: object):
|
||||
def overrides(InterfaceClass: object) -> Callable[[T_Wrapped], T_Wrapped]:
|
||||
"""标记一个方法为父类 interface 的 implement"""
|
||||
|
||||
def overrider(func: T_Wrapped) -> T_Wrapped:
|
||||
assert func.__name__ in dir(InterfaceClass), f"Error method: {func.__name__}"
|
||||
return func
|
||||
@ -36,136 +42,114 @@ def overrides(InterfaceClass: object):
|
||||
|
||||
|
||||
T_State = Dict[Any, Any]
|
||||
"""
|
||||
事件处理状态 State 类型
|
||||
"""
|
||||
"""事件处理状态 State 类型"""
|
||||
|
||||
T_BotConnectionHook = Callable[["Bot"], Awaitable[None]]
|
||||
"""
|
||||
Bot 连接建立时执行的函数
|
||||
"""
|
||||
"""Bot 连接建立时钩子函数"""
|
||||
T_BotDisconnectionHook = Callable[["Bot"], Awaitable[None]]
|
||||
"""
|
||||
Bot 连接断开时执行的函数
|
||||
"""
|
||||
"""Bot 连接断开时钩子函数"""
|
||||
T_CallingAPIHook = Callable[["Bot", str, Dict[str, Any]], Awaitable[None]]
|
||||
"""
|
||||
`bot.call_api` 时执行的函数
|
||||
"""
|
||||
"""`bot.call_api` 钩子函数"""
|
||||
T_CalledAPIHook = Callable[
|
||||
["Bot", Optional[Exception], str, Dict[str, Any], Any], Awaitable[None]
|
||||
]
|
||||
"""
|
||||
`bot.call_api` 后执行的函数,参数分别为 bot, exception, api, data, result
|
||||
"""
|
||||
"""`bot.call_api` 后执行的函数,参数分别为 bot, exception, api, data, result"""
|
||||
|
||||
T_EventPreProcessor = Callable[..., Union[None, Awaitable[None]]]
|
||||
"""
|
||||
事件预处理函数 EventPreProcessor 类型
|
||||
"""事件预处理函数 EventPreProcessor 类型
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_EventPostProcessor = Callable[..., Union[None, Awaitable[None]]]
|
||||
"""
|
||||
事件预处理函数 EventPostProcessor 类型
|
||||
"""事件预处理函数 EventPostProcessor 类型
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_RunPreProcessor = Callable[..., Union[None, Awaitable[None]]]
|
||||
"""
|
||||
事件响应器运行前预处理函数 RunPreProcessor 类型
|
||||
"""事件响应器运行前预处理函数 RunPreProcessor 类型
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_RunPostProcessor = Callable[..., Union[None, Awaitable[None]]]
|
||||
"""
|
||||
事件响应器运行前预处理函数 RunPostProcessor 类型,第二个参数为运行时产生的错误(如果存在)
|
||||
"""事件响应器运行前预处理函数 RunPostProcessor 类型
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- ExceptionParam: 异常对象(可能为 None)
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- ExceptionParam: 异常对象(可能为 None)
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
|
||||
T_RuleChecker = Callable[..., Union[bool, Awaitable[bool]]]
|
||||
"""
|
||||
RuleChecker 即判断是否响应事件的处理函数。
|
||||
"""RuleChecker 即判断是否响应事件的处理函数。
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_PermissionChecker = Callable[..., Union[bool, Awaitable[bool]]]
|
||||
"""
|
||||
RuleChecker 即判断是否响应消息的处理函数。
|
||||
"""PermissionChecker 即判断事件是否满足权限的处理函数。
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
|
||||
T_Handler = Callable[..., Any]
|
||||
"""
|
||||
Handler 处理函数。
|
||||
"""
|
||||
"""Handler 处理函数。"""
|
||||
T_TypeUpdater = Callable[..., Union[str, Awaitable[str]]]
|
||||
"""
|
||||
TypeUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新响应的事件类型。默认会更新为 `message`。
|
||||
"""TypeUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新响应的事件类型。默认会更新为 `message`。
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_PermissionUpdater = Callable[..., Union["Permission", Awaitable["Permission"]]]
|
||||
"""
|
||||
PermissionUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新会话对象权限。默认会更新为当前事件的触发对象。
|
||||
"""PermissionUpdater 在 Matcher.pause, Matcher.reject 时被运行,用于更新会话对象权限。默认会更新为当前事件的触发对象。
|
||||
|
||||
依赖参数:
|
||||
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
- DependParam: 子依赖参数
|
||||
- BotParam: Bot 对象
|
||||
- EventParam: Event 对象
|
||||
- StateParam: State 对象
|
||||
- MatcherParam: Matcher 对象
|
||||
- DefaultParam: 带有默认值的参数
|
||||
"""
|
||||
T_DependencyCache = Dict[Callable[..., Any], "Task[Any]"]
|
||||
"""
|
||||
依赖缓存, 用于存储依赖函数的返回值
|
||||
"""
|
||||
"""依赖缓存, 用于存储依赖函数的返回值"""
|
||||
|
@ -1,3 +1,10 @@
|
||||
"""本模块包含了 NoneBot 的一些工具函数
|
||||
|
||||
FrontMatter:
|
||||
sidebar_position: 8
|
||||
description: nonebot.utils 模块
|
||||
"""
|
||||
|
||||
import re
|
||||
import json
|
||||
import asyncio
|
||||
@ -30,8 +37,9 @@ V = TypeVar("V")
|
||||
|
||||
|
||||
def escape_tag(s: str) -> str:
|
||||
"""
|
||||
用于记录带颜色日志时转义 `<tag>` 类型特殊标签
|
||||
"""用于记录带颜色日志时转义 `<tag>` 类型特殊标签
|
||||
|
||||
参考: [loguru color 标签](https://loguru.readthedocs.io/en/stable/api/logger.html#color)
|
||||
|
||||
参数:
|
||||
s: 需要转义的字符串
|
||||
@ -42,6 +50,7 @@ def escape_tag(s: str) -> str:
|
||||
def generic_check_issubclass(
|
||||
cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...]]
|
||||
) -> bool:
|
||||
"""检查 cls 是否是 class_or_tuple 中的一个类型子类或"""
|
||||
try:
|
||||
return issubclass(cls, class_or_tuple)
|
||||
except TypeError:
|
||||
@ -59,6 +68,7 @@ def generic_check_issubclass(
|
||||
|
||||
|
||||
def is_coroutine_callable(call: Callable[..., Any]) -> bool:
|
||||
"""检查 call 是否是一个 callable 协程函数"""
|
||||
if inspect.isroutine(call):
|
||||
return inspect.iscoroutinefunction(call)
|
||||
if inspect.isclass(call):
|
||||
@ -68,6 +78,7 @@ def is_coroutine_callable(call: Callable[..., Any]) -> bool:
|
||||
|
||||
|
||||
def is_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
"""检查 call 是否是一个生成器函数"""
|
||||
if inspect.isgeneratorfunction(call):
|
||||
return True
|
||||
func_ = getattr(call, "__call__", None)
|
||||
@ -75,6 +86,7 @@ def is_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
|
||||
|
||||
def is_async_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
"""检查 call 是否是一个异步生成器函数"""
|
||||
if inspect.isasyncgenfunction(call):
|
||||
return True
|
||||
func_ = getattr(call, "__call__", None)
|
||||
@ -82,8 +94,7 @@ def is_async_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
|
||||
|
||||
def run_sync(call: Callable[P, R]) -> Callable[P, Awaitable[R]]:
|
||||
"""
|
||||
一个用于包装 sync function 为 async function 的装饰器
|
||||
"""一个用于包装 sync function 为 async function 的装饰器
|
||||
|
||||
参数:
|
||||
call: 被装饰的同步函数
|
||||
@ -103,6 +114,7 @@ def run_sync(call: Callable[P, R]) -> Callable[P, Awaitable[R]]:
|
||||
async def run_sync_ctx_manager(
|
||||
cm: ContextManager[T],
|
||||
) -> AsyncGenerator[T, None]:
|
||||
"""一个用于包装 sync context manager 为 async context manager 的执行函数"""
|
||||
try:
|
||||
yield await run_sync(cm.__enter__)()
|
||||
except Exception as e:
|
||||
@ -114,15 +126,14 @@ async def run_sync_ctx_manager(
|
||||
|
||||
|
||||
def get_name(obj: Any) -> str:
|
||||
"""获取对象的名称"""
|
||||
if inspect.isfunction(obj) or inspect.isclass(obj):
|
||||
return obj.__name__
|
||||
return obj.__class__.__name__
|
||||
|
||||
|
||||
class DataclassEncoder(json.JSONEncoder):
|
||||
"""
|
||||
在JSON序列化 `Message` (List[Dataclass]) 时使用的 `JSONEncoder`
|
||||
"""
|
||||
"""在JSON序列化 {re}`nonebot.adapters._message.Message` (List[Dataclass]) 时使用的 `JSONEncoder`"""
|
||||
|
||||
@overrides(json.JSONEncoder)
|
||||
def default(self, o):
|
||||
@ -131,14 +142,18 @@ class DataclassEncoder(json.JSONEncoder):
|
||||
return super().default(o)
|
||||
|
||||
|
||||
def logger_wrapper(logger_name: str):
|
||||
"""
|
||||
用于打印 adapter 的日志。
|
||||
def logger_wrapper(logger_name: str) -> Callable[[str, str, Optional[Exception]], None]:
|
||||
"""用于打印 adapter 的日志。
|
||||
|
||||
参数:
|
||||
level: 日志等级
|
||||
message: 日志信息
|
||||
exception: 异常信息
|
||||
logger_name: adapter 的名称
|
||||
|
||||
返回:
|
||||
日志记录函数
|
||||
|
||||
- level: 日志等级
|
||||
- message: 日志信息
|
||||
- exception: 异常信息
|
||||
"""
|
||||
|
||||
def log(level: str, message: str, exception: Optional[Exception] = None):
|
||||
|
Reference in New Issue
Block a user