diff --git a/archive/2.0.0a4/api/config.md b/archive/2.0.0a4/api/config.md deleted file mode 100644 index 6943427b..00000000 --- a/archive/2.0.0a4/api/config.md +++ /dev/null @@ -1,265 +0,0 @@ ---- -contentSidebar: true -sidebarDepth: 0 ---- - -# NoneBot.config 模块 - -## 配置 - -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/) 文档。 - - -## _class_ `Env` - -基类:`pydantic.env_settings.BaseSettings` - -运行环境配置。大小写不敏感。 - -将会从 `nonebot.init 参数` > `环境变量` > `.env 环境配置文件` 的优先级读取配置。 - - -### `environment` - - -* 类型: `str` - - -* 默认值: `"prod"` - - -* 说明: -当前环境名。 NoneBot 将从 `.env.{environment}` 文件中加载配置。 - - -## _class_ `Config` - -基类:`nonebot.config.BaseConfig` - -NoneBot 主要配置。大小写不敏感。 - -除了 NoneBot 的配置项外,还可以自行添加配置项到 `.env.{environment}` 文件中。 -这些配置将会在 json 反序列化后一起带入 `Config` 类中。 - - -### `driver` - - -* 类型: `str` - - -* 默认值: `"nonebot.drivers.fastapi"` - - -* 说明: -NoneBot 运行所使用的 `Driver` 。继承自 `nonebot.driver.BaseDriver` 。 - - -### `host` - - -* 类型: `IPvAnyAddress` - - -* 默认值: `127.0.0.1` - - -* 说明: -NoneBot 的 HTTP 和 WebSocket 服务端监听的 IP/主机名。 - - -### `port` - - -* 类型: `int` - - -* 默认值: `8080` - - -* 说明: -NoneBot 的 HTTP 和 WebSocket 服务端监听的端口。 - - -### `debug` - - -* 类型: `bool` - - -* 默认值: `False` - - -* 说明: -是否以调试模式运行 NoneBot。 - - -### `api_root` - - -* 类型: `Dict[str, str]` - - -* 默认值: `{}` - - -* 说明: -以机器人 ID 为键,上报地址为值的字典,环境变量或文件中应使用 json 序列化。 - - -* 示例: - -```default -API_ROOT={"123456": "http://127.0.0.1:5700"} -``` - - -### `api_timeout` - - -* 类型: `Optional[float]` - - -* 默认值: `30.` - - -* 说明: -API 请求超时时间,单位: 秒。 - - -### `access_token` - - -* 类型: `Optional[str]` - - -* 默认值: `None` - - -* 说明: -API 请求以及上报所需密钥,在请求头中携带。 - - -* 示例: - -```http -POST /cqhttp/ HTTP/1.1 -Authorization: Bearer kSLuTF2GC2Q4q4ugm3 -``` - - -### `secret` - - -* 类型: `Optional[str]` - - -* 默认值: `None` - - -* 说明: -HTTP POST 形式上报所需签名,在请求头中携带。 - - -* 示例: - -```http -POST /cqhttp/ HTTP/1.1 -X-Signature: sha1=f9ddd4863ace61e64f462d41ca311e3d2c1176e2 -``` - - -### `superusers` - - -* 类型: `Set[int]` - - -* 默认值: `set()` - - -* 说明: -机器人超级用户。 - - -* 示例: - -```default -SUPER_USERS=[12345789] -``` - - -### `nickname` - - -* 类型: `Set[str]` - - -* 默认值: `set()` - - -* 说明: -机器人昵称。 - - -### `command_start` - - -* 类型: `Set[str]` - - -* 默认值: `{"/"}` - - -* 说明: -命令的起始标记,用于判断一条消息是不是命令。 - - -### `command_sep` - - -* 类型: `Set[str]` - - -* 默认值: `{"."}` - - -* 说明: -命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。 - - -### `session_expire_timeout` - - -* 类型: `timedelta` - - -* 默认值: `timedelta(minutes=2)` - - -* 说明: -等待用户回复的超时时间。 - - -* 示例: - -```default -SESSION_EXPIRE_TIMEOUT=120 # 单位: 秒 -SESSION_EXPIRE_TIMEOUT=[DD ][HH:MM]SS[.ffffff] -SESSION_EXPIRE_TIMEOUT=P[DD]DT[HH]H[MM]M[SS]S # ISO 8601 -``` - - -### `apscheduler_config` - - -* 类型: `dict` - - -* 默认值: `{"apscheduler.timezone": "Asia/Shanghai"}` - - -* 说明: -APScheduler 的配置对象,见 [Configuring the Scheduler](https://apscheduler.readthedocs.io/en/latest/userguide.html#configuring-the-scheduler) diff --git a/archive/2.0.0a4/api/sched.md b/archive/2.0.0a4/api/sched.md deleted file mode 100644 index 450fd7d0..00000000 --- a/archive/2.0.0a4/api/sched.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -contentSidebar: true -sidebarDepth: 0 ---- - -# NoneBot.sched 模块 - -## 计划任务 - -计划任务使用第三方库 [APScheduler](https://github.com/agronholm/apscheduler) ,使用文档请参考 [APScheduler使用文档](https://apscheduler.readthedocs.io/en/latest/) 。 - - -## `scheduler` - - -* **类型** - - `Optional[apscheduler.schedulers.asyncio.AsyncIOScheduler]` - - - -* **说明** - - 当可选依赖 `APScheduler` 未安装时,`scheduler` 为 None - - 使用 `pip install nonebot[scheduler]` 安装可选依赖 - - - -* **常用示例** - - -```python -from nonebot import scheduler - -@scheduler.scheduled_job("cron", hour="*/2", id="xxx", args=[1], kwargs={arg2: 2}) -async def run_every_2_hour(arg1, arg2): - pass - -scheduler.add_job(run_every_day_from_program_start, "interval", days=1, id="xxx") -``` diff --git a/archive/2.0.0a4/guide/installation.md b/archive/2.0.0a4/guide/installation.md deleted file mode 100644 index 4f6e68e1..00000000 --- a/archive/2.0.0a4/guide/installation.md +++ /dev/null @@ -1,76 +0,0 @@ -# 安装 - -## NoneBot - -:::warning 注意 -请确保你的 Python 版本 >= 3.7。 -::: - -请在安装 nonebot2 之前卸载 nonebot 1.x - -```bash -pip uninstall nonebot -pip install nonebot2 -``` - -如果你需要使用最新的(可能尚未发布的)特性,可以克隆 Git 仓库后手动安装: - -```bash -git clone https://github.com/nonebot/nonebot2.git -cd nonebot2 -poetry install --no-dev # 推荐 -pip install . # 不推荐 -``` - -## 额外依赖 - -### APScheduler - -A task scheduling library for Python. - -可用于计划任务,后台执行任务等 - -```bash -pip install nonebot2[scheduler] -poetry add nonebot2[scheduler] -``` - -[View On GitHub](https://github.com/agronholm/apscheduler) - -### NoneBot-Test - -A test frontend for nonebot2. - -通过前端展示 nonebot 已加载的插件以及运行状态,同时可以用于模拟发送事件测试机器人 - -```bash -pip install nonebot2[test] -poetry add nonebot2[test] -``` - -[View On GitHub](https://github.com/nonebot/nonebot-test) - -### CLI - -CLI for nonebot2. - -一个多功能脚手架 - -```bash -pip install nonebot2[cli] -poetry add nonebot2[cli] -``` - -[View On GitHub](https://github.com/yanyongyu/nb-cli) - -### 我全都要 - -```bash -pip install nonebot2[full] -poetry add nonebot2[full] -``` - -```bash -pip install nonebot2[cli,scheduler] -poetry add nonebot2[cli,scheduler] -``` diff --git a/archive/2.0.0a4/guide/writing-a-plugin.md b/archive/2.0.0a4/guide/writing-a-plugin.md deleted file mode 100644 index 42657d9d..00000000 --- a/archive/2.0.0a4/guide/writing-a-plugin.md +++ /dev/null @@ -1,290 +0,0 @@ -# 编写插件 - -本章将以一个天气查询插件为例,教学如何编写自己的命令。 - -## 加载插件 - -在 [创建一个完整的项目](creating-a-project) 一章节中,我们已经创建了插件目录 `awesome_bot/plugins`,现在我们在机器人入口文件中加载它。当然,你也可以单独加载一个插件。 - -:::tip 提示 -加载插件目录时,目录下以 `_` 下划线开头的插件将不会被加载! -::: - -在 `bot.py` 文件中添加以下行: - -```python{5,7} -import nonebot - -nonebot.init() -# 加载单独的一个插件,参数为合法的python包名 -nonebot.load_plugin("nonebot.plugins.base") -# 加载插件目录,该目录下为各插件,以下划线开头的插件将不会被加载 -nonebot.load_plugins("awesome_bot/plugins") - -app = nonebot.get_asgi() - -if __name__ == "__main__": - nonebot.run() -``` - -尝试运行 `nb run` 或者 `python bot.py`,可以看到日志输出了类似如下内容: - -```plain -09-19 21:51:59 [INFO] nonebot | Succeeded to import "nonebot.plugins.base" -09-19 21:51:59 [INFO] nonebot | Succeeded to import "plugin_in_folder" -``` - -## 创建插件 - -现在我们已经有了一个空的插件目录,我们可以开始创建插件了!插件有两种形式 - -### 单文件形式 - -在插件目录下创建名为 `weather.py` 的 Python 文件,暂时留空,此时目录结构如下: - - -:::vue -AweSome-Bot -├── awesome_bot -│ └── plugins -│ └── `weather.py` -├── .env -├── .env.dev -├── .env.prod -├── .gitignore -├── bot.py -├── docker-compose.yml -├── Dockerfile -├── pyproject.toml -└── README.md -::: - - -这个时候它已经可以被称为一个插件了,尽管它还什么都没做。 - -### 包形式 - -在插件目录下创建文件夹 `weather`,并在该文件夹下创建文件 `__init__.py`,此时目录结构如下: - - -:::vue -AweSome-Bot -├── awesome_bot -│ └── plugins -│ └── `weather` -│ └── `__init__.py` -├── .env -├── .env.dev -├── .env.prod -├── .gitignore -├── bot.py -├── docker-compose.yml -├── Dockerfile -├── pyproject.toml -└── README.md -::: - - -这个时候 `weather` 就是一个合法的 Python 包了,同时也是合法的 NoneBot 插件,插件内容可以在 `__init__.py` 中编写。 - -## 编写真正的内容 - -好了,现在插件已经可以正确加载,我们可以开始编写命令的实际代码了。在 `weather.py` 中添加如下代码: - -```python -from nonebot import on_command -from nonebot.rule import to_me -from nonebot.adapters.cqhttp import Bot, Event - -weather = on_command("天气", rule=to_me(), priority=5) - - -@weather.handle() -async def handle_first_receive(bot: Bot, event: Event, state: dict): - args = str(event.message).strip() # 首次发送命令时跟随的参数,例:/天气 上海,则args为上海 - if args: - state["city"] = args # 如果用户发送了参数则直接赋值 - - -@weather.got("city", prompt="你想查询哪个城市的天气呢?") -async def handle_city(bot: Bot, event: Event, state: dict): - city = state["city"] - if city not in ["上海", "北京"]: - await weather.reject("你想查询的城市暂不支持,请重新输入!") - city_weather = await get_weather(city) - await weather.finish(city_weather) - - -async def get_weather(city: str): - return f"{city}的天气是..." -``` - -为了简单起见,我们在这里的例子中没有接入真实的天气数据,但要接入也非常简单,你可以使用中国天气网、和风天气等网站提供的 API。 - -下面我们来说明这段代码是如何工作的。 - -:::tip 提示 -从这里开始,你需要对 Python 的 asyncio 编程有所了解,因为 NoneBot 是完全基于 asyncio 的,具体可以参考 [廖雪峰的 Python 教程](https://www.liaoxuefeng.com/wiki/1016959663602400/1017959540289152) -::: - -### 注册一个 [事件响应器](../api/matcher.md) - -```python{4} -from nonebot import on_command -from nonebot.rule import to_me -from nonebot.permission import Permission - -weather = on_command("天气", rule=to_me(), permission=Permission(), priority=5) -``` - -在上方代码中,我们注册了一个事件响应器 `Matcher`,它由几个部分组成: - -1. `on_command` 注册一个消息类型的命令处理器 -2. `"天气"` 指定 command 参数 - 命令名 -3. `rule` 补充事件响应器的匹配规则 -4. `priority` 事件响应器优先级 -5. `block` 是否阻止事件传递 - -其他详细配置可以参考 API 文档,下面我们详细说明各个部分: - -#### 事件响应器类型 type - -事件响应器类型其实就是对应 `Event.type` ,NoneBot 提供了一个基础类型事件响应器 `on()` 以及一些内置的事件响应器。 - -- `on("事件类型")`: 基础事件响应器,第一个参数为事件类型,空字符串表示不限 -- `on_metaevent()` ~ `on("meta_event")`: 元事件响应器 -- `on_message()` ~ `on("message")`: 消息事件响应器 -- `on_request()` ~ `on("request")`: 请求事件响应器 -- `on_notice()` ~ `on("notice")`: 通知事件响应器 -- `on_startswith(str)` ~ `on("message", startswith(str))`: 消息开头匹配处理器 -- `on_endswith(str)` ~ `on("message", endswith(str))`: 消息结尾匹配处理器 -- `on_command(str|tuple)` ~ `on("message", command(str|tuple))`: 命令处理器 -- `on_regex(pattern_str)` ~ `on("message", regex(pattern_str))`: 正则匹配处理器 - -#### 匹配规则 rule - -事件响应器的匹配规则即 `Rule`,由非负个 `RuleChecker` 组成,当所有 `RuleChecker` 返回 `True` 时匹配成功。这些 `RuleChecker` 的形式如下: - -```python -async def check(bot: Bot, event: Event, state: dict) -> bool: - return True - -def check(bot: Bot, event: Event, state: dict) -> bool: - return True -``` - -`Rule` 和 `RuleChecker` 之间可以使用 `与 &` 互相组合: - -```python -from nonebot.rule import Rule - -Rule(async_checker1) & sync_checker & async_checker2 -``` - -:::danger 警告 -`Rule(*checkers)` 只接受 async function,或使用 `nonebot.utils.run_sync` 自行包裹 sync function。在使用 `与 &` 时,NoneBot 会自动包裹 sync function -::: - -#### 优先级 priority - -事件响应器的优先级代表事件响应器的执行顺序,同一优先级的事件响应器会 **同时执行!** - -:::tip 提示 -使用 `nonebot-test` 可以看到当前所有事件响应器的执行流程,有助理解事件响应流程! - -```bash -pip install nonebot2[test] -``` - -::: - -#### 阻断 block - -当有任意事件响应器发出了阻止事件传递信号时,该事件将不再会传递给下一优先级,直接结束处理。 - -NoneBot 内置的事件响应器中,所有 `message` 类的事件响应器默认会阻断事件传递,其他则不会。 - -### 编写事件处理函数 [Handler](../api/typing.md#handler) - -```python{1,2,8,9} -@weather.handle() -async def handle_first_receive(bot: Bot, event: Event, state: dict): - args = str(event.message).strip() # 首次发送命令时跟随的参数,例:/天气 上海,则args为上海 - if args: - state["city"] = args # 如果用户发送了参数则直接赋值 - - -@weather.got("city", prompt="你想查询哪个城市的天气呢?") -async def handle_city(bot: Bot, event: Event, state: dict): - city = state["city"] - if city not in ["上海", "北京"]: - await weather.reject("你想查询的城市暂不支持,请重新输入!") - city_weather = await get_weather(city) - await weather.finish(city_weather) -``` - -在上面的代码中,我们给 `weather` 事件响应器添加了两个事件处理函数:`handle_first_receive`, `handle_city` - -其中有几个要点,我们一一解释: - -#### 添加一个事件处理函数 - -在事件响应器响应事件时,事件处理函数会依次顺序执行,也就是说,与添加顺序一致。 - -我们可以使用 `@matcher.handle()` 装饰器来简单地为该事件响应器添加一个处理函数。 - -同时,NoneBot 内置了几种添加事件处理函数方式以方便处理: - -- `@matcher.receive()`: 指示 NoneBot 接收一条新的用户消息以继续执行后续处理函数。 -- `@matcher.got(key, [prompt="请输入key"], [args_parser=function])`: 指示 NoneBot 当 `state` 中不存在 `key` 时向用户发送 `prompt` 等待用户回复并赋值给 `state[key]` - -这些装饰器可以套娃使用!例如: - -```python -@matcher.got("key1") -@matcher.got("key2") -async def handle(bot: Bot, event: Event, state: dict): - pass -``` - -#### 事件处理函数参数 - -事件处理函数类型为 `Callable[[Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]` 。 - -参数分别为: - -1. [nonebot.typing.Bot](../api/typing.md#bot): 即事件上报连接对应的 Bot 对象,为 BaseBot 的子类。特别注意,此处的类型注释可以替换为指定的 Bot 类型,例如:`nonebot.adapters.cqhttp.Bot`,只有在上报事件的 Bot 类型与类型注释相符时才会执行该处理函数!可用于多平台进行不同的处理。 -2. [nonebot.typing.Event](../api/typing.md#event): 即上报事件对象,可以获取到上报的所有信息。 -3. `state`: 状态字典,可以存储任意的信息 - -#### 处理事件 - -在事件处理函数中,我们只需要对 `event` 做出相应的处理,存入状态字典 `state` 中,或者向用户发送消息、调用某个机器人 API 等等。 - -在 NoneBot 中,提供了几种特殊的处理函数: - -##### `@matcher.args_parser` - -这是一个装饰器,装饰一个函数来使它成为参数的默认解析函数,当使用 `matcher.got(xxx, [args_parser])` 获取到一条消息时,会运行 `matcher.got` 的 `args_parser` ,如果不存在则运行 `@matcher.args_parser`。 - -##### `matcher.pause` - -这个函数用于结束当前事件处理函数,强制接收一条新的消息再运行**下一个消息处理函数**。 - -##### `matcher.reject` - -这个函数用于结束当前事件处理函数,强制接收一条新的消息再**再次运行当前消息处理函数**。 - -##### `matcher.finish` - -这个函数用于直接结束当前事件处理。 - -以上三个函数都拥有一个参数 `prompt`,用于向用户发送一条消息。 - -## 结语 - -至此,相信你已经能够写出一个基础的插件了,更多的用法将会在 进阶 部分进行介绍,这里给出几个小提示: - -- 请千万注意事件处理器的优先级设定 -- 在匹配规则中请勿使用耗时极长的函数 -- 同一个用户可以跨群(私聊)继续他的事件处理(除非做出权限限制,将在后续介绍) diff --git a/archive/2.0.0a4/README.md b/archive/2.0.0a7/README.md similarity index 89% rename from archive/2.0.0a4/README.md rename to archive/2.0.0a7/README.md index e568de9f..c093eb5c 100644 --- a/archive/2.0.0a4/README.md +++ b/archive/2.0.0a7/README.md @@ -3,7 +3,7 @@ home: true heroImage: /logo.png tagline: An asynchronous QQ bot framework. actionText: 开始使用 -actionLink: /guide/ +actionLink: guide/ features: - title: 简洁 details: 提供极其简洁易懂的 API,使你可以毫无压力地开始验证你的绝佳创意,只需编写最少量的代码,即可实现丰富的功能。 @@ -11,5 +11,5 @@ features: details: 精心设计的消息处理流程使得你可以很方便地将原型扩充为具有大量实用功能的完整聊天机器人,并持续保证扩展性。 - title: 高性能 details: 采用异步 I/O,利用 WebSocket 进行通信,以获得极高的性能;同时,支持使用多账号同时接入,减少业务宕机的可能。 -footer: MIT Licensed | Copyright © 2020 NoneBot Team +footer: MIT Licensed | Copyright © 2018 - 2020 NoneBot Team --- diff --git a/archive/2.0.0a7/advanced/README.md b/archive/2.0.0a7/advanced/README.md new file mode 100644 index 00000000..92c6af3e --- /dev/null +++ b/archive/2.0.0a7/advanced/README.md @@ -0,0 +1,7 @@ +# 深入 + +## 它如何工作? + + + +~~未填坑~~ diff --git a/archive/2.0.0a7/advanced/export-and-require.md b/archive/2.0.0a7/advanced/export-and-require.md new file mode 100644 index 00000000..832b0e75 --- /dev/null +++ b/archive/2.0.0a7/advanced/export-and-require.md @@ -0,0 +1 @@ +# 跨插件访问 diff --git a/archive/2.0.0a7/advanced/permission.md b/archive/2.0.0a7/advanced/permission.md new file mode 100644 index 00000000..7190bcdd --- /dev/null +++ b/archive/2.0.0a7/advanced/permission.md @@ -0,0 +1 @@ +# 权限控制 diff --git a/archive/2.0.0a7/advanced/publish-plugin.md b/archive/2.0.0a7/advanced/publish-plugin.md new file mode 100644 index 00000000..68e2e6f9 --- /dev/null +++ b/archive/2.0.0a7/advanced/publish-plugin.md @@ -0,0 +1 @@ +# 发布插件 diff --git a/archive/2.0.0a7/advanced/runtime-hook.md b/archive/2.0.0a7/advanced/runtime-hook.md new file mode 100644 index 00000000..58bca681 --- /dev/null +++ b/archive/2.0.0a7/advanced/runtime-hook.md @@ -0,0 +1 @@ +# 运行时插槽 diff --git a/archive/2.0.0a7/advanced/scheduler.md b/archive/2.0.0a7/advanced/scheduler.md new file mode 100644 index 00000000..53e6cedc --- /dev/null +++ b/archive/2.0.0a7/advanced/scheduler.md @@ -0,0 +1 @@ +# 定时任务 diff --git a/archive/2.0.0a4/api/README.md b/archive/2.0.0a7/api/README.md similarity index 87% rename from archive/2.0.0a4/api/README.md rename to archive/2.0.0a7/api/README.md index dcfb548c..243733f8 100644 --- a/archive/2.0.0a4/api/README.md +++ b/archive/2.0.0a7/api/README.md @@ -13,6 +13,9 @@ * [nonebot.plugin](plugin.html) + * [nonebot.message](message.html) + + * [nonebot.matcher](matcher.html) @@ -22,9 +25,6 @@ * [nonebot.permission](permission.html) - * [nonebot.sched](sched.html) - - * [nonebot.log](log.html) @@ -47,3 +47,6 @@ * [nonebot.adapters.cqhttp](adapters/cqhttp.html) + + + * [nonebot.adapters.ding](adapters/ding.html) diff --git a/archive/2.0.0a4/api/adapters/README.md b/archive/2.0.0a7/api/adapters/README.md similarity index 79% rename from archive/2.0.0a4/api/adapters/README.md rename to archive/2.0.0a7/api/adapters/README.md index f3f937ec..1a1dd85b 100644 --- a/archive/2.0.0a4/api/adapters/README.md +++ b/archive/2.0.0a7/api/adapters/README.md @@ -69,6 +69,45 @@ Websocket 连接对象 Adapter 类型 +### _abstract async classmethod_ `check_permission(driver, connection_type, headers, body)` + + +* **说明** + + 检查连接请求是否合法的函数,如果合法则返回当前连接 `唯一标识符`,通常为机器人 ID;如果不合法则抛出 `RequestDenied` 异常。 + + + +* **参数** + + + * `driver: Driver`: Driver 对象 + + + * `connection_type: str`: 连接类型 + + + * `headers: dict`: 请求头 + + + * `body: Optional[dict]`: 请求数据,WebSocket 连接该部分为空 + + + +* **返回** + + + * `str`: 连接唯一标识符 + + + +* **异常** + + + * `RequestDenied`: 请求非法 + + + ### _abstract async_ `handle_message(message)` @@ -108,7 +147,7 @@ Adapter 类型 ```python -await bot.call_api("send_msg", data={"message": "hello world"}) +await bot.call_api("send_msg", message="hello world"}) await bot.send_msg(message="hello world") ``` @@ -137,7 +176,7 @@ await bot.send_msg(message="hello world") ## _class_ `BaseEvent` -基类:`abc.ABC` +基类:`abc.ABC`, `typing.Generic` Event 基类。提供上报信息的关键信息,其余信息可从原始上报消息获取。 @@ -148,7 +187,7 @@ Event 基类。提供上报信息的关键信息,其余信息可从原始上 * **参数** - * `raw_event: dict`: 原始上报消息 + * `raw_event: Union[dict, T]`: 原始上报消息 @@ -270,7 +309,7 @@ Event 基类。提供上报信息的关键信息,其余信息可从原始上 * **参数** - * `message: Union[str, dict, list, MessageSegment, Message]`: 消息内容 + * `message: Union[str, dict, list, BaseModel, MessageSegment, Message]`: 消息内容 @@ -311,7 +350,7 @@ Event 基类。提供上报信息的关键信息,其余信息可从原始上 * **说明** - 缩减消息数组,即拼接相邻纯文本消息段 + 缩减消息数组,即按 MessageSegment 的实现拼接相邻消息段 diff --git a/archive/2.0.0a4/api/adapters/cqhttp.md b/archive/2.0.0a7/api/adapters/cqhttp.md similarity index 74% rename from archive/2.0.0a4/api/adapters/cqhttp.md rename to archive/2.0.0a7/api/adapters/cqhttp.md index 73b4e044..b80d6ad1 100644 --- a/archive/2.0.0a4/api/adapters/cqhttp.md +++ b/archive/2.0.0a7/api/adapters/cqhttp.md @@ -5,29 +5,6 @@ sidebarDepth: 0 # NoneBot.adapters.cqhttp 模块 -## CQHTTP (OneBot) v11 协议适配 - -协议详情请看: [CQHTTP](http://cqhttp.cc/) | [OneBot](https://github.com/howmanybots/onebot) - - -## `log(level, message)` - - -* **说明** - - 用于打印 CQHTTP 日志。 - - - -* **参数** - - - * `level: str`: 日志等级 - - - * `message: str`: 日志信息 - - ## `escape(s, *, escape_comma=True)` @@ -64,9 +41,50 @@ sidebarDepth: 0 -## `_b2s(b)` +## _exception_ `CQHTTPAdapterException` -转换布尔值为字符串。 +基类:[`nonebot.exception.AdapterException`](../exception.md#nonebot.exception.AdapterException) + + +## _exception_ `ActionFailed` + +基类:[`nonebot.exception.ActionFailed`](../exception.md#nonebot.exception.ActionFailed), `nonebot.adapters.cqhttp.exception.CQHTTPAdapterException` + + +* **说明** + + API 请求返回错误信息。 + + + +* **参数** + + + * `retcode: Optional[int]`: 错误码 + + + +## _exception_ `NetworkError` + +基类:[`nonebot.exception.NetworkError`](../exception.md#nonebot.exception.NetworkError), `nonebot.adapters.cqhttp.exception.CQHTTPAdapterException` + + +* **说明** + + 网络错误。 + + + +* **参数** + + + * `retcode: Optional[int]`: 错误码 + + + +## _exception_ `ApiNotAvailable` + +基类:[`nonebot.exception.ApiNotAvailable`](../exception.md#nonebot.exception.ApiNotAvailable), `nonebot.adapters.cqhttp.exception.CQHTTPAdapterException` ## _async_ `_check_reply(bot, event)` @@ -158,7 +176,7 @@ sidebarDepth: 0 ## _class_ `Bot` -基类:[`nonebot.adapters.BaseBot`](#None) +基类:[`nonebot.adapters.BaseBot`](README.md#nonebot.adapters.BaseBot) CQHTTP 协议 Bot 适配。继承属性参考 [BaseBot](./#class-basebot) 。 @@ -169,6 +187,15 @@ CQHTTP 协议 Bot 适配。继承属性参考 [BaseBot](./#class-basebot) 。 * 返回: `"cqhttp"` +### _async classmethod_ `check_permission(driver, connection_type, headers, body)` + + +* **说明** + + CQHTTP (OneBot) 协议鉴权。参考 [鉴权](https://github.com/howmanybots/onebot/blob/master/v11/specs/communication/authorization.md) + + + ### _async_ `handle_message(message)` @@ -261,7 +288,7 @@ CQHTTP 协议 Bot 适配。继承属性参考 [BaseBot](./#class-basebot) 。 ## _class_ `Event` -基类:[`nonebot.adapters.BaseEvent`](#None) +基类:[`nonebot.adapters.BaseEvent`](README.md#nonebot.adapters.BaseEvent) CQHTTP 协议 Event 适配。继承属性参考 [BaseEvent](./#class-baseevent) 。 @@ -403,13 +430,13 @@ CQHTTP 协议 Event 适配。继承属性参考 [BaseEvent](./#class-baseevent) ## _class_ `MessageSegment` -基类:[`nonebot.adapters.BaseMessageSegment`](#None) +基类:[`nonebot.adapters.BaseMessageSegment`](README.md#nonebot.adapters.BaseMessageSegment) CQHTTP 协议 MessageSegment 适配。具体方法参考协议消息段类型或源码。 ## _class_ `Message` -基类:[`nonebot.adapters.BaseMessage`](#None) +基类:[`nonebot.adapters.BaseMessage`](README.md#nonebot.adapters.BaseMessage) CQHTTP 协议 Message 适配。 diff --git a/archive/2.0.0a7/api/adapters/ding.md b/archive/2.0.0a7/api/adapters/ding.md new file mode 100644 index 00000000..0bbdd6d8 --- /dev/null +++ b/archive/2.0.0a7/api/adapters/ding.md @@ -0,0 +1,380 @@ +--- +contentSidebar: true +sidebarDepth: 0 +--- + +# NoneBot.adapters.ding 模块 + + +## _exception_ `DingAdapterException` + +基类:[`nonebot.exception.AdapterException`](../exception.md#nonebot.exception.AdapterException) + + +* **说明** + + 钉钉 Adapter 错误基类 + + + +## _exception_ `ActionFailed` + +基类:[`nonebot.exception.ActionFailed`](../exception.md#nonebot.exception.ActionFailed), `nonebot.adapters.ding.exception.DingAdapterException` + + +* **说明** + + API 请求返回错误信息。 + + + +* **参数** + + + * `errcode: Optional[int]`: 错误码 + + + * `errmsg: Optional[str]`: 错误信息 + + + +## _exception_ `ApiNotAvailable` + +基类:[`nonebot.exception.ApiNotAvailable`](../exception.md#nonebot.exception.ApiNotAvailable), `nonebot.adapters.ding.exception.DingAdapterException` + + +## _exception_ `NetworkError` + +基类:[`nonebot.exception.NetworkError`](../exception.md#nonebot.exception.NetworkError), `nonebot.adapters.ding.exception.DingAdapterException` + + +* **说明** + + 网络错误。 + + + +* **参数** + + + * `retcode: Optional[int]`: 错误码 + + + +## _exception_ `SessionExpired` + +基类:[`nonebot.exception.ApiNotAvailable`](../exception.md#nonebot.exception.ApiNotAvailable), `nonebot.adapters.ding.exception.DingAdapterException` + + +* **说明** + + 发消息的 session 已经过期。 + + + +## _class_ `Bot` + +基类:[`nonebot.adapters.BaseBot`](README.md#nonebot.adapters.BaseBot) + +钉钉 协议 Bot 适配。继承属性参考 [BaseBot](./#class-basebot) 。 + + +### _property_ `type` + + +* 返回: `"ding"` + + +### _async classmethod_ `check_permission(driver, connection_type, headers, body)` + + +* **说明** + + 钉钉协议鉴权。参考 [鉴权](https://ding-doc.dingtalk.com/doc#/serverapi2/elzz1p) + + + +### _async_ `handle_message(body)` + + +* **说明** + + 处理上报消息的函数,转换为 `Event` 事件后调用 `nonebot.message.handle_event` 进一步处理事件。 + + + +* **参数** + + + * `message: dict`: 收到的上报消息 + + + +### _async_ `call_api(api, event=None, **data)` + + +* **说明** + + 调用 钉钉 协议 API + + + +* **参数** + + + * `api: str`: API 名称 + + + * `**data: Any`: API 参数 + + + +* **返回** + + + * `Any`: API 调用返回数据 + + + +* **异常** + + + * `NetworkError`: 网络错误 + + + * `ActionFailed`: API 调用失败 + + + +### _async_ `send(event, message, at_sender=False, **kwargs)` + + +* **说明** + + 根据 `event` 向触发事件的主体发送消息。 + + + +* **参数** + + + * `event: Event`: Event 对象 + + + * `message: Union[str, Message, MessageSegment]`: 要发送的消息 + + + * `at_sender: bool`: 是否 @ 事件主体 + + + * `**kwargs`: 覆盖默认参数 + + + +* **返回** + + + * `Any`: API 调用返回数据 + + + +* **异常** + + + * `ValueError`: 缺少 `user_id`, `group_id` + + + * `NetworkError`: 网络错误 + + + * `ActionFailed`: API 调用失败 + + + +## _class_ `Event` + +基类:[`nonebot.adapters.BaseEvent`](README.md#nonebot.adapters.BaseEvent) + +钉钉 协议 Event 适配。继承属性参考 [BaseEvent](./#class-baseevent) 。 + + +### _property_ `raw_event` + +原始上报消息 + + +### _property_ `id` + + +* 类型: `Optional[str]` + + +* 说明: 消息 ID + + +### _property_ `name` + + +* 类型: `str` + + +* 说明: 事件名称,由 type.\`detail_type\` 组合而成 + + +### _property_ `self_id` + + +* 类型: `str` + + +* 说明: 机器人自身 ID + + +### _property_ `time` + + +* 类型: `int` + + +* 说明: 消息的时间戳,单位 s + + +### _property_ `type` + + +* 类型: `str` + + +* 说明: 事件类型 + + +### _property_ `detail_type` + + +* 类型: `str` + + +* 说明: 事件详细类型 + + +### _property_ `sub_type` + + +* 类型: `None` + + +* 说明: 钉钉适配器无事件子类型 + + +### _property_ `user_id` + + +* 类型: `Optional[str]` + + +* 说明: 发送者 ID + + +### _property_ `group_id` + + +* 类型: `Optional[str]` + + +* 说明: 事件主体群 ID + + +### _property_ `to_me` + + +* 类型: `Optional[bool]` + + +* 说明: 消息是否与机器人相关 + + +### _property_ `message` + + +* 类型: `Optional[Message]` + + +* 说明: 消息内容 + + +### _property_ `reply` + + +* 类型: `None` + + +* 说明: 回复消息详情 + + +### _property_ `raw_message` + + +* 类型: `Optional[str]` + + +* 说明: 原始消息 + + +### _property_ `plain_text` + + +* 类型: `Optional[str]` + + +* 说明: 纯文本消息内容 + + +### _property_ `sender` + + +* 类型: `Optional[dict]` + + +* 说明: 消息发送者信息 + + +## _class_ `MessageSegment` + +基类:[`nonebot.adapters.BaseMessageSegment`](README.md#nonebot.adapters.BaseMessageSegment) + +钉钉 协议 MessageSegment 适配。具体方法参考协议消息段类型或源码。 + + +### _static_ `actionCardSingleMultiBtns(title, text, btns=[], hideAvatar=False, btnOrientation='1')` + + +* **参数** + + + * `btnOrientation`: 0:按钮竖直排列 1:按钮横向排列 + + + * `btns`: [{ "title": title, "actionURL": actionURL }, ...] + + + +### _static_ `feedCard(links=[])` + + +* **参数** + + + * `links`: [{ "title": xxx, "messageURL": xxx, "picURL": xxx }, ...] + + + +### _static_ `empty()` + +不想回复消息到群里 + + +## _class_ `Message` + +基类:[`nonebot.adapters.BaseMessage`](README.md#nonebot.adapters.BaseMessage) + +钉钉 协议 Message 适配。 diff --git a/archive/2.0.0a7/api/config.md b/archive/2.0.0a7/api/config.md new file mode 100644 index 00000000..f2eaa4d4 --- /dev/null +++ b/archive/2.0.0a7/api/config.md @@ -0,0 +1,285 @@ +--- +contentSidebar: true +sidebarDepth: 0 +--- + +# NoneBot.config 模块 + +## 配置 + +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/) 文档。 + + +## _class_ `Env` + +基类:`pydantic.env_settings.BaseSettings` + +运行环境配置。大小写不敏感。 + +将会从 `nonebot.init 参数` > `环境变量` > `.env 环境配置文件` 的优先级读取配置。 + + +### `environment` + + +* **类型**: `str` + + +* **默认值**: `"prod"` + + +* **说明** + + 当前环境名。 NoneBot 将从 `.env.{environment}` 文件中加载配置。 + + + +## _class_ `Config` + +基类:`nonebot.config.BaseConfig` + +NoneBot 主要配置。大小写不敏感。 + +除了 NoneBot 的配置项外,还可以自行添加配置项到 `.env.{environment}` 文件中。 +这些配置将会在 json 反序列化后一起带入 `Config` 类中。 + + +### `driver` + + +* **类型**: `str` + + +* **默认值**: `"nonebot.drivers.fastapi"` + + +* **说明** + + NoneBot 运行所使用的 `Driver` 。继承自 `nonebot.driver.BaseDriver` 。 + + + +### `host` + + +* **类型**: `IPvAnyAddress` + + +* **默认值**: `127.0.0.1` + + +* **说明** + + NoneBot 的 HTTP 和 WebSocket 服务端监听的 IP/主机名。 + + + +### `port` + + +* **类型**: `int` + + +* **默认值**: `8080` + + +* **说明** + + NoneBot 的 HTTP 和 WebSocket 服务端监听的端口。 + + + +### `debug` + + +* **类型**: `bool` + + +* **默认值**: `False` + + +* **说明** + + 是否以调试模式运行 NoneBot。 + + + +### `api_root` + + +* **类型**: `Dict[str, str]` + + +* **默认值**: `{}` + + +* **说明** + + 以机器人 ID 为键,上报地址为值的字典,环境变量或文件中应使用 json 序列化。 + + + +* **示例** + + +```default +API_ROOT={"123456": "http://127.0.0.1:5700"} +``` + + +### `api_timeout` + + +* **类型**: `Optional[float]` + + +* **默认值**: `30.` + + +* **说明** + + API 请求超时时间,单位: 秒。 + + + +### `access_token` + + +* **类型**: `Optional[str]` + + +* **默认值**: `None` + + +* **说明** + + API 请求以及上报所需密钥,在请求头中携带。 + + + +* **示例** + + +```http +POST /cqhttp/ HTTP/1.1 +Authorization: Bearer kSLuTF2GC2Q4q4ugm3 +``` + + +### `secret` + + +* **类型**: `Optional[str]` + + +* **默认值**: `None` + + +* **说明** + + HTTP POST 形式上报所需签名,在请求头中携带。 + + + +* **示例** + + +```http +POST /cqhttp/ HTTP/1.1 +X-Signature: sha1=f9ddd4863ace61e64f462d41ca311e3d2c1176e2 +``` + + +### `superusers` + + +* **类型**: `Set[int]` + + +* **默认值**: `set()` + + +* **说明** + + 机器人超级用户。 + + + +* **示例** + + +```default +SUPER_USERS=[12345789] +``` + + +### `nickname` + + +* **类型**: `Set[str]` + + +* **默认值**: `set()` + + +* **说明** + + 机器人昵称。 + + + +### `command_start` + + +* **类型**: `Set[str]` + + +* **默认值**: `{"/"}` + + +* **说明** + + 命令的起始标记,用于判断一条消息是不是命令。 + + + +### `command_sep` + + +* **类型**: `Set[str]` + + +* **默认值**: `{"."}` + + +* **说明** + + 命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。 + + + +### `session_expire_timeout` + + +* **类型**: `timedelta` + + +* **默认值**: `timedelta(minutes=2)` + + +* **说明** + + 等待用户回复的超时时间。 + + + +* **示例** + + +```default +SESSION_EXPIRE_TIMEOUT=120 # 单位: 秒 +SESSION_EXPIRE_TIMEOUT=[DD ][HH:MM]SS[.ffffff] +SESSION_EXPIRE_TIMEOUT=P[DD]DT[HH]H[MM]M[SS]S # ISO 8601 +``` diff --git a/archive/2.0.0a4/api/drivers/README.md b/archive/2.0.0a7/api/drivers/README.md similarity index 100% rename from archive/2.0.0a4/api/drivers/README.md rename to archive/2.0.0a7/api/drivers/README.md diff --git a/archive/2.0.0a4/api/drivers/fastapi.md b/archive/2.0.0a7/api/drivers/fastapi.md similarity index 67% rename from archive/2.0.0a4/api/drivers/fastapi.md rename to archive/2.0.0a7/api/drivers/fastapi.md index 523b09b2..b4f5c6fb 100644 --- a/archive/2.0.0a4/api/drivers/fastapi.md +++ b/archive/2.0.0a7/api/drivers/fastapi.md @@ -12,22 +12,25 @@ sidebarDepth: 0 ## _class_ `Driver` -基类:[`nonebot.drivers.BaseDriver`](#None) +基类:[`nonebot.drivers.BaseDriver`](README.md#nonebot.drivers.BaseDriver) FastAPI 驱动框架 -### `__init__(env, config)` +* **上报地址** + + + * `/{adapter name}/`: HTTP POST 上报 -* **参数** + * `/{adapter name}/http/`: HTTP POST 上报 - -* `env: Env`: 包含环境信息的 Env 对象 + * `/{adapter name}/ws`: WebSocket 上报 -* `config: Config`: 包含配置信息的 Config 对象 + * `/{adapter name}/ws/`: WebSocket 上报 + ### _property_ `type` @@ -65,29 +68,19 @@ fastapi 使用的 logger 使用 `uvicorn` 启动 FastAPI -### _async_ `_handle_http(adapter, data=Body(Ellipsis), x_self_id=Header(None), x_signature=Header(None), auth=Depends(get_auth_bearer))` +### _async_ `_handle_http(adapter, request, data=Body(Ellipsis))` 用于处理 HTTP 类型请求的函数 -### _async_ `_handle_ws_reverse(adapter, websocket, x_self_id=Header(None), auth=Depends(get_auth_bearer))` +### _async_ `_handle_ws_reverse(adapter, websocket)` 用于处理 WebSocket 类型请求的函数 ## _class_ `WebSocket` -基类:[`nonebot.drivers.BaseWebSocket`](#None) - - -### `__init__(websocket)` - - -* **参数** - - - -* `websocket: Any`: WebSocket 连接对象 +基类:[`nonebot.drivers.BaseWebSocket`](README.md#nonebot.drivers.BaseWebSocket) ### _property_ `closed` diff --git a/archive/2.0.0a4/api/exception.md b/archive/2.0.0a7/api/exception.md similarity index 66% rename from archive/2.0.0a4/api/exception.md rename to archive/2.0.0a7/api/exception.md index 2c7abad1..0c584f75 100644 --- a/archive/2.0.0a4/api/exception.md +++ b/archive/2.0.0a7/api/exception.md @@ -11,11 +11,22 @@ sidebarDepth: 0 这些异常并非所有需要用户处理,在 NoneBot 内部运行时被捕获,并进行对应操作。 -## _exception_ `IgnoredException` +## _exception_ `NoneBotException` 基类:`Exception` +* **说明** + + 所有 NoneBot 发生的异常基类。 + + + +## _exception_ `IgnoredException` + +基类:`nonebot.exception.NoneBotException` + + * **说明** 指示 NoneBot 应该忽略该事件。可由 PreProcessor 抛出。 @@ -31,7 +42,7 @@ sidebarDepth: 0 ## _exception_ `PausedException` -基类:`Exception` +基类:`nonebot.exception.NoneBotException` * **说明** @@ -49,7 +60,7 @@ sidebarDepth: 0 ## _exception_ `RejectedException` -基类:`Exception` +基类:`nonebot.exception.NoneBotException` * **说明** @@ -67,7 +78,7 @@ sidebarDepth: 0 ## _exception_ `FinishedException` -基类:`Exception` +基类:`nonebot.exception.NoneBotException` * **说明** @@ -83,26 +94,9 @@ sidebarDepth: 0 -## _exception_ `ExpiredException` - -基类:`Exception` - - -* **说明** - - 指示 NoneBot 当前 `Matcher` 已失效。 - - - -* **用法** - - 当 `Matcher` 运行前检查时抛出。 - - - ## _exception_ `StopPropagation` -基类:`Exception` +基类:`nonebot.exception.NoneBotException` * **说明** @@ -117,9 +111,48 @@ sidebarDepth: 0 +## _exception_ `RequestDenied` + +基类:`nonebot.exception.NoneBotException` + + +* **说明** + + Bot 连接请求不合法。 + + + +* **参数** + + + * `status_code: int`: HTTP 状态码 + + + * `reason: str`: 拒绝原因 + + + +## _exception_ `AdapterException` + +基类:`nonebot.exception.NoneBotException` + + +* **说明** + + 代表 `Adapter` 抛出的异常,所有的 `Adapter` 都要在内部继承自这个 `Exception` + + + +* **参数** + + + * `adapter_name: str`: 标识 adapter + + + ## _exception_ `ApiNotAvailable` -基类:`Exception` +基类:`nonebot.exception.AdapterException` * **说明** @@ -130,7 +163,7 @@ sidebarDepth: 0 ## _exception_ `NetworkError` -基类:`Exception` +基类:`nonebot.exception.AdapterException` * **说明** @@ -141,16 +174,9 @@ sidebarDepth: 0 ## _exception_ `ActionFailed` -基类:`Exception` +基类:`nonebot.exception.AdapterException` * **说明** API 请求成功返回数据,但 API 操作失败。 - - - -* **参数** - - - * `retcode`: 错误代码 diff --git a/archive/2.0.0a4/api/log.md b/archive/2.0.0a7/api/log.md similarity index 100% rename from archive/2.0.0a4/api/log.md rename to archive/2.0.0a7/api/log.md diff --git a/archive/2.0.0a4/api/matcher.md b/archive/2.0.0a7/api/matcher.md similarity index 86% rename from archive/2.0.0a4/api/matcher.md rename to archive/2.0.0a7/api/matcher.md index b061cd64..9e72b658 100644 --- a/archive/2.0.0a4/api/matcher.md +++ b/archive/2.0.0a7/api/matcher.md @@ -450,48 +450,3 @@ sidebarDepth: 0 * `**kwargs`: 其他传递给 `bot.send` 的参数,请参考对应 adapter 的 bot 对象 api - - - -## _class_ `MatcherGroup` - -基类:`object` - -事件响应器组合,统一管理。用法同 `Matcher` - - -### `__init__(type_='', rule=None, permission=None, handlers=None, temp=False, priority=1, block=False, *, module=None, default_state=None, expire_time=None)` - - -* **说明** - - 创建一个事件响应器组合,参数为默认值,与 `Matcher.new` 一致 - - - -### `matchers` - - -* **类型** - - `List[Type[Matcher]]` - - - -* **说明** - - 组内事件响应器列表 - - - -### `new(type_='', rule=None, permission=None, handlers=None, temp=False, priority=1, block=False, *, module=None, default_state=None, expire_time=None)` - - -* **说明** - - 在组中创建一个新的事件响应器,参数留空则使用组合默认值 - - -:::danger 警告 -如果使用 handlers 参数覆盖组合默认值则该事件响应器不会随组合一起添加新的事件处理函数 -::: diff --git a/archive/2.0.0a7/api/message.md b/archive/2.0.0a7/api/message.md new file mode 100644 index 00000000..c9d7c158 --- /dev/null +++ b/archive/2.0.0a7/api/message.md @@ -0,0 +1,143 @@ +--- +contentSidebar: true +sidebarDepth: 0 +--- + +# NoneBot.message 模块 + +## 事件处理 + +NoneBot 内部处理并按优先级分发事件给所有事件响应器,提供了多个插槽以进行事件的预处理等。 + + +## `event_preprocessor(func)` + + +* **说明** + + 事件预处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之前执行。 + + + +* **参数** + + 事件预处理函数接收三个参数。 + + + * `bot: Bot`: Bot 对象 + + + * `event: Event`: Event 对象 + + + * `state: dict`: 当前 State + + + +## `event_postprocessor(func)` + + +* **说明** + + 事件后处理。装饰一个函数,使它在每次接收到事件并分发给各响应器之后执行。 + + + +* **参数** + + 事件后处理函数接收三个参数。 + + + * `bot: Bot`: Bot 对象 + + + * `event: Event`: Event 对象 + + + * `state: dict`: 当前事件运行前 State + + + +## `run_preprocessor(func)` + + +* **说明** + + 运行预处理。装饰一个函数,使它在每次事件响应器运行前执行。 + + + +* **参数** + + 运行预处理函数接收四个参数。 + + + * `matcher: Matcher`: 当前要运行的事件响应器 + + + * `bot: Bot`: Bot 对象 + + + * `event: Event`: Event 对象 + + + * `state: dict`: 当前 State + + + +## `run_postprocessor(func)` + + +* **说明** + + 运行后处理。装饰一个函数,使它在每次事件响应器运行后执行。 + + + +* **参数** + + 运行后处理函数接收五个参数。 + + + * `matcher: Matcher`: 运行完毕的事件响应器 + + + * `exception: Optional[Exception]`: 事件响应器运行错误(如果存在) + + + * `bot: Bot`: Bot 对象 + + + * `event: Event`: Event 对象 + + + * `state: dict`: 当前 State + + + +## _async_ `handle_event(bot, event)` + + +* **说明** + + 处理一个事件。调用该函数以实现分发事件。 + + + +* **参数** + + + * `bot: Bot`: Bot 对象 + + + * `event: Event`: Event 对象 + + + +* **示例** + + +```python +import asyncio +asyncio.create_task(handle_event(bot, event)) +``` diff --git a/archive/2.0.0a4/api/nonebot.md b/archive/2.0.0a7/api/nonebot.md similarity index 94% rename from archive/2.0.0a4/api/nonebot.md rename to archive/2.0.0a7/api/nonebot.md index 7c89c882..68708c95 100644 --- a/archive/2.0.0a4/api/nonebot.md +++ b/archive/2.0.0a7/api/nonebot.md @@ -28,18 +28,15 @@ sidebarDepth: 0 * `on_endswith` => `nonebot.plugin.on_endswith` +* `on_keyword` => `nonebot.plugin.on_keyword` + + * `on_command` => `nonebot.plugin.on_command` * `on_regex` => `nonebot.plugin.on_regex` -* `on_regex` => `nonebot.plugin.on_regex` - - -* `on_regex` => `nonebot.plugin.on_regex` - - * `CommandGroup` => `nonebot.plugin.CommandGroup` @@ -52,9 +49,18 @@ sidebarDepth: 0 * `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` + + ## `get_driver()` diff --git a/archive/2.0.0a4/api/permission.md b/archive/2.0.0a7/api/permission.md similarity index 100% rename from archive/2.0.0a4/api/permission.md rename to archive/2.0.0a7/api/permission.md diff --git a/archive/2.0.0a4/api/plugin.md b/archive/2.0.0a7/api/plugin.md similarity index 52% rename from archive/2.0.0a4/api/plugin.md rename to archive/2.0.0a7/api/plugin.md index 42cdf84f..91d7320e 100644 --- a/archive/2.0.0a4/api/plugin.md +++ b/archive/2.0.0a7/api/plugin.md @@ -25,6 +25,38 @@ sidebarDepth: 0 +## _class_ `Export` + +基类:`dict` + + +* **说明** + + 插件导出内容以使得其他插件可以获得。 + + + +* **示例** + + +```python +nonebot.export().default = "bar" + +@nonebot.export() +def some_function(): + pass + +# this doesn't work before python 3.9 +# use +# export = nonebot.export(); @export.sub +# instead +# See also PEP-614: https://www.python.org/dev/peps/pep-0614/ +@nonebot.export().sub +def something_else(): + pass +``` + + ## _class_ `Plugin` 基类:`object` @@ -59,6 +91,15 @@ sidebarDepth: 0 * **说明**: 插件内定义的 `Matcher` +### `export` + + +* **类型**: `Export` + + +* **说明**: 插件内定义的导出内容 + + ## `on(type='', rule=None, permission=None, *, handlers=None, temp=False, priority=1, block=False, state=None)` @@ -552,6 +593,475 @@ sidebarDepth: 0 +## _class_ `MatcherGroup` + +基类:`object` + +事件响应器组合,统一管理。为 `Matcher` 创建提供默认属性。 + + +### `__init__(**kwargs)` + + +* **说明** + + 创建一个事件响应器组合,参数为默认值,与 `on` 一致 + + + +### `matchers` + + +* **类型** + + `List[Type[Matcher]]` + + + +* **说明** + + 组内事件响应器列表 + + + +### `base_kwargs` + + +* **类型**: `Dict[str, Any]` + + +* **说明**: 其他传递给 `on` 的参数默认值 + + +### `on(**kwargs)` + + +* **说明** + + 注册一个基础事件响应器,可自定义类型。 + + + +* **参数** + + + * `type: str`: 事件响应器类型 + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `permission: Optional[Permission]`: 事件响应权限 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_metaevent(**kwargs)` + + +* **说明** + + 注册一个元事件响应器。 + + + +* **参数** + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_message(**kwargs)` + + +* **说明** + + 注册一个消息事件响应器。 + + + +* **参数** + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `permission: Optional[Permission]`: 事件响应权限 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_notice(**kwargs)` + + +* **说明** + + 注册一个通知事件响应器。 + + + +* **参数** + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_request(**kwargs)` + + +* **说明** + + 注册一个请求事件响应器。 + + + +* **参数** + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_startswith(msg, rule=None, **kwargs)` + + +* **说明** + + 注册一个消息事件响应器,并且当消息的\*\*文本部分\*\*以指定内容开头时响应。 + + + +* **参数** + + + * `msg: str`: 指定消息开头内容 + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `permission: Optional[Permission]`: 事件响应权限 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_endswith(msg, rule=None, **kwargs)` + + +* **说明** + + 注册一个消息事件响应器,并且当消息的\*\*文本部分\*\*以指定内容结尾时响应。 + + + +* **参数** + + + * `msg: str`: 指定消息结尾内容 + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `permission: Optional[Permission]`: 事件响应权限 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_keyword(keywords, rule=None, **kwargs)` + + +* **说明** + + 注册一个消息事件响应器,并且当消息纯文本部分包含关键词时响应。 + + + +* **参数** + + + * `keywords: Set[str]`: 关键词列表 + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `permission: Optional[Permission]`: 事件响应权限 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_command(cmd, rule=None, aliases=None, **kwargs)` + + +* **说明** + + 注册一个消息事件响应器,并且当消息以指定命令开头时响应。 + + 命令匹配规则参考: [命令形式匹配](rule.html#command-command) + + + +* **参数** + + + * `cmd: Union[str, Tuple[str, ...]]`: 指定命令内容 + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `aliases: Optional[Set[Union[str, Tuple[str, ...]]]]`: 命令别名 + + + * `permission: Optional[Permission]`: 事件响应权限 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + +### `on_regex(pattern, flags=0, rule=None, **kwargs)` + + +* **说明** + + 注册一个消息事件响应器,并且当消息匹配正则表达式时响应。 + + 命令匹配规则参考: [正则匹配](rule.html#regex-regex-flags-0) + + + +* **参数** + + + * `pattern: str`: 正则表达式 + + + * `flags: Union[int, re.RegexFlag]`: 正则匹配标志 + + + * `rule: Optional[Union[Rule, RuleChecker]]`: 事件响应规则 + + + * `permission: Optional[Permission]`: 事件响应权限 + + + * `handlers: Optional[List[Handler]]`: 事件处理函数列表 + + + * `temp: bool`: 是否为临时事件响应器(仅执行一次) + + + * `priority: int`: 事件响应器优先级 + + + * `block: bool`: 是否阻止事件向更低优先级传递 + + + * `state: Optional[dict]`: 默认的 state + + + +* **返回** + + + * `Type[Matcher]` + + + ## `load_plugin(module_path)` @@ -614,12 +1124,35 @@ sidebarDepth: 0 +## `get_plugin(name)` + + +* **说明** + + 获取当前导入的某个插件。 + + + +* **参数** + + + * `name: str`: 插件名,与 `load_plugin` 参数一致。如果为 `load_plugins` 导入的插件,则为文件(夹)名。 + + + +* **返回** + + + * `Optional[Plugin]` + + + ## `get_loaded_plugins()` * **说明** - 获取当前已导入的插件。 + 获取当前已导入的所有插件。 @@ -627,3 +1160,42 @@ sidebarDepth: 0 * `Set[Plugin]` + + + +## `export()` + + +* **说明** + + 获取插件的导出内容对象 + + + +* **返回** + + + * `Export` + + + +## `require(name)` + + +* **说明** + + 获取一个插件的导出内容 + + + +* **参数** + + + * `name: str`: 插件名,与 `load_plugin` 参数一致。如果为 `load_plugins` 导入的插件,则为文件(夹)名。 + + + +* **返回** + + + * `Optional[Export]` diff --git a/archive/2.0.0a4/api/rule.md b/archive/2.0.0a7/api/rule.md similarity index 100% rename from archive/2.0.0a4/api/rule.md rename to archive/2.0.0a7/api/rule.md diff --git a/archive/2.0.0a4/api/typing.md b/archive/2.0.0a7/api/typing.md similarity index 77% rename from archive/2.0.0a4/api/typing.md rename to archive/2.0.0a7/api/typing.md index 72d66f23..8f8a2223 100644 --- a/archive/2.0.0a4/api/typing.md +++ b/archive/2.0.0a7/api/typing.md @@ -110,7 +110,7 @@ sidebarDepth: 0 -## `PreProcessor` +## `EventPreProcessor` * **类型** @@ -121,7 +121,55 @@ sidebarDepth: 0 * **说明** - 消息预处理函数 PreProcessor 类型 + 事件预处理函数 EventPreProcessor 类型 + + + + +## `EventPostProcessor` + + +* **类型** + + `Callable[[Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]` + + + +* **说明** + + 事件预处理函数 EventPostProcessor 类型 + + + + +## `RunPreProcessor` + + +* **类型** + + `Callable[[Matcher, Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]` + + + +* **说明** + + 事件响应器运行前预处理函数 RunPreProcessor 类型 + + + + +## `RunPostProcessor` + + +* **类型** + + `Callable[[Matcher, Optional[Exception], Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]` + + + +* **说明** + + 事件响应器运行前预处理函数 RunPostProcessor 类型,第二个参数为运行时产生的错误(如果存在) diff --git a/archive/2.0.0a4/api/utils.md b/archive/2.0.0a7/api/utils.md similarity index 94% rename from archive/2.0.0a4/api/utils.md rename to archive/2.0.0a7/api/utils.md index ed98fab9..52cf5766 100644 --- a/archive/2.0.0a4/api/utils.md +++ b/archive/2.0.0a7/api/utils.md @@ -54,8 +54,6 @@ sidebarDepth: 0 ## _class_ `DataclassEncoder` -基类:`json.encoder.JSONEncoder` - * **说明** diff --git a/archive/2.0.0a4/guide/README.md b/archive/2.0.0a7/guide/README.md similarity index 53% rename from archive/2.0.0a4/guide/README.md rename to archive/2.0.0a7/guide/README.md index 43b7f325..4326ac1b 100644 --- a/archive/2.0.0a4/guide/README.md +++ b/archive/2.0.0a7/guide/README.md @@ -1,33 +1,30 @@ # 概览 -:::tip 提示 + :::tip 提示 初次使用时可能会觉得这里的概览过于枯燥,可以先简单略读之后直接前往 [安装](./installation.md) 查看安装方法,并进行后续的基础使用教程。 ::: -NoneBot2 是一个可扩展的 Python 异步机器人框架,它会对机器人收到的消息进行解析和处理,并以插件化的形式,分发给消息所对应的命令处理器和自然语言处理器,来完成具体的功能。 +## 简介 -除了起到解析消息的作用,NoneBot 还为插件提供了大量实用的预设操作和权限控制机制,尤其对于命令处理器,它更是提供了完善且易用的会话机制和内部调用机制,以分别适应命令的连续交互和插件内部功能复用等需求。 +NoneBot2 是一个可扩展的 Python 异步机器人框架,它会对机器人收到的事件进行解析和处理,并以插件化的形式,按优先级分发给事件所对应的事件响应器,来完成具体的功能。 -目前 NoneBot2 在 [FastAPI](https://fastapi.tiangolo.com/) 的基础上封装了与 [CQHTTP(OneBot) 协议](http://cqhttp.cc/)插件的网络交互。 +除了起到解析事件的作用,NoneBot 还为插件提供了大量实用的预设操作和权限控制机制。对于命令处理,它更是提供了完善且易用的会话机制和内部调用机制,以分别适应命令的连续交互和插件内部功能复用等需求。 -得益于 Python 的 [asyncio](https://docs.python.org/3/library/asyncio.html) 机制,NoneBot 处理消息的吞吐量有了很大的保障,再配合 WebSocket 通信方式(也是最建议的通信方式),NoneBot 的性能可以达到 HTTP 通信方式的两倍以上,相较于传统同步 I/O 的 HTTP 通信,更是有质的飞跃。 +得益于 Python 的 [asyncio](https://docs.python.org/3/library/asyncio.html) 机制,NoneBot 处理事件的吞吐量有了很大的保障,再配合 WebSocket 通信方式(也是最建议的通信方式),NoneBot 的性能可以达到 HTTP 通信方式的两倍以上,相较于传统同步 I/O 的 HTTP 通信,更是有质的飞跃。 -需要注意的是,NoneBot 仅支持 Python 3.7+ 及 CQHTTP(OneBot) 插件 v11+。 - -## 它如何工作? - - - -~~未填坑~~ +需要注意的是,NoneBot 仅支持 **Python 3.7+** ## 特色 -- 提供直观的测试前端 +NoneBot2 的驱动框架 `Driver` 以及通信协议 `Adapter` 均可**自定义**,并且可以作为插件进行**替换/添加**! + - 提供使用简易的脚手架 +- 提供丰富的官方插件 +- 提供可添加/替换的驱动以及协议选项 - 基于异步 I/O - 同时支持 HTTP 和反向 WebSocket 通信方式 - 支持多个机器人账号负载均衡 diff --git a/archive/2.0.0a4/guide/basic-configuration.md b/archive/2.0.0a7/guide/basic-configuration.md similarity index 100% rename from archive/2.0.0a4/guide/basic-configuration.md rename to archive/2.0.0a7/guide/basic-configuration.md diff --git a/archive/2.0.0a7/guide/creating-a-handler.md b/archive/2.0.0a7/guide/creating-a-handler.md new file mode 100644 index 00000000..ca65b1a6 --- /dev/null +++ b/archive/2.0.0a7/guide/creating-a-handler.md @@ -0,0 +1,159 @@ +# 事件处理 + +在上一章中,我们已经注册了事件响应器,现在我们可以正式编写事件处理逻辑了! + +## [事件处理函数](../api/typing.md#handler) + +```python{1,2,8,9} +@weather.handle() +async def handle_first_receive(bot: Bot, event: Event, state: dict): + args = str(event.message).strip() # 首次发送命令时跟随的参数,例:/天气 上海,则args为上海 + if args: + state["city"] = args # 如果用户发送了参数则直接赋值 + + +@weather.got("city", prompt="你想查询哪个城市的天气呢?") +async def handle_city(bot: Bot, event: Event, state: dict): + city = state["city"] + if city not in ["上海", "北京"]: + await weather.reject("你想查询的城市暂不支持,请重新输入!") + city_weather = await get_weather(city) + await weather.finish(city_weather) +``` + +在之前的样例中,我们定义了两个函数 `handle_first_receive`, `handle_city`,他们被事件响应器的装饰器装饰从而成为事件响应器的事件处理函数。 + +:::tip 提示 +在事件响应器中,事件处理函数是**顺序**执行的! +::: + +### 添加一个事件处理函数 + +事件响应器提供了三种装饰事件处理函数的装饰器,分别是: + +1. [handle()](../api/matcher.md#classmethod-handle) +2. [receive()](../api/matcher.md#classmethod-receive) +3. [got(key, prompt, args_parser)](../api/matcher.md#classmethod-got-key-prompt-none-args-parser-none) + +#### handle() + +简单的为事件响应器添加一个事件处理函数,这个函数将会在上一个处理函数正常返回执行完毕后立即执行。 + +#### receive() + +指示 NoneBot 接收一条新的用户消息后继续执行该处理函数。此时函数将会接收到新的消息而非前一条消息,之前相关信息可以存储在 state 中。 + +特别的,当装饰的函数前没有其他事件处理函数,那么 `receive()` 不会接收一条新的消息而是直接使用第一条接收到的消息。 + +#### got(key, prompt, args_parser) + +指示 NoneBot 当 `state` 中不存在 `key` 时向用户发送 `prompt` 等待用户回复并赋值给 `state[key]`。 + +`prompt` 可以为 `str`, `Message`, `MessageSegment`,若为空则不会向用户发送,若不为空则会在 format 之后发送,即 `prompt.format(**state)`,注意对 `{}` 进行转义。示例: + +```python +@matcher.receive() +async def handle(bot: Bot, event: Event, state: dict): + state["key"] = "hello" + + +@matcher.got("key2", prompt="{key}!") +async def handle2(bot: Bot, event: Event, state: dict): + pass +``` + +`args_parser` 为参数处理函数,在这里传入一个新的函数以覆盖默认的参数处理。详情参照 [args_parser](#参数处理函数-args-parser) + +特别的,这些装饰器都可以套娃使用: + +```python +@matcher.got("key1") +@matcher.got("key2") +async def handle(bot: Bot, event: Event, state: dict): + pass +``` + +### 事件处理函数参数 + +事件处理函数类型为 `Callable[[Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]` 。 + +参数分别为: + +1. [nonebot.typing.Bot](../api/typing.md#bot): 即事件上报连接对应的 Bot 对象,为 BaseBot 的子类。特别注意,此处的类型注释可以替换为指定的 Bot 类型,例如:`nonebot.adapters.cqhttp.Bot`,只有在上报事件的 Bot 类型与类型注释相符时才会执行该处理函数!可用于多平台进行不同的处理。 +2. [nonebot.typing.Event](../api/typing.md#event): 即上报事件对象,可以获取到上报的所有信息。 +3. `state`: 状态字典,可以存储任意的信息,其中还包含一些特殊的值以获取 NoneBot 内部处理时的一些信息,如: + +- `state["_current_key"]`: 存储当前 `got` 获取的参数名 +- `state["_prefix"]`, `state["_suffix"]`: 存储当前 TRIE 匹配的前缀/后缀,可以通过该值获取用户命令的原始命令 + +### 参数处理函数 args_parser + +在使用 `got` 获取用户输入参数时,需要对用户的消息进行处理以转换为我们所需要的信息。在默认情况下,NoneBot 会把用户的消息字符串原封不动的赋值给 `state[key]` 。可以通过以下两种方式修改默认处理逻辑: + +- `@matcher.args_parser` 装饰器:直接装饰一个函数作为参数处理器 +- `got(key, prompt, args_parser)`:直接把函数作为参数传入 + +参数处理函数类型为:`Callable[[Bot, Event, dict], Union[Awaitable[None], Awaitable[NoReturn]]]`,即: + +```python +async def parser(bot: Bot, event: Event, state: dict): + state[state["_current_key"]] = str(event.message) +``` + +特别的,`state["_current_key"]` 中存储了当前获取的参数名 + +### 逻辑控制 + +NoneBot 也为事件处理函数提供了一些便捷的逻辑控制函数: + +#### `matcher.send` + +这个函数用于发送一条消息给当前交互的用户。~~其实这并不是一个逻辑控制函数,只是不知道放在哪里……~~ + +#### `matcher.pause` + +这个函数用于结束当前事件处理函数,强制接收一条新的消息再运行**下一个消息处理函数**。 + +#### `matcher.reject` + +这个函数用于结束当前事件处理函数,强制接收一条新的消息再**再次运行当前消息处理函数**。常用于用户输入信息不符合预期。 + +#### `matcher.finish` + +这个函数用于直接结束当前事件处理。 + +以上三个函数都拥有一个参数 `message` / `prompt`,用于向用户发送一条消息。以及 `**kwargs` 直接传递给 `bot.send` 的额外参数。 + +## 常用事件处理结构 + +```python +matcher = on_command("test") + +# 修改默认参数处理 +@matcher.args_parser +async def parse(bot: Bot, event: Event, state: dict): + print(state["_current_key"], ":", str(event.message)) + state[state["_current_key"]] = str(event.message) + +@matcher.handle() +async def first_receive(bot: Bot, event: Event, state: dict): + # 获取用户原始命令,如:/test + print(state["_prefix"]["raw_command"]) + # 处理用户输入参数,如:/test arg1 arg2 + raw_args = str(event.message).strip() + if raw_args: + arg_list = raw_args.split() + # 将参数存入state以阻止后续再向用户询问参数 + state["arg1"] = arg_list[0] + + +@matcher.got("arg1", prompt="参数?") +async def arg_handle(bot: Bot, event: Event, state: dict): + # 在这里对参数进行验证 + if state["arg1"] not in ["allow", "list"]: + await matcher.reject("参数不正确!请重新输入") + # 发送一些信息 + await bot.send(event, "message") + await matcher.send("message") + await matcher.finish("message") +``` diff --git a/archive/2.0.0a7/guide/creating-a-matcher.md b/archive/2.0.0a7/guide/creating-a-matcher.md new file mode 100644 index 00000000..b603449a --- /dev/null +++ b/archive/2.0.0a7/guide/creating-a-matcher.md @@ -0,0 +1,144 @@ +# 注册事件响应器 + +好了,现在插件已经创建完毕,我们可以开始编写实际代码了,下面将以一个简易单文件天气查询插件为例。 + +在插件目录下 `weather.py` 中添加如下代码: + +```python +from nonebot import on_command +from nonebot.rule import to_me +from nonebot.adapters.cqhttp import Bot, Event + +weather = on_command("天气", rule=to_me(), priority=5) + + +@weather.handle() +async def handle_first_receive(bot: Bot, event: Event, state: dict): + args = str(event.message).strip() # 首次发送命令时跟随的参数,例:/天气 上海,则args为上海 + if args: + state["city"] = args # 如果用户发送了参数则直接赋值 + + +@weather.got("city", prompt="你想查询哪个城市的天气呢?") +async def handle_city(bot: Bot, event: Event, state: dict): + city = state["city"] + if city not in ["上海", "北京"]: + await weather.reject("你想查询的城市暂不支持,请重新输入!") + city_weather = await get_weather(city) + await weather.finish(city_weather) + + +async def get_weather(city: str): + return f"{city}的天气是..." +``` + +为了简单起见,我们在这里的例子中没有接入真实的天气数据,但要接入也非常简单,你可以使用中国天气网、和风天气等网站提供的 API。 + +接下来我们来说明这段代码是如何工作的。 + +:::tip 提示 +从这里开始,你需要对 Python 的 asyncio 编程有所了解,因为 NoneBot 是完全基于 asyncio 的,具体可以参考 [廖雪峰的 Python 教程](https://www.liaoxuefeng.com/wiki/1016959663602400/1017959540289152) +::: + +## [事件响应器](../api/matcher.md) + +```python{4} +from nonebot import on_command +from nonebot.rule import to_me +from nonebot.permission import Permission + +weather = on_command("天气", rule=to_me(), permission=Permission(), priority=5) +``` + +在上方代码中,我们注册了一个事件响应器 `Matcher`,它由几个部分组成: + +1. `on_command` 注册一个消息类型的命令处理器 +2. `"天气"` 指定 command 参数 - 命令名 +3. `rule` 补充事件响应器的匹配规则 +4. `priority` 事件响应器优先级 +5. `block` 是否阻止事件传递 + +其他详细配置可以参考 API 文档,下面我们详细说明各个部分: + +### 事件响应器类型 type + +事件响应器类型其实就是对应事件的类型 `Event.type` ,NoneBot 提供了一个基础类型事件响应器 `on()` 以及一些其他内置的事件响应器。 + +以下所有类型的事件响应器都是由 `on(type, rule)` 的形式进行了简化封装。 + +- `on("事件类型")`: 基础事件响应器,第一个参数为事件类型,空字符串表示不限 +- `on_metaevent()` ~ `on("meta_event")`: 元事件响应器 +- `on_message()` ~ `on("message")`: 消息事件响应器 +- `on_request()` ~ `on("request")`: 请求事件响应器 +- `on_notice()` ~ `on("notice")`: 通知事件响应器 +- `on_startswith(str)` ~ `on("message", startswith(str))`: 消息开头匹配响应器,参考 [startswith](../api/rule.md#startswith-msg) +- `on_endswith(str)` ~ `on("message", endswith(str))`: 消息结尾匹配响应器,参考 [endswith](../api/rule.md#endswith-msg) +- `on_keyword(set)` ~ `on("message", keyword(str))`: 消息关键词匹配响应器,参考 [keyword](../api/rule.md#keyword-keywords) +- `on_command(str|tuple)` ~ `on("message", command(str|tuple))`: 命令响应器,参考 [command](../api/rule.md#command-cmds) +- `on_regex(pattern_str)` ~ `on("message", regex(pattern_str))`: 正则匹配处理器,参考 [regex](../api/rule.md#regex-regex-flags-0) + +### 匹配规则 rule + +事件响应器的匹配规则即 `Rule`,详细内容在下方介绍。[直达](#自定义-rule) + +### 优先级 priority + +事件响应器的优先级代表事件响应器的执行顺序,同一优先级的事件响应器会 **同时执行!**,优先级数字**越小**越先响应!优先级请从 `1` 开始排序! + +:::tip 提示 +使用 `nonebot-test` 可以看到当前所有事件响应器的执行流程,有助理解事件响应流程! + +```bash +pip install nonebot2[test] +``` + +::: + +### 阻断 block + +当有任意事件响应器发出了阻止事件传递信号时,该事件将不再会传递给下一优先级,直接结束处理。 + +NoneBot 内置的事件响应器中,所有 `message` 类的事件响应器默认会阻断事件传递,其他则不会。 + +## 自定义 rule + +rule 的出现使得 nonebot 对事件的响应可以非常自由,nonebot 内置了一些规则: + +- [startswith(msg)](../api/rule.md#startswith-msg) +- [endswith(msg)](../api/rule.md#endswith-msg) +- [keyword(\*keywords)](../api/rule.md#keyword-keywords) +- [command(\*cmds)](../api/rule.md#command-cmds) +- [regex(regex, flag)](../api/rule.md#regex-regex-flags-0) + +以上规则都是返回类型为 `Rule` 的函数,`Rule` 由非负个 `RuleChecker` 组成,当所有 `RuleChecker` 返回 `True` 时匹配成功。这些 `Rule`, `RuleChecker` 的形式如下: + +```python +from nonebot.rule import Rule + +async def async_checker(bot: Bot, event: Event, state: dict) -> bool: + return True + +def sync_checker(bot: Bot, event: Event, state: dict) -> bool: + return True + +def check(arg1, args2): + + async def _checker(bot: Bot, event: Event, state: dict) -> bool: + return bool(arg1 + arg2) + + return Rule(_check) +``` + +`Rule` 和 `RuleChecker` 之间可以使用 `与 &` 互相组合: + +```python +from nonebot.rule import Rule + +Rule(async_checker1) & sync_checker & async_checker2 +``` + +**_请勿将事件处理的逻辑写入 `rule` 中,这会使得事件处理返回奇怪的响应。_** + +:::danger 警告 +`Rule(*checkers)` 只接受 async function,或使用 `nonebot.utils.run_sync` 自行包裹 sync function。在使用 `与 &` 时,NoneBot 会自动包裹 sync function +::: diff --git a/archive/2.0.0a7/guide/creating-a-plugin.md b/archive/2.0.0a7/guide/creating-a-plugin.md new file mode 100644 index 00000000..0a6678db --- /dev/null +++ b/archive/2.0.0a7/guide/creating-a-plugin.md @@ -0,0 +1,119 @@ +# 创建插件 + +如果之前使用 `nb-cli` 生成了项目结构,那我们已经有了一个空的插件目录 `Awesome-Bot/awesome_bot/plugins`,并且它已在 `bot.py` 中被加载,我们现在可以开始创建插件了! + +使用 `nb-cli` 创建包形式插件,或自行创建文件(夹) + +```bash +nb plugin new +``` + +插件通常有两种形式,下面分别介绍 + +## 单文件形式 + +在插件目录下创建名为 `foo.py` 的 Python 文件,暂时留空,此时目录结构如下: + + +:::vue +AweSome-Bot +├── awesome_bot +│ └── plugins +│ └── `foo.py` +├── .env +├── .env.dev +├── .env.prod +├── .gitignore +├── bot.py +├── docker-compose.yml +├── Dockerfile +├── pyproject.toml +└── README.md +::: + + +这个时候它已经可以被称为一个插件了,尽管它还什么都没做。 + +## 包形式(推荐) + +在插件目录下创建文件夹 `foo`,并在该文件夹下创建文件 `__init__.py`,此时目录结构如下: + + +:::vue +AweSome-Bot +├── awesome_bot +│ └── plugins +│ └── `foo` +│ └── `__init__.py` +├── .env +├── .env.dev +├── .env.prod +├── .gitignore +├── bot.py +├── docker-compose.yml +├── Dockerfile +├── pyproject.toml +└── README.md +::: + + +这个时候 `foo` 就是一个合法的 Python 包了,同时也是合法的 NoneBot 插件,插件内容可以在 `__init__.py` 中编写。 + +### 推荐结构(仅供参考) + + +:::vue +foo +├── `__init__.py` +├── `config.py` +├── `data_source.py` +└── `model.py` +::: + + +#### \_\_init\_\_.py + +在该文件中编写各类事件响应及处理逻辑。 + +#### config.py + +在该文件中使用 `pydantic` 定义插件所需要的配置项以及类型。 + +示例: + +```python +from pydantic import BaseSetting + + +class Config(BaseSetting): + + # plugin custom config + plugin_setting: str = "default" + + class Config: + extra = "ignore" +``` + +并在 `__init__.py` 文件中添加以下行 + +```python +import nonebot +from .config import Config + +global_config = nonebot.get_driver().config +plugin_config = Config(**global_config.dict()) +``` + +此时就可以通过 `plugin_config.plugin_setting` 获取到插件所需要的配置项了。 + +#### data_source.py + +在该文件中编写数据获取函数。 + +:::warning 警告 +数据获取应尽量使用**异步**处理!例如使用 [httpx](https://www.python-httpx.org/) 而非 [requests](https://requests.readthedocs.io/en/master/) +::: + +#### model.py + +在该文件中编写数据库模型。 diff --git a/archive/2.0.0a4/guide/creating-a-project.md b/archive/2.0.0a7/guide/creating-a-project.md similarity index 87% rename from archive/2.0.0a4/guide/creating-a-project.md rename to archive/2.0.0a7/guide/creating-a-project.md index 74cdb24a..b8ac3b77 100644 --- a/archive/2.0.0a4/guide/creating-a-project.md +++ b/archive/2.0.0a7/guide/creating-a-project.md @@ -4,16 +4,12 @@ ## 目录结构 -首先,我们可以使用 `nb-cli` 或者自行创建项目目录: +首先,我们可以使用 `nb-cli` 或者自行创建完整的项目目录: ```bash -pip install nonebot2[cli] -# pip install nb-cli nb create ``` -这将创建默认的目录结构 - :::vue AweSome-Bot diff --git a/archive/2.0.0a7/guide/end-or-start.md b/archive/2.0.0a7/guide/end-or-start.md new file mode 100644 index 00000000..11780114 --- /dev/null +++ b/archive/2.0.0a7/guide/end-or-start.md @@ -0,0 +1,9 @@ +# 结语 + +至此,相信你已经能够写出一个基础的插件了,更多的用法将会在 进阶 部分进行介绍,这里给出几个小提示: + +- 请千万注意事件处理器的优先级设定 +- 在匹配规则中请勿使用耗时极长的函数 +- 同一个用户可以**跨群**(**私聊**)继续他的事件处理(除非做出权限限制,将在后续介绍) + +如果你还不能满足,前往 [进阶](../advanced/README.md) 获得更多的功能信息。 diff --git a/archive/2.0.0a4/guide/getting-started.md b/archive/2.0.0a7/guide/getting-started.md similarity index 80% rename from archive/2.0.0a4/guide/getting-started.md rename to archive/2.0.0a7/guide/getting-started.md index 9c358ead..8ed182eb 100644 --- a/archive/2.0.0a4/guide/getting-started.md +++ b/archive/2.0.0a7/guide/getting-started.md @@ -4,38 +4,53 @@ ## 最小实例 -使用你最熟悉的编辑器或 IDE,创建一个名为 `bot.py` 的文件,内容如下: +如果你已经按照推荐方式安装了 `nb-cli`,使用脚手架创建一个空项目: + +```bash +nb create +``` + +根据脚手架引导,将在当前目录下创建一个项目目录,项目目录内包含 `bot.py`。 + +如果未安装 `nb-cli`,使用你最熟悉的编辑器或 IDE,创建一个名为 `bot.py` 的文件,内容如下: ```python{3,4,7} import nonebot +from nonebot.adapters.cqhttp import Bot as CQHTTPBot nonebot.init() +driver = nonebot.get_driver() +driver.register_adapter("cqhttp", CQHTTPBot) nonebot.load_builtin_plugins() if __name__ == "__main__": nonebot.run() ``` -这几行高亮代码将依次: +## 解读 -1. 使用默认配置初始化 NoneBot 包 +在上方 `bot.py` 中,这几行高亮代码将依次: + +1. 使用默认配置初始化 NoneBot 2. 加载 NoneBot 内置的插件 3. 在地址 `127.0.0.1:8080` 运行 NoneBot 在命令行使用如下命令即可运行这个 NoneBot 实例: ```bash +# nb-cli +nb run +# 其他 python bot.py ``` 运行后会产生如下日志: -```default +```plain 09-14 21:02:00 [INFO] nonebot | Succeeded to import "nonebot.plugins.base" 09-14 21:02:00 [INFO] nonebot | Running NoneBot... 09-14 21:02:00 [INFO] uvicorn | Started server process [1234] 09-14 21:02:00 [INFO] uvicorn | Waiting for application startup. -09-14 21:02:00 [INFO] nonebot | Scheduler Started 09-14 21:02:00 [INFO] uvicorn | Application startup complete. 09-14 21:02:00 [INFO] uvicorn | Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit) ``` @@ -46,23 +61,23 @@ python bot.py 目前支持的协议有: -- [OneBot(CQHTTP)](https://github.com/howmanybots/onebot) +- [OneBot(CQHTTP)](https://github.com/howmanybots/onebot/blob/master/README.md) QQ 协议端举例: -- [Mirai](https://github.com/mamoe/mirai) + [cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai) -- [cqhttp-mirai-embedded](https://github.com/yyuueexxiinngg/cqhttp-mirai/tree/embedded) -- [Mirai](https://github.com/mamoe/mirai) + [Mirai Native](https://github.com/iTXTech/mirai-native) + [CQHTTP](https://github.com/richardchien/coolq-http-api) - [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) (基于 [MiraiGo](https://github.com/Mrs4s/MiraiGo)) +- [cqhttp-mirai-embedded](https://github.com/yyuueexxiinngg/cqhttp-mirai/tree/embedded) +- [Mirai](https://github.com/mamoe/mirai) + [cqhttp-mirai](https://github.com/yyuueexxiinngg/cqhttp-mirai) +- [Mirai](https://github.com/mamoe/mirai) + [Mirai Native](https://github.com/iTXTech/mirai-native) + [CQHTTP](https://github.com/richardchien/coolq-http-api) - [OICQ-http-api](https://github.com/takayama-lily/onebot) (基于 [OICQ](https://github.com/takayama-lily/oicq)) 这里以 [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 为例 -1. 下载 go-cqhttp 对应平台的 release 文件 -2. 双击 exe 文件或者使用 `./go-cqhttp` 启动 +1. 下载 go-cqhttp 对应平台的 release 文件,[点此前往](https://github.com/Mrs4s/go-cqhttp/releases) +2. 运行 exe 文件或者使用 `./go-cqhttp` 启动 3. 生成默认配置文件并修改默认配置 -```json{2,3,30-31} +```json{2,3,35-36,42} { "uin": 你的QQ号, "password": "你的密码", @@ -75,6 +90,11 @@ QQ 协议端举例: "relogin_delay": 3, "max_relogin_times": 0 }, + "_rate_limit": { + "enabled": false, + "frequency": 0, + "bucket_size": 0 + }, "ignore_invalid_cqcode": false, "force_fragmented": true, "heartbeat_interval": 0, @@ -99,9 +119,16 @@ QQ 协议端举例: "reverse_reconnect_interval": 3000 } ], - "post_message_format": "string", + "post_message_format": "array", + "use_sso_address": false, "debug": false, - "log_level": "" + "log_level": "", + "web_ui": { + "enabled": true, + "host": "0.0.0.0", + "web_ui_port": 9999, + "web_input": false + } } ``` diff --git a/archive/2.0.0a7/guide/installation.md b/archive/2.0.0a7/guide/installation.md new file mode 100644 index 00000000..b7259254 --- /dev/null +++ b/archive/2.0.0a7/guide/installation.md @@ -0,0 +1,87 @@ +# 安装 + +## NoneBot + +:::warning 注意 +请确保你的 Python 版本 >= 3.7。 +::: + +:::warning 注意 +请在安装 nonebot2 之前卸载 nonebot 1.x + +```bash +pip uninstall nonebot +``` + +::: + +### 通过脚手架安装(推荐安装方式) + +1. (可选)使用你喜欢的 Python 环境管理工具创建新的虚拟环境。 +2. 使用 `pip` (或其他) 安装 NoneBot 脚手架。 + + ```bash + pip install nb-cli + ``` + +3. 点个 star 吧 + + nonebot2: [![nb-cli](https://img.shields.io/github/stars/nonebot/nonebot2?style=social)](https://github.com/nonebot/nonebot2) + + nb-cli: [![nb-cli](https://img.shields.io/github/stars/nonebot/nb-cli?style=social)](https://github.com/nonebot/nb-cli) + +### 不使用脚手架(纯净安装) + +```bash +# poetry +poetry add nonebot2 +# pip +pip install nonebot2 +``` + +如果你需要使用最新的(可能**尚未发布**的)特性,可以直接从 GitHub 仓库安装: + +```bash +# master +poetry add git+https://github.com/nonebot/nonebot2.git#master +# dev +poetry add git+https://github.com/nonebot/nonebot2.git#dev +``` + +或者克隆 Git 仓库后手动安装: + +```bash +git clone https://github.com/nonebot/nonebot2.git +cd nonebot2 +poetry install --no-dev # 推荐 +pip install . # 不推荐 +``` + +## 安装插件 + +插件可以通过 `nb-cli` 进行安装,也可以自行安装并加载插件。 + +```bash +# 列出所有的插件 +nb plugin list +# 搜索插件 +nb plugin search xxx +# 安装插件 +nb plugin install xxx +``` + +如果急于上线 Bot 或想要使用现成的插件,以下插件可作为参考: + +### 官方插件 + +~~自用插件~~ ~~确信~~ + +- [NoneBot-Plugin-Docs](https://github.com/nonebot/nonebot2/tree/master/packages/nonebot-plugin-docs) 离线文档插件 +- [NoneBot-Plugin-Test](https://github.com/nonebot/plugin-test) 本地机器人测试前端插件 +- [NoneBot-Plugin-APScheduler](https://github.com/nonebot/plugin-apscheduler) 定时任务插件 +- [NoneBot-Plugin-Sentry](https://github.com/cscs181/QQ-GitHub-Bot/tree/master/src/plugins/nonebot_plugin_sentry) Sentry 在线日志分析插件 +- [NoneBot-Plugin-Status](https://github.com/cscs181/QQ-GitHub-Bot/tree/master/src/plugins/nonebot_plugin_status) 服务器状态查看插件 + +### 其他插件 + +还有更多的插件在 [这里](/plugin-store.md) 等着你发现~ diff --git a/archive/2.0.0a7/guide/loading-a-plugin.md b/archive/2.0.0a7/guide/loading-a-plugin.md new file mode 100644 index 00000000..e69c52a8 --- /dev/null +++ b/archive/2.0.0a7/guide/loading-a-plugin.md @@ -0,0 +1,116 @@ +# 加载插件 + +在 [创建一个完整的项目](creating-a-project) 一章节中,我们已经创建了插件目录 `awesome_bot/plugins`,现在我们在机器人入口文件中加载它。当然,你也可以单独加载一个插件。 + +## 加载内置插件 + +在 `bot.py` 文件中添加以下行: + +```python{5} +import nonebot + +nonebot.init() +# 加载 nonebot 内置插件 +nonebot.load_builtin_plugins() + +app = nonebot.get_asgi() + +if __name__ == "__main__": + nonebot.run() +``` + +这将会加载 nonebot 内置的插件,它包含: + +- 命令 `say`:可由**superuser**使用,可以将消息内容由特殊纯文本转为富文本 +- 命令 `echo`:可由任何人使用,将消息原样返回 + +以上命令均需要指定机器人,即私聊、群聊内@机器人、群聊内称呼机器人昵称。参考 [Rule: to_me](../api/rule.md#to-me) + +## 加载插件目录 + +在 `bot.py` 文件中添加以下行: + +```python{5} +import nonebot + +nonebot.init() +# 加载插件目录,该目录下为各插件,以下划线开头的插件将不会被加载 +nonebot.load_plugins("awesome_bot/plugins") + +app = nonebot.get_asgi() + +if __name__ == "__main__": + nonebot.run() +``` + +:::tip 提示 +加载插件目录时,目录下以 `_` 下划线开头的插件将不会被加载! +::: + +:::warning 提示 +**插件不能存在相同名称!** +::: + +:::danger 警告 +插件间不应该存在过多的耦合,如果确实需要导入某个插件内的数据,可以参考 [进阶-跨插件访问](../advanced/export-and-require.md) +::: + +## 加载单个插件 + +在 `bot.py` 文件中添加以下行: + +```python{5,7} +import nonebot + +nonebot.init() +# 加载一个 pip 安装的插件 +nonebot.load_plugin("nonebot_plugin_status") +# 加载本地的单独插件 +nonebot.load_plugin("awesome_bot.plugins.xxx") + +app = nonebot.get_asgi() + +if __name__ == "__main__": + nonebot.run() +``` + +## 子插件(嵌套插件) + +在插件中同样可以加载子插件,例如如下插件目录结构: + + +:::vue +foo_plugin +├── `plugins` +│ ├── `sub_plugin1` +│ │ └── \_\_init\_\_.py +│ └── `sub_plugin2.py` +├── `__init__.py` +└── config.py +::: + + +在插件目录下的 `__init__.py` 中添加如下代码: + +```python +from pathlib import Path + +import nonebot + +# store all subplugins +_sub_plugins = set() +# load sub plugins +_sub_plugins |= nonebot.load_plugins( + str((Path(__file__).parent / "plugins").resolve())) +``` + +插件将会被加载并存储于 `_sub_plugins` 中。 + +## 运行结果 + +尝试运行 `nb run` 或者 `python bot.py`,可以看到日志输出了类似如下内容: + +```plain +09-19 21:51:59 [INFO] nonebot | Succeeded to import "nonebot.plugins.base" +09-19 21:51:59 [INFO] nonebot | Succeeded to import "plugin_in_folder" +``` diff --git a/archive/2.0.0a4/sidebar.config.json b/archive/2.0.0a7/sidebar.config.json similarity index 67% rename from archive/2.0.0a4/sidebar.config.json rename to archive/2.0.0a7/sidebar.config.json index 54e78eaa..d01b84e1 100644 --- a/archive/2.0.0a4/sidebar.config.json +++ b/archive/2.0.0a7/sidebar.config.json @@ -15,6 +15,10 @@ "text": "指南", "link": "/guide/" }, + { + "text": "进阶", + "link": "/advanced/" + }, { "text": "API", "link": "/api/" @@ -22,14 +26,17 @@ { "text": "插件广场", "link": "/plugin-store" + }, + { + "text": "更新日志", + "link": "/changelog" } ], "sidebarDepth": 2, "sidebar": { "/guide/": [ { - "title": "指南", - "path": "", + "title": "开始", "collapsable": false, "sidebar": "auto", "children": [ @@ -37,8 +44,41 @@ "installation", "getting-started", "creating-a-project", - "basic-configuration", - "writing-a-plugin" + "basic-configuration" + ] + }, + { + "title": "编写插件", + "collapsable": false, + "sidebar": "auto", + "children": [ + "loading-a-plugin", + "creating-a-plugin", + "creating-a-matcher", + "creating-a-handler", + "end-or-start" + ] + } + ], + "/advanced/": [ + { + "title": "进阶", + "collapsable": false, + "sidebar": "auto", + "children": [ + "", + "scheduler", + "permission", + "runtime-hook", + "export-and-require" + ] + }, + { + "title": "发布", + "collapsable": false, + "sidebar": "auto", + "children": [ + "publish-plugin" ] } ], @@ -60,6 +100,10 @@ "title": "nonebot.plugin 模块", "path": "plugin" }, + { + "title": "nonebot.message 模块", + "path": "message" + }, { "title": "nonebot.matcher 模块", "path": "matcher" @@ -72,10 +116,6 @@ "title": "nonebot.permission 模块", "path": "permission" }, - { - "title": "nonebot.sched 模块", - "path": "sched" - }, { "title": "nonebot.log 模块", "path": "log" @@ -107,6 +147,10 @@ { "title": "nonebot.adapters.cqhttp 模块", "path": "adapters/cqhttp" + }, + { + "title": "nonebot.adapters.ding 模块", + "path": "adapters/ding" } ] } diff --git a/docs/.vuepress/versions.json b/docs/.vuepress/versions.json index b2845794..be230268 100644 --- a/docs/.vuepress/versions.json +++ b/docs/.vuepress/versions.json @@ -1,4 +1,4 @@ [ - "2.0.0a6", - "2.0.0a4" + "2.0.0a7", + "2.0.0a6" ] \ No newline at end of file diff --git a/pages/changelog.md b/pages/changelog.md index 457925e8..2a766f70 100644 --- a/pages/changelog.md +++ b/pages/changelog.md @@ -11,8 +11,8 @@ sidebar: auto - 修改 cqhttp 检查 reply 时未去除后续 at 以及空格 - 添加 get_plugin 获取插件函数 - 添加插件 export, require 方法 -- 移除内置 apscheduler 定时任务支持 -- 移除内置协议适配默认加载 +- **移除**内置 apscheduler 定时任务支持 +- **移除**内置协议适配默认加载 - 新增**钉钉**协议适配 - 移除原有共享型 `MatcherGroup` 改为默认型 `MatcherGroup` diff --git a/poetry.lock b/poetry.lock index aa464727..6ac05a37 100644 --- a/poetry.lock +++ b/poetry.lock @@ -474,7 +474,7 @@ reference = "aliyun" [[package]] name = "importlib-metadata" -version = "3.1.0" +version = "3.1.1" description = "Read metadata from Python packages" category = "dev" optional = true @@ -484,8 +484,8 @@ python-versions = ">=3.6" zipp = ">=0.5" [package.extras] -docs = ["sphinx", "rst.linker"] -testing = ["packaging", "pep517", "unittest2", "importlib-resources (>=1.3)"] +docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [package.source] type = "legacy" @@ -1570,8 +1570,8 @@ imagesize = [ {file = "imagesize-1.2.0.tar.gz", hash = "sha256:b1f6b5a4eab1f73479a50fb79fcf729514a900c341d8503d62a62dbc4127a2b1"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.1.0-py2.py3-none-any.whl", hash = "sha256:590690d61efdd716ff82c39ca9a9d4209252adfe288a4b5721181050acbd4175"}, - {file = "importlib_metadata-3.1.0.tar.gz", hash = "sha256:d9b8a46a0885337627a6430db287176970fff18ad421becec1d64cfc763c2099"}, + {file = "importlib_metadata-3.1.1-py3-none-any.whl", hash = "sha256:6112e21359ef8f344e7178aa5b72dc6e62b38b0d008e6d3cb212c5b84df72013"}, + {file = "importlib_metadata-3.1.1.tar.gz", hash = "sha256:b0c2d3b226157ae4517d9625decf63591461c66b3a808c2666d538946519d170"}, ] jinja2 = [ {file = "Jinja2-2.11.2-py2.py3-none-any.whl", hash = "sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"}, diff --git a/pyproject.toml b/pyproject.toml index ced1a8f4..d4fc9677 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "nonebot2" -version = "2.0.0-alpha.6" +version = "2.0.0-alpha.7" description = "An asynchronous python bot framework." authors = ["yanyongyu "] license = "MIT" @@ -35,6 +35,8 @@ pydantic = { extras = ["dotenv"], version = "^1.7.2" } yapf = "^0.30.0" sphinx = "^3.3.1" nb-cli = { version = "^0.2.0", optional = true } +nonebot-plugin-test = { version = "^0.1.0", optional = true } +nonebot-plugin-apscheduler = { version = "^0.1.0", optional = true } sphinx-markdown-builder = { git = "https://github.com/nonebot/sphinx-markdown-builder.git" } [[tool.poetry.source]] diff --git a/tests/bot.py b/tests/bot.py index 16d3c5b0..6e45e051 100644 --- a/tests/bot.py +++ b/tests/bot.py @@ -23,6 +23,8 @@ driver.register_adapter("ding", DingBot) # load builtin plugin nonebot.load_builtin_plugins() +nonebot.load_plugin("nonebot_plugin_apscheduler") +nonebot.load_plugin("nonebot_plugin_test") # load local plugins nonebot.load_plugins("test_plugins")