配置
配置是项目中非常重要的一部分,为了方便我们控制机器人的行为,NoneBot 提供了一套配置系统。下面我们将会补充指南中的天气插件,使其能够读取用户配置。在这之前,我们需要先了解一下配置系统,如果你已经了解了 NoneBot 中的配置方法,可以跳转到编写插件配置。
NoneBot 使用 pydantic
以及 python-dotenv
来读取 dotenv 配置文件以及环境变量,从而控制机器人行为。配置文件需要符合 dotenv 格式,复杂数据类型需使用 JSON 格式或 pydantic 支持格式填写。
NoneBot 内置的配置项列表及含义可以在内置配置项中查看。
配置项的加载
在 NoneBot 中,我们可以把配置途径分为 直接传入、系统环境变量、dotenv 配置文件 三种,其加载优先级依次由高到低。
直接传入
在 NoneBot 初始化的过程中,可以通过 nonebot.init()
传入任意合法的 Python 变量,也可以在初始化完成后直接赋值。
通常,在初始化前的传参会在机器人的入口文件(如 bot.py
)中进行,而初始化后的赋值可以在任何地方进行。
import nonebot
# 初始化时
nonebot.init(custom_config1="config on init")
# 初始化后
config = nonebot.get_driver().config
config.custom_config1 = "changed after init"
config.custom_config2 = "new config after init"
系统环境变量
在 dotenv 配置文件中定义的配置项,也会在环境变量中进行寻找。如果在环境变量中发现同名配置项(大小写不敏感),将会覆盖 dotenv 中所填值。
例如,在 dotenv 配置文件中存在配置项 custom_config
:
CUSTOM_CONFIG=config in dotenv
同时,设置环境变量:
# windows
set CUSTOM_CONFIG "config in environment variables"
# linux/macOS
export CUSTOM_CONFIG="config in environment variables"
那最终 NoneBot 所读取的内容为环境变量中的内容,即 config in environment variables
。
注意
NoneBot 不会自发读取未被定义的配置项的环境变量,如果需要读取某一环境变量需要在 dotenv 配置文件中进行声明。
dotenv 配置文件
dotenv 是一种便捷的跨平台配置通用模式,也是我们推荐的配置方式。
NoneBot 在启动时将会从系统环境变量或者 .env
文件中寻找配置项 ENVIRONMENT
(大小写不敏感),默认值为 prod
。这将决定 NoneBot 后续进一步加载环境配置的文件路径 .env.{ENVIRONMENT}
。
配置项解析
dotenv 文件中的配置值使用 JSON 进行解析。如果配置项值无法被解析,将作为字符串处理。例如:
STRING_CONFIG=some string
LIST_CONFIG=[1, 2, 3]
DICT_CONFIG={"key": "value"}
MULTILINE_CONFIG='
[
{
"item_key": "item_value"
}
]
'
EMPTY_CONFIG=
NULL_CONFIG
将被解析为:
dotenv_config = {
"string_config": "some string",
"list_config": [1, 2, 3],
"dict_config": {"key": "value"},
"multiline_config": [{"item_key": "item_value"}],
"empty_config": "",
"null_config": None
}
特别的,NoneBot 支持使用 env_nested_delimiter
配置嵌套字典,在层与层之间使用 __
分隔即可:
DICT={"k1": "v1", "k2": null}
DICT__K2=v2
DICT__K3=v3
DICT__INNER__K4=v4
将被解析为:
dotenv_config = {
"dict": {
"k1": "v1",
"k2": "v2",
"k3": "v3",
"inner": {
"k4": "v4"
}
}
}
.env 文件
.env
文件是基础配置文件,该文件中的配置项在不同环境下都会被加载,但会被 .env.{ENVIRONMENT}
文件中的配置所覆盖。
我们可以在 .env
文件中写入当前的环境信息:
ENVIRONMENT=dev
COMMON_CONFIG=common config # 这个配置项在任何环境中都会被加载
这样,我们在启动 NoneBot 时就会从 .env.dev
文件中加载剩余配置项。
提示
在生产环境中,可以通过设置环境变量 ENVIRONMENT=prod
来确保 NoneBot 读取正确的环境配置。
.env.{ENVIRONMENT} 文件
.env.{ENVIRONMENT}
文件类似于预设,可以让我们在多套不同的配置方案中灵活切换,默认 NoneBot 会读取 .env.prod
配置。如果你使用了 nb-cli
创建 simple
项目,那么将含有两套预设配置:.env.dev
和 .env.prod
。
在 NoneBot 初始化时,可以指定加载某个环境配置文件:
nonebot.init(_env_file=".env.dev")
这将忽略在 .env
文件或环境变量中指定的 ENVIRONMENT
配置项。
读取配置项
NoneBot 的全局配置对象可以通过 driver
获取,如:
import nonebot
config = nonebot.get_driver().config
如果我们需要获取某个配置项,可以直接通过 config
对象的属性访问:
superusers = config.superusers
如果配置项不存在,将会抛出异常。
插件配置
在一个涉及大量配置项的项目中,通过直接读取配置项的方式显然并不高效。同时,由于额外的全局配置项没有预先定义,开发时编辑器将无法提示字段与类型,并且运行时没有对配置项直接进行合法性检查。那么就需要一种方式来规范定义插件配置项。
在 NoneBot 中,我们使用强大高效的 pydantic
来定义配置模型,这个模型可以被用于配置的读取和类型检查等。例如在 weather
插件目录中新建 config.py
来定义一个模型:
from pydantic import BaseModel, validator
class Config(BaseModel):
weather_api_key: str
weather_command_priority: int = 10
weather_plugin_enabled: bool = True
@validator("weather_command_priority")
def check_priority(cls, v):
if isinstance(v, int) and v >= 1:
return v
raise ValueError("weather command priority must be an integer and greater than 1")
在 config.py
中,我们定义了一个 Config
类,它继承自 pydantic.BaseModel
,并定义了一些配置项。在 Config
类中,我们还定义了一个 check_priority
方法,它用于检查 weather_command_priority
配置项的合法性。更多关于 pydantic
的编写方式,可以参考 pydantic 官方文档。
在定义好配置模型后,我们可以在插件加载时获取全局配置,导入插件自身的配置模型并使用:
from nonebot import get_driver
from .config import Config
plugin_config = Config.parse_obj(get_driver().config)
weather = on_command(
"天气",
rule=to_me(),
aliases={"weather", "查天气"},
priority=plugin_config.weather_command_priority,
block=True,
)
然后,我们便可以从 plugin_config
中读取配置了,例如 plugin_config.weather_api_key
。
这种方式可以简洁、高效地读取配置项,同时也可以设置默认值或者在运行时对配置项进行合法性检查,防止由于配置项导致的插件出错等情况出现。
提示
发布插件应该为自身的事件响应器提供可配置的优先级,以便插件使用者可以自定义多个插件间的响应顺序。
内置配置项
配置项 API 文档可以前往 Config 类查看。
Driver
- 类型:
str
- 默认值:
"~fastapi"
NoneBot 运行所使用的驱动器。具体配置方法可以参考安装驱动器和选择驱动器。
- dotenv
- 系统环境变量
- 直接传入
DRIVER=~fastapi+~httpx+~websockets
# windows
set DRIVER '~fastapi+~httpx+~websockets'
# linux/macOS
export DRIVER='~fastapi+~httpx+~websockets'
import nonebot
nonebot.init(driver="~fastapi+~httpx+~websockets")
Host
- 类型:
IPvAnyAddress
- 默认值:
127.0.0.1
当 NoneBot 作为服务端时,监听的 IP / 主机名。
- dotenv
- 系统环境变量
- 直接传入
HOST=127.0.0.1
# windows
set HOST '127.0.0.1'
# linux/macOS
export HOST='127.0.0.1'
import nonebot
nonebot.init(host="127.0.0.1")
Port
- 类型:
int
(1 ~ 65535) - 默认值:
8080
当 NoneBot 作为服务端时,监听的端口。
- dotenv
- 系统环境变量
- 直接传入
PORT=8080
# windows
set PORT '8080'
# linux/macOS
export PORT='8080'
import nonebot
nonebot.init(port=8080)
Log Level
- 类型:
int | str
- 默认值:
INFO
NoneBot 日志输出等级,可以为 int
类型等级或等级名称。具体等级对照表参考 loguru 日志等级。
提示
日志等级名称应为大写,如 INFO
。
- dotenv
- 系统环境变量
- 直接传入
LOG_LEVEL=DEBUG
# windows
set LOG_LEVEL 'DEBUG'
# linux/macOS
export LOG_LEVEL='DEBUG'
import nonebot
nonebot.init(log_level="DEBUG")
API Timeout
- 类型:
float | None
- 默认值:
30.0
调用平台接口的超时时间,单位为秒。None
表示不设置超时时间。
- dotenv
- 系统环境变量
- 直接传入
API_TIMEOUT=10.0
# windows
set API_TIMEOUT '10.0'
# linux/macOS
export API_TIMEOUT='10.0'
import nonebot
nonebot.init(api_timeout=10.0)
SuperUsers
- 类型:
set[str]
- 默认值:
set()
机器人超级用户,可以使用权限 SUPERUSER
。
- dotenv
- 系统环境变量
- 直接传入
SUPERUSERS=["123123123"]
# windows
set SUPERUSERS '["123123123"]'
# linux/macOS
export SUPERUSERS='["123123123"]'
import nonebot
nonebot.init(superusers={"123123123"})
Nickname
- 类型:
set[str]
- 默认值:
set()
机器人昵称,通常协议适配器会根据用户是否 @user 或者是否以机器人昵称开头来判断是否是向机器人发送的消息。
- dotenv
- 系统环境变量
- 直接传入
NICKNAME=["bot"]
# windows
set NICKNAME '["bot"]'
# linux/macOS
export NICKNAME='["bot"]'
import nonebot
nonebot.init(nickname={"bot"})
Command Start 和 Command Separator
- 类型:
set[str]
- 默认值:
- Command Start:
{"/"}
- Command Separator:
{"."}
- Command Start:
命令消息的起始符和分隔符。用于 command
规则。
- dotenv
- 系统环境变量
- 直接传入
COMMAND_START=["/", ""]
COMMAND_SEP=[".", " "]
# windows
set COMMAND_START '["/", ""]'
set COMMAND_SEP '[".", " "]'
# linux/macOS
export COMMAND_START='["/", ""]'
export COMMAND_SEP='[".", " "]'
import nonebot
nonebot.init(command_start={"/", ""}, command_sep={".", " "})
Session Expire Timeout
- 类型:
timedelta
- 默认值:
timedelta(minutes=2)
用户会话超时时间,配置格式参考 Datetime Types,可以为单位为秒的 int | float
等。
- dotenv
- 系统环境变量
- 直接传入
SESSION_EXPIRE_TIMEOUT=120
# windows
set SESSION_EXPIRE_TIMEOUT '120'
# linux/macOS
export SESSION_EXPIRE_TIMEOUT='120'
import nonebot
nonebot.init(session_expire_timeout=120)