nonebot2/website/versioned_docs/version-2.0.0/tutorial/create-plugin.md
noneflow[bot] 8dcfe92f13 🔖 Release 2.0.0
2023-06-01 06:26:07 +00:00

227 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
sidebar_position: 3
description: 创建并加载自定义插件
options:
menu:
weight: 50
category: tutorial
---
# 插件编写准备
在正式编写插件之前,我们需要先了解一下插件的概念。
## 插件结构
在 NoneBot 中,插件即是 Python 的一个[模块module](https://docs.python.org/zh-cn/3/glossary.html#term-module)。NoneBot 会在导入时对这些模块做一些特殊的处理使得他们成为一个插件。插件间应尽量减少耦合可以进行有限制的相互调用NoneBot 能够正确解析插件间的依赖关系。
### 单文件插件
一个普通的 `.py` 文件即可以作为一个插件,例如创建一个 `foo.py` 文件:
```tree title=Project
📂 plugins
└── 📜 foo.py
```
这个时候模块 `foo` 已经可以被称为一个插件了,尽管它还什么都没做。
### 包插件
一个包含 `__init__.py` 的文件夹即是一个常规 Python [包 `package`](https://docs.python.org/zh-cn/3/glossary.html#term-regular-package),例如创建一个 `foo` 文件夹:
```tree title=Project
📂 plugins
└── 📂 foo
└── 📜 __init__.py
```
这个时候包 `foo` 同样是一个合法的插件,插件内容可以在 `__init__.py` 文件中编写。
## 创建插件
:::warning 注意
如果在之前的[快速上手](../quick-start.mdx)章节中已经使用 `bootstrap` 模板创建了项目,那么你需要做出如下修改:
1. 在项目目录中创建一个两层文件夹 `awesome_bot/plugins`
```tree title=Project
📦 awesome-bot
├── 📂 awesome_bot
│ └── 📂 plugins
├── 📜 pyproject.toml
└── 📜 README.md
```
2. 修改 `pyproject.toml` 文件中的 `nonebot` 配置项,在 `plugin_dirs` 中添加 `awesome_bot/plugins`
```toml title=pyproject.toml
[tool.nonebot]
plugin_dirs = ["awesome_bot/plugins"]
```
:::
:::warning 注意
如果在之前的[创建项目](./application.md)章节中手动创建了相关文件,那么你需要做出如下修改:
1. 在项目目录中创建一个两层文件夹 `awesome_bot/plugins`
```tree title=Project
📦 awesome-bot
├── 📂 awesome_bot
│ └── 📂 plugins
└── 📜 bot.py
```
2. 修改 `bot.py` 文件中的加载插件部分,取消注释或者添加如下代码
```python title=bot.py
# 在这里加载插件
nonebot.load_builtin_plugins("echo") # 内置插件
nonebot.load_plugins("awesome_bot/plugins") # 本地插件
```
:::
创建插件可以通过 `nb-cli` 命令从完整模板创建,也可以手动新建空白文件。通过以下命令创建一个名为 `weather` 的插件:
```bash
$ nb plugin create
[?] 插件名称: weather
[?] 使用嵌套插件? (y/N) N
[?] 输出目录: awesome_bot/plugins
```
`nb-cli` 会在 `awesome_bot/plugins` 目录下创建一个名为 `weather` 的文件夹,其中包含的文件将在稍后章节中用到。
```tree title=Project
📦 awesome-bot
├── 📂 awesome_bot
│ └── 📂 plugins
| └── 📂 foo
| ├── 📜 __init__.py
| └── 📜 config.py
├── 📜 pyproject.toml
└── 📜 README.md
```
## 加载插件
:::danger 警告
请勿在插件被加载前 `import` 插件模块,这会导致 NoneBot 无法将其转换为插件而出现意料之外的情况。
:::
加载插件是在机器人入口文件中完成的,需要在框架初始化之后,运行之前进行。
请注意,加载的插件模块名称(插件文件名或文件夹名)**不能相同**,且每一个插件**只能被加载一次**,重复加载将会导致异常。
如果你使用 `nb-cli` 管理插件,那么你可以跳过这一节,`nb-cli` 将会自动处理加载。
如果你**使用自定义的入口文件** `bot.py`,那么你需要在 `bot.py` 中加载插件。
```python {5} title=bot.py
import nonebot
nonebot.init()
# 加载插件
nonebot.run()
```
加载插件的方式有多种,但在底层的加载逻辑是一致的。以下是为加载插件提供的几种方式:
### `load_plugin`
通过点分割模块名称或使用 [`pathlib`](https://docs.python.org/zh-cn/3/library/pathlib.html) 的 `Path` 对象来加载插件。通常用于加载第三方插件或者项目插件。例如:
```python
from pathlib import Path
nonebot.load_plugin("path.to.your.plugin") # 加载第三方插件
nonebot.load_plugin(Path("./path/to/your/plugin.py")) # 加载项目插件
```
:::warning 注意
请注意,本地插件的路径应该为相对机器人 **入口文件(通常为 bot.py** 可导入的,例如在项目 `plugins` 目录下。
:::
### `load_plugins`
加载传入插件目录中的所有插件,通常用于加载一系列本地编写的项目插件。例如:
```python
nonebot.load_plugins("src/plugins", "path/to/your/plugins")
```
:::warning 注意
请注意,插件目录应该为相对机器人 **入口文件(通常为 bot.py** 可导入的,例如在项目 `plugins` 目录下。
:::
### `load_all_plugins`
这种加载方式是以上两种方式的混合,加载所有传入的插件模块名称,以及所有给定目录下的插件。例如:
```python
nonebot.load_all_plugins(["path.to.your.plugin"], ["path/to/your/plugins"])
```
### `load_from_json`
通过 JSON 文件加载插件,是 [`load_all_plugins`](#load_all_plugins) 的 JSON 变种。通过读取 JSON 文件中的 `plugins` 字段和 `plugin_dirs` 字段进行加载。例如:
```json title=plugin_config.json
{
"plugins": ["path.to.your.plugin"],
"plugin_dirs": ["path/to/your/plugins"]
}
```
```python
nonebot.load_from_json("plugin_config.json", encoding="utf-8")
```
:::tip 提示
如果 JSON 配置文件中的字段无法满足你的需求,可以使用 [`load_all_plugins`](#load_all_plugins) 方法自行读取配置来加载插件。
:::
### `load_from_toml`
通过 TOML 文件加载插件,是 [`load_all_plugins`](#load_all_plugins) 的 TOML 变种。通过读取 TOML 文件中的 `[tool.nonebot]` Table 中的 `plugins``plugin_dirs` Array 进行加载。例如:
```toml title=plugin_config.toml
[tool.nonebot]
plugins = ["path.to.your.plugin"]
plugin_dirs = ["path/to/your/plugins"]
```
```python
nonebot.load_from_toml("plugin_config.toml", encoding="utf-8")
```
:::tip 提示
如果 TOML 配置文件中的字段无法满足你的需求,可以使用 [`load_all_plugins`](#load_all_plugins) 方法自行读取配置来加载插件。
:::
### `load_builtin_plugin`
加载一个内置插件,传入的插件名必须为 NoneBot 内置插件。该方法是 [`load_plugin`](#load_plugin) 的封装。例如:
```python
nonebot.load_builtin_plugin("echo")
```
### `load_builtin_plugins`
加载传入插件列表中的所有内置插件。例如:
```python
nonebot.load_builtin_plugins("echo", "single_session")
```
### 其他加载方式
有关其他插件加载的方式,可参考[跨插件访问](../advanced/requiring.md)和[嵌套插件](../advanced/plugin-nesting.md)。