配置
应用配置是一个常见但棘手的问题,特别是在实际项目中。
你经常需要创建依赖于动态设置的依赖项——比如设置数据库引擎的隔离级别,或根据环境调整超时时间。
Lihil 提供了一个统一的配置系统,支持多个来源——文件、环境变量和命令行参数——允许开箱即用的安全和灵活的配置管理。
配置加载和解析
from lihil.config import lhl_read_config, AppConfig
Lihil 自动从以下来源加载配置值,按递增优先级顺序:
- 用户提供的配置文件
- 环境变量
- 命令行参数
这种分层方法反映了现实世界的需求:
-
静态和公共配置(如服务器端口或日志级别)可以放在版本控制的文件中(例如 settings.toml)。
-
敏感数据(如 API 密钥或数据库密码)应该来自环境变量以避免意外暴露。
-
对于临时覆盖(如使用不同端口进行调试或切换标志),命令行参数提供最大的灵活性。
从不同来源读取配置
config = lhl_read_config("settings.toml", config_type=MyAppConfig)
这会自动从所有三个来源读取并将它们合并到一个配置实例中。
你可以提供多个文件,它们将按顺序读取。
config = lhl_read_config("settings.toml", "dev.env", "prod.env")
手动设置配置
from lihil import AppConfig, Lihil
lhl = Lihil(app_config = AppConfig())
或直接使用 lhl_set_config():
from lihil.config import lhl_set_config
lhl_set_config(MyConfig())
不带参数调用会重置为默认值:
lhl_set_config()
获取当前配置
使用 lhl_get_config()
从应用的任何地方检索活动配置:
from lihil.config import lhl_get_config
config = lhl_get_config()
扩展 AppConfig
你可以扩展 AppConfig 来定义自己的设置:
from lihil.app_config import AppConfig
class MyAppConfig(AppConfig):
my_custom_setting: str = "default"
然后加载它:
from lihil.config import lhl_read_config
config = lhl_read_config("settings.toml", config_type=MyAppConfig)
自动生成的命令行参数
如果你通过继承 AppConfig
扩展配置,
额外的属性也会作为命令行参数生成,你可以传递它们来覆盖。
示例配置文件 (config.toml)
[lihil]
IS_PROD = true
VERSION = "1.0.0"
[lihil.server]
HOST = "127.0.0.1"
PORT = 9000
[lihil.oas]
TITLE = "My API"
命令行覆盖
任何字段都可以通过命令行覆盖:
python app.py --is_prod --server.port 8080
使用其他配置模式(例如 Pydantic)
如果你使用不同的验证系统(如 Pydantic),你可以自己解析并手动注入:
from lihil.config import lhl_set_config, lhl_get_config
app_config = PydanticSettings()
lhl_set_config(app_config)
你的配置需要实现 IAppConfig
接口。
AppConfig 接口
class IOASConfig(Protocol):
@property
def OAS_PATH(self) -> str: ...
@property
def DOC_PATH(self) -> str: ...
@property
def TITLE(self) -> str: ...
@property
def PROBLEM_PATH(self) -> str: ...
@property
def PROBLEM_TITLE(self) -> str: ...
@property
def VERSION(self) -> str: ...
class IServerConfig(Protocol):
@property
def HOST(self) -> str: ...
@property
def PORT(self) -> int: ...
@property
def WORKERS(self) -> int: ...
@property
def RELOAD(self) -> bool: ...
@property
def ROOT_PATH(self) -> bool: ...
def asdict(self) -> dict[str, Any]: ...
class IAppConfig(Protocol):
@property
def VERSION(self) -> str: ...
@property
def server(self) -> IServerConfig: ...
@property
def oas(self) -> IOASConfig: ...
总结
- 继承
AppConfig
进行扩展,使用lhl_read_config
加载配置,然后通过lhl_set_config
设置配置,适用于大多数情况 - 如果你手动构建配置(例如通过 Pydantic),实现
IAppConfig
接口。 - 调用
lhl_get_config
在任何地方访问配置。 - 敏感值应该放在环境变量中。
- 使用命令行参数进行快速、本地覆盖,例如调试。