2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
|
|
|
|
配置
|
|
|
|
|
====
|
|
|
|
|
|
|
|
|
|
NoneBot 使用 `pydantic`_ 以及 `python-dotenv`_ 来读取配置。
|
|
|
|
|
|
|
|
|
|
配置项需符合特殊格式或 json 序列化格式。详情见 `pydantic Field Type`_ 文档。
|
|
|
|
|
|
|
|
|
|
.. _pydantic:
|
|
|
|
|
https://pydantic-docs.helpmanual.io/
|
|
|
|
|
.. _python-dotenv:
|
|
|
|
|
https://saurabh-kumar.com/python-dotenv/
|
|
|
|
|
.. _pydantic Field Type:
|
|
|
|
|
https://pydantic-docs.helpmanual.io/usage/types/
|
|
|
|
|
"""
|
2020-08-07 11:18:02 +08:00
|
|
|
|
import os
|
|
|
|
|
from pathlib import Path
|
2020-08-06 17:54:55 +08:00
|
|
|
|
from datetime import timedelta
|
2020-07-04 22:51:10 +08:00
|
|
|
|
from ipaddress import IPv4Address
|
2021-09-27 00:19:30 +08:00
|
|
|
|
from typing import Any, Set, Dict, Tuple, Union, Mapping, Optional
|
2020-07-04 22:51:10 +08:00
|
|
|
|
|
2020-08-18 17:24:49 +08:00
|
|
|
|
from pydantic import BaseSettings, IPvAnyAddress
|
2021-11-22 23:21:26 +08:00
|
|
|
|
from pydantic.env_settings import (
|
|
|
|
|
SettingsError,
|
|
|
|
|
EnvSettingsSource,
|
|
|
|
|
InitSettingsSource,
|
|
|
|
|
SettingsSourceCallable,
|
|
|
|
|
read_env_file,
|
|
|
|
|
env_file_sentinel,
|
|
|
|
|
)
|
2020-08-07 11:18:02 +08:00
|
|
|
|
|
2021-12-27 02:26:02 +08:00
|
|
|
|
from nonebot.log import logger
|
|
|
|
|
from nonebot.utils import escape_tag
|
|
|
|
|
|
2020-08-07 11:18:02 +08:00
|
|
|
|
|
2021-02-28 00:35:40 +08:00
|
|
|
|
class CustomEnvSettings(EnvSettingsSource):
|
|
|
|
|
def __call__(self, settings: BaseSettings) -> Dict[str, Any]:
|
2020-08-07 11:18:02 +08:00
|
|
|
|
"""
|
|
|
|
|
Build environment variables suitable for passing to the Model.
|
|
|
|
|
"""
|
|
|
|
|
d: Dict[str, Optional[str]] = {}
|
|
|
|
|
|
2021-02-28 00:35:40 +08:00
|
|
|
|
if settings.__config__.case_sensitive:
|
2021-12-16 17:28:57 +08:00
|
|
|
|
env_vars: Mapping[str, Optional[str]] = os.environ # pragma: no cover
|
2020-08-07 11:18:02 +08:00
|
|
|
|
else:
|
|
|
|
|
env_vars = {k.lower(): v for k, v in os.environ.items()}
|
|
|
|
|
|
2020-08-13 18:16:59 +08:00
|
|
|
|
env_file_vars: Dict[str, Optional[str]] = {}
|
2021-11-22 23:21:26 +08:00
|
|
|
|
env_file = (
|
|
|
|
|
self.env_file
|
|
|
|
|
if self.env_file != env_file_sentinel
|
|
|
|
|
else settings.__config__.env_file
|
|
|
|
|
)
|
|
|
|
|
env_file_encoding = (
|
|
|
|
|
self.env_file_encoding
|
|
|
|
|
if self.env_file_encoding is not None
|
|
|
|
|
else settings.__config__.env_file_encoding
|
|
|
|
|
)
|
2020-08-07 11:18:02 +08:00
|
|
|
|
if env_file is not None:
|
|
|
|
|
env_path = Path(env_file)
|
|
|
|
|
if env_path.is_file():
|
|
|
|
|
env_file_vars = read_env_file(
|
2020-08-13 18:16:59 +08:00
|
|
|
|
env_path,
|
|
|
|
|
encoding=env_file_encoding,
|
2021-11-22 23:21:26 +08:00
|
|
|
|
case_sensitive=settings.__config__.case_sensitive,
|
|
|
|
|
)
|
2020-08-07 11:18:02 +08:00
|
|
|
|
env_vars = {**env_file_vars, **env_vars}
|
|
|
|
|
|
2021-02-28 00:35:40 +08:00
|
|
|
|
for field in settings.__fields__.values():
|
2020-08-07 11:18:02 +08:00
|
|
|
|
env_val: Optional[str] = None
|
2020-12-06 02:30:19 +08:00
|
|
|
|
for env_name in field.field_info.extra["env_names"]:
|
2020-08-07 11:18:02 +08:00
|
|
|
|
env_val = env_vars.get(env_name)
|
|
|
|
|
if env_name in env_file_vars:
|
|
|
|
|
del env_file_vars[env_name]
|
|
|
|
|
if env_val is not None:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if env_val is None:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
if field.is_complex():
|
|
|
|
|
try:
|
2021-02-28 00:35:40 +08:00
|
|
|
|
env_val = settings.__config__.json_loads(env_val)
|
2021-12-16 17:28:57 +08:00
|
|
|
|
except ValueError as e: # pragma: no cover
|
2021-12-10 17:01:56 +08:00
|
|
|
|
raise SettingsError(
|
|
|
|
|
f'error parsing JSON for "{env_name}"' # type: ignore
|
|
|
|
|
) from e
|
2020-08-07 11:18:02 +08:00
|
|
|
|
d[field.alias] = env_val
|
|
|
|
|
|
|
|
|
|
if env_file_vars:
|
|
|
|
|
for env_name, env_val in env_file_vars.items():
|
2021-11-22 23:21:26 +08:00
|
|
|
|
if (env_val is None or len(env_val) == 0) and env_name in env_vars:
|
2020-09-14 22:38:03 +08:00
|
|
|
|
env_val = env_vars[env_name]
|
2020-08-07 11:18:02 +08:00
|
|
|
|
try:
|
2021-02-28 00:35:40 +08:00
|
|
|
|
if env_val:
|
2021-12-27 02:26:02 +08:00
|
|
|
|
env_val = settings.__config__.json_loads(env_val.strip())
|
2020-08-07 11:18:02 +08:00
|
|
|
|
except ValueError as e:
|
2021-12-27 02:26:02 +08:00
|
|
|
|
logger.opt(colors=True, exception=e).trace(
|
|
|
|
|
f"Error while parsing JSON for {escape_tag(env_name)}. Assumed as string."
|
|
|
|
|
)
|
2020-08-07 11:18:02 +08:00
|
|
|
|
|
|
|
|
|
d[env_name] = env_val
|
|
|
|
|
|
|
|
|
|
return d
|
2020-07-04 22:51:10 +08:00
|
|
|
|
|
2021-02-28 00:35:40 +08:00
|
|
|
|
|
|
|
|
|
class BaseConfig(BaseSettings):
|
2021-12-16 17:28:57 +08:00
|
|
|
|
# dummy getattr for pylance checking, actually not used
|
|
|
|
|
def __getattr__(self, name: str) -> Any: # pragma: no cover
|
2020-08-20 15:07:05 +08:00
|
|
|
|
return self.__dict__.get(name)
|
|
|
|
|
|
2021-02-28 00:35:40 +08:00
|
|
|
|
class Config:
|
|
|
|
|
@classmethod
|
|
|
|
|
def customise_sources(
|
|
|
|
|
cls,
|
2021-03-01 00:30:06 +08:00
|
|
|
|
init_settings: InitSettingsSource,
|
|
|
|
|
env_settings: EnvSettingsSource,
|
2021-02-28 00:35:40 +08:00
|
|
|
|
file_secret_settings: SettingsSourceCallable,
|
|
|
|
|
) -> Tuple[SettingsSourceCallable, ...]:
|
2021-03-01 00:30:06 +08:00
|
|
|
|
common_config = init_settings.init_kwargs.pop("_common_config", {})
|
2021-11-22 23:21:26 +08:00
|
|
|
|
return (
|
|
|
|
|
init_settings,
|
|
|
|
|
CustomEnvSettings(
|
|
|
|
|
env_settings.env_file, env_settings.env_file_encoding
|
|
|
|
|
),
|
|
|
|
|
InitSettingsSource(common_config),
|
|
|
|
|
file_secret_settings,
|
|
|
|
|
)
|
2021-02-28 00:35:40 +08:00
|
|
|
|
|
2020-07-04 22:51:10 +08:00
|
|
|
|
|
2021-01-27 11:39:34 +08:00
|
|
|
|
class Env(BaseConfig):
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
|
|
|
|
运行环境配置。大小写不敏感。
|
|
|
|
|
|
2022-01-12 18:19:21 +08:00
|
|
|
|
将会从 `nonebot.init 参数` > `环境变量` > `.env 环境配置文件` 的优先级读取配置。
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
|
|
|
|
|
2020-07-04 22:51:10 +08:00
|
|
|
|
environment: str = "prod"
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
2022-01-12 18:19:21 +08:00
|
|
|
|
当前环境名。 NoneBot 将从 `.env.{environment}` 文件中加载配置。
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
2020-07-04 22:51:10 +08:00
|
|
|
|
|
|
|
|
|
class Config:
|
2021-01-27 11:39:34 +08:00
|
|
|
|
extra = "allow"
|
2020-07-04 22:51:10 +08:00
|
|
|
|
env_file = ".env"
|
|
|
|
|
|
|
|
|
|
|
2020-08-07 11:18:02 +08:00
|
|
|
|
class Config(BaseConfig):
|
|
|
|
|
"""
|
2020-08-20 15:07:05 +08:00
|
|
|
|
NoneBot 主要配置。大小写不敏感。
|
2020-08-07 11:18:02 +08:00
|
|
|
|
|
2022-01-12 18:19:21 +08:00
|
|
|
|
除了 NoneBot 的配置项外,还可以自行添加配置项到 `.env.{environment}` 文件中。
|
|
|
|
|
这些配置将会在 json 反序列化后一起带入 `Config` 类中。
|
2020-08-07 11:18:02 +08:00
|
|
|
|
"""
|
2021-11-22 23:21:26 +08:00
|
|
|
|
|
2022-01-04 14:36:32 +08:00
|
|
|
|
_common_config: dict
|
|
|
|
|
_env_file: str
|
|
|
|
|
|
2020-08-01 22:03:40 +08:00
|
|
|
|
# nonebot configs
|
2021-12-25 14:57:29 +08:00
|
|
|
|
driver: str = "~fastapi"
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
2022-01-12 18:19:21 +08:00
|
|
|
|
NoneBot 运行所使用的 `Driver` 。继承自 `nonebot.drivers.Driver` 。
|
2021-06-20 23:38:42 +08:00
|
|
|
|
|
2022-01-12 18:19:21 +08:00
|
|
|
|
配置格式为 `<module>[:<Driver>][+<module>[:<Mixin>]]*`。
|
2021-12-25 14:57:29 +08:00
|
|
|
|
|
2022-01-12 18:19:21 +08:00
|
|
|
|
`~` 为 `nonebot.drivers.` 的缩写。
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
2020-08-18 17:24:49 +08:00
|
|
|
|
host: IPvAnyAddress = IPv4Address("127.0.0.1") # type: ignore
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
2022-01-12 18:16:05 +08:00
|
|
|
|
NoneBot 的 HTTP 和 WebSocket 服务端监听的 IP/主机名。
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
2020-07-04 22:51:10 +08:00
|
|
|
|
port: int = 8080
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
2022-01-12 18:16:05 +08:00
|
|
|
|
NoneBot 的 HTTP 和 WebSocket 服务端监听的端口。
|
2020-08-20 15:07:05 +08:00
|
|
|
|
"""
|
2021-12-28 15:19:53 +08:00
|
|
|
|
log_level: Union[int, str] = "INFO"
|
2021-04-19 21:15:10 +08:00
|
|
|
|
"""
|
2022-01-12 18:19:21 +08:00
|
|
|
|
配置 NoneBot 日志输出等级,可以为 `int` 类型等级或等级名称,参考 `loguru 日志等级`_。
|
2021-04-19 21:15:10 +08:00
|
|
|
|
|
|
|
|
|
:示例:
|
|
|
|
|
|
|
|
|
|
.. code-block:: default
|
|
|
|
|
|
|
|
|
|
LOG_LEVEL=25
|
|
|
|
|
LOG_LEVEL=INFO
|
|
|
|
|
|
|
|
|
|
.. _loguru 日志等级:
|
|
|
|
|
https://loguru.readthedocs.io/en/stable/api/logger.html#levels
|
|
|
|
|
"""
|
2020-07-04 22:51:10 +08:00
|
|
|
|
|
2020-08-01 22:03:40 +08:00
|
|
|
|
# bot connection configs
|
2021-11-22 23:21:26 +08:00
|
|
|
|
api_timeout: Optional[float] = 30.0
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2022-01-12 18:16:05 +08:00
|
|
|
|
API 请求超时时间,单位: 秒。
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2020-08-01 22:03:40 +08:00
|
|
|
|
|
|
|
|
|
# bot runtime configs
|
2020-12-17 21:09:30 +08:00
|
|
|
|
superusers: Set[str] = set()
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2022-01-12 18:16:05 +08:00
|
|
|
|
机器人超级用户。
|
2020-11-30 11:08:00 +08:00
|
|
|
|
|
2020-11-30 12:43:44 +08:00
|
|
|
|
:示例:
|
2020-08-20 16:34:07 +08:00
|
|
|
|
|
2020-09-14 21:40:05 +08:00
|
|
|
|
.. code-block:: default
|
2020-08-20 16:34:07 +08:00
|
|
|
|
|
2021-01-05 23:06:36 +08:00
|
|
|
|
SUPERUSERS=["12345789"]
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2020-10-06 22:29:05 +08:00
|
|
|
|
nickname: Set[str] = set()
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2022-01-12 18:16:05 +08:00
|
|
|
|
机器人昵称。
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2020-08-17 16:09:41 +08:00
|
|
|
|
command_start: Set[str] = {"/"}
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2022-01-12 18:16:05 +08:00
|
|
|
|
命令的起始标记,用于判断一条消息是不是命令。
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2020-08-17 16:09:41 +08:00
|
|
|
|
command_sep: Set[str] = {"."}
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2022-01-12 18:16:05 +08:00
|
|
|
|
命令的分隔标记,用于将文本形式的命令切分为元组(实际的命令名)。
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2020-08-06 17:54:55 +08:00
|
|
|
|
session_expire_timeout: timedelta = timedelta(minutes=2)
|
2020-08-20 16:34:07 +08:00
|
|
|
|
"""
|
2022-01-12 18:16:05 +08:00
|
|
|
|
等待用户回复的超时时间。
|
2020-11-30 11:08:00 +08:00
|
|
|
|
|
2020-11-30 12:43:44 +08:00
|
|
|
|
:示例:
|
2020-08-20 16:34:07 +08:00
|
|
|
|
|
2020-09-14 21:40:05 +08:00
|
|
|
|
.. code-block:: default
|
2020-08-20 16:34:07 +08:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
"""
|
2020-07-04 22:51:10 +08:00
|
|
|
|
|
2021-01-12 17:55:27 +08:00
|
|
|
|
# adapter configs
|
|
|
|
|
# adapter configs are defined in adapter/config.py
|
|
|
|
|
|
2020-08-01 22:03:40 +08:00
|
|
|
|
# custom configs
|
2020-08-07 11:18:02 +08:00
|
|
|
|
# custom configs can be assigned during nonebot.init
|
|
|
|
|
# or from env file using json loads
|
2020-07-04 22:51:10 +08:00
|
|
|
|
|
|
|
|
|
class Config:
|
2020-08-07 11:18:02 +08:00
|
|
|
|
extra = "allow"
|
2020-07-04 22:51:10 +08:00
|
|
|
|
env_file = ".env.prod"
|