yaml-config-loader
轻量级 Python 配置加载工具包,提供类似 Spring Boot 的配置管理能力。
功能特性
- YAML 配置加载:自动递归查找
application.yml,全局缓存配置 - 环境变量解析:yml 中的
${ENV_VAR}/${ENV_VAR:-default}自动替换为环境变量值 - @configuration_properties:类似 Spring Boot 的配置属性绑定,支持嵌套 dataclass 自动转换
- 标量类型强转:按字段注解将配置值强转为
str/int/float/bool - List[X] 泛型转换:
Optional[List[SkillConfig]]递归转换为 dataclass 实例列表 - @Value:类似 Spring Boot 的
@Value("${...}"),单个配置值注入,支持嵌套路径和默认值 - aliases 别名映射:yml 中的数字 key(如
"1002")、关键字等映射到合法的 Python 属性名 - aliases 嵌套路径:aliases 值含
.(如"otherMath.100.a.100")时视为完整层级路径,严格按 yml 层级钻取,解决不同层级同名 key 的歧义 - 字段级 yml_key 显式声明:嵌套 dataclass 字段用
field(metadata={"yml_key": "100"})精确声明映射,变量名任意,不依赖命名约定 - 自动 kebab-case → snake_case 转换:yml 中的
api-key自动映射到 Python 的api_key,无需手动配置 - @component 单例容器:轻量级 IoC 容器,线程安全单例,自动注册和获取 Bean
- DotDict 点访问字典:支持
config.user.name方式访问嵌套字典 - 零配置:开箱即用,无需复杂设置
安装
pip install yaml-config-loader
v1.1.0 包名变更说明:import 包名已从
config_loader更名为yaml_config_loader,与 PyPI 包名保持一致,这样 PyCharm 等 IDE 能自动识别并提示"安装软件包"。旧代码
from config_loader import ...仍然可用(兼容别名包),但推荐新代码使用from yaml_config_loader import ...。
更新日志
v1.3.0(最新)
新增功能:
- @Value 单值注入:类似 Spring Boot
@Value("${...}"),支持两种用法Annotated + @value_config(推荐,保留类型注解)- 描述符方式(简洁,无需类型注解)
- aliases 别名映射:解决 yml 中数字 key(如
"1002")、Python 关键字(如class)无法作为属性名的问题 - 自动 kebab-case → snake_case 转换:yml 中的
api-key自动映射到 Python 的api_key,嵌套对象也自动转换,无需手动写 aliases - aliases 嵌套路径:aliases 值含
.(如"b_a": "otherMath.100.a.100")视为相对前缀的完整层级路径,严格按 yml 层级钻取绑定,不同层级的同名数字 key 不会混淆 - 字段级 yml_key 显式声明:嵌套 dataclass 字段用
field(metadata={"yml_key": "100"})精确声明对应的 yml key,变量名任意命名,不依赖X_100命名约定
修复的问题:
${ENV_VAR}环境变量不解析:yaml_loader 新增_resolve_env_vars递归解析${ENV_VAR}与${ENV_VAR:-default},加载与回退读取均生效,不再把字面量传给下游- 缓存为空时回退读文件依赖相对路径 + 静默吞错:回退改为
find_yaml()项目级搜索(绝对路径),不依赖 CWD;读取失败/文件未找到均输出logger.warning,不再静默绑成{} - 绑定失败完全静默:前缀不存在、字段缺 key、文件未找到、aliases 目标属性未声明、嵌套路径不存在,五种情况均输出
logger.warning告警 - 不做标量类型强转:新增
_coerce_scalar,按字段注解将配置值强转为str/int/float/bool(bool 支持"false"/"0"/"no"/"off"等字符串),注解为float时0.8不再变字符串 - List[dataclass] 泛型不转换:新增
List[X]递归转换,Optional[List[SkillConfig]]实际拿到的是List[SkillConfig]实例列表,注解与运行时类型一致 - @component 返回工厂函数:改为返回类本身 +
__new__单例,isinstance、继承、get_type_hints、反射全部正常,get_bean()直接返回实例 - functools.wraps 污染类属性:移除
@component中的functools.wraps(cls);@configuration_properties使用functools.wraps(cls, updated=[])避免类__dict__复制 - init_config import 即执行 + verbose 打印:
init_config(verbose=False)默认静默(print 仅在 verbose=True),日志统一走 logging 体系,不污染控制台 - 单例非线程安全 / 注册表无锁:
__new__双检锁 + 注册表锁保证线程安全;同名类覆盖注册表时输出logger.warning提示 - _get_caller_dir 依赖 inspect.stack:支持
set_config_search_dir()显式指定搜索起点 + 调用方目录缓存(同进程只计算一次),inspect.stack 仅兜底且失败回退 cwd,兼容 PyInstaller 等场景 - get_session 直接崩:非标识符 yml key(纯数字
"1003"等)绑定到实例__dict__,getattr(self, "1003")动态访问可用,get_session不再崩溃
优化:
get_bean()支持直接传类对象get_bean(MyService),不再只能传类名字符串DotDict构造函数递归转换嵌套 dict,DotDict(config)直接支持点访问
v1.1.0
- import 包名从
config_loader更名为yaml_config_loader(与 PyPI 包名一致) - 保留
config_loader兼容别名包,老用户代码无需修改
v1.0.0
- 初始版本:YAML 配置加载、@configuration_properties、@component、DotDict
快速开始
1. 创建 application.yml
user:
name: "张三"
age: 25
email: "zhangsan@example.com"
address:
city: "北京"
street: "长安街"
# kebab-case(连字符)自动转换为 snake_case(下划线)
api-key: "abc123"
server-timeout: 30
# 纯数字 key 自动后缀匹配(如 _1002 / item_1002),也可用 aliases 显式声明
"1002": "编号1002的值"
server:
port: 8080
host: "localhost"
2. 初始化配置
from yaml_config_loader import init_config
# 一行初始化配置(类似 load_dotenv(find_dotenv()))
# 自动递归查找 application.yml 并加载到全局缓存
init_config()
3. 使用 @configuration_properties 绑定配置
from dataclasses import dataclass
from typing import Optional
from yaml_config_loader import configuration_properties, component, DotDict
@component
@configuration_properties(prefix="user")
@dataclass
class UserConfig:
name: str = None
age: int = None
email: str = None
address: Optional[DotDict] = None # 嵌套配置自动转为 DotDict
def show(self):
print(f"姓名: {self.name}")
print(f"年龄: {self.age}")
print(f"城市: {self.address.city}") # 点访问嵌套配置
user = UserConfig()
user.show()
4. 嵌套 dataclass 自动转换
from dataclasses import dataclass
from typing import Optional
from yaml_config_loader import configuration_properties
@dataclass
class Address:
city: str = None
street: str = None
@configuration_properties(prefix="user")
@dataclass
class UserConfig:
name: str = None
address: Optional[Address] = None # 自动转为 Address 实例
user = UserConfig()
print(user.address.city) # 北京
5. 自动 kebab-case → snake_case 转换
yml 中的 api-key(连字符)自动映射到 Python 的 api_key(下划线),不需要写 aliases,嵌套对象也自动转换。
yml 配置:
user:
api-key: "abc123"
server-timeout: 30
nested:
my-name: "嵌套配置"
Python 代码:
from dataclasses import dataclass
from yaml_config_loader import configuration_properties
@configuration_properties(prefix="user")
@dataclass
class UserConfig:
# yml 中的 api-key → 自动映射到 api_key
api_key: str = None
# yml 中的 server-timeout → 自动映射到 server_timeout
server_timeout: int = None
# 嵌套对象中的 my-name → 自动映射到 my_name
nested: dict = None
user = UserConfig()
print(user.api_key) # abc123
print(user.server_timeout) # 30
print(user.nested.my_name) # 嵌套配置
转换规则:
| yml 中的 key | Python 属性名 | 是否需要 aliases |
|---|---|---|
api-key |
api_key |
❌ 自动转换 |
server-timeout |
server_timeout |
❌ 自动转换 |
my-name |
my_name |
❌ 自动转换 |
"1002"(纯数字) |
_1002 / item_1002 等任意 X_1002 形式 |
❌ 自动后缀匹配;也可用 aliases / metadata 显式声明 |
"class"(关键字) |
class_type |
✅ 需要 aliases |
6. aliases 别名映射
当 yml 中的 key 是纯数字(如 "1002")或 Python 关键字(如 class)时,无法作为 Python 属性名,用 aliases 参数做映射。
yml 配置:
user:
"1002": "编号1002的值"
"1003": 1003
"class": "用户类"
Python 代码:
from dataclasses import dataclass
from yaml_config_loader import configuration_properties
@configuration_properties(
prefix="user",
aliases={
"item_1002": "1002", # Python 属性名 item_1002 ← yml key "1002"
"item_1003": "1003", # Python 属性名 item_1003 ← yml key "1003"
"class_type": "class", # Python 属性名 class_type ← yml key "class"
},
)
@dataclass
class UserConfig:
item_1002: str = None
item_1003: int = None
class_type: str = None
user = UserConfig()
print(user.item_1002) # 编号1002的值
print(user.item_1003) # 1003
print(user.class_type) # 用户类
aliases 格式:
aliases={
"Python属性名": "yml中的key名",
}
优先级:
aliases显式映射(优先级最高,同层 key)aliases嵌套路径(值含.,从前缀向下钻取完整层级)- 自动 kebab-case → snake_case 转换
- 纯数字 key 后缀匹配(
"100"匹配任意X_100形式字段) - 直接用 yml key
6.1 aliases 嵌套路径(完整层级映射)
当 yml 中不同层级出现同名 key(如 otherMath.100 与 otherMath.100.a.100 都有 "100")时,同层 key 别名无法区分。aliases 的值含 . 时视为相对前缀的完整层级路径,严格按 yml 层级钻取;变量名(键)可任意命名,被映射者(值)必须写清 yml 层级。
yml 配置:
ai:
otherMath:
"100":
model: qwen3-max
a:
"100":
b: qwen3-max-plus
Python 代码:
from dataclasses import dataclass
from typing import Optional
from yaml_config_loader import configuration_properties
@dataclass
class BConfig:
b: str = None
@configuration_properties(prefix="ai", aliases={
# 变量名任意;值写清 yml 完整层级(相对 ai 前缀),精确指向 a 层下的 "100"
"b_a": "otherMath.100.a.100",
})
class AiConfig:
b_a: Optional[BConfig] = None
conf = AiConfig()
print(conf.b_a.b) # qwen3-max-plus(精确取到 a 层下的 "100",不会与 otherMath 层的 "100" 混淆)
6.2 字段级 yml_key 显式声明(嵌套 dataclass)
嵌套 dataclass 内部也可以用 field(metadata={"yml_key": "..."}) 显式声明字段对应的 yml key:变量名任意命名,映射精确锁定当前层级,不依赖 X_100 之类的命名约定,不同层级出现同名 key 也不会错乱。
yml 配置:
ai:
otherMath:
"100":
model: qwen3-max
a:
"100":
b: qwen3-max-plus
Python 代码:
from dataclasses import dataclass, field
from typing import Optional
from yaml_config_loader import configuration_properties
@dataclass
class BConfig:
b: str = None
@dataclass
class AConfig:
# 变量名任意;yml_key 精确指向当前层级(a 层)的 "100"
b_a: Optional[BConfig] = field(default=None, metadata={"yml_key": "100"})
@dataclass
class ModelConfig:
model: str = None
a: Optional[AConfig] = None
@dataclass
class OtherMathConfig:
item_100: Optional[ModelConfig] = None # 数字 key "100" 自动映射到 item_100
@configuration_properties(prefix="ai")
class AiConfig:
otherMath: Optional[OtherMathConfig] = None
conf = AiConfig()
print(conf.otherMath.item_100.a.b_a.b) # qwen3-max-plus
嵌套 dataclass 内字段的匹配优先级:
metadata={"yml_key": "..."}显式声明(最高,精确匹配当前层级的 key,含 int 型数字 key)- 自动 kebab-case → snake_case 转换
- 纯数字 key 后缀匹配(
"100"匹配任意X_100形式字段) - 直接用 yml key
7. 使用 @Value 注入单个配置值
类似 Spring Boot 的 @Value("${...}"),只读取单个配置值,更轻量灵活。
推荐用法(Annotated + @value_config,保留类型注解):
from typing import Annotated
from yaml_config_loader import init_config, Value, value_config
init_config()
@value_config
class AppConfig:
# 基本用法:读取 user.name
name: Annotated[str, Value(key="user.name", default="未知用户")] = None
# 带默认值:配置不存在时返回 18
age: Annotated[int, Value(key="user.age", default=18)] = None
# 嵌套路径:支持点分隔,如 user.address.city
city: Annotated[str, Value(key="user.address.city", default="未知城市")] = None
# 读取其他前缀的配置
server_port: Annotated[int, Value(key="server.port", default=8080)] = None
app = AppConfig()
print(app.name) # 张三
print(app.age) # 25
print(app.city) # 北京
print(app.server_port) # 8080
简洁用法(描述符方式,无需类型注解):
from yaml_config_loader import init_config, Value
init_config()
class AppConfig:
name = Value("user.name")
age = Value("user.age", default=18)
city = Value("user.address.city", default="未知城市")
说明:Python 语法不支持
@Value直接写在类属性上(@装饰器只能用于def和class),因此用Annotated + @value_config的方式实现等价效果,同时保留类型提示。
@Value 与 @configuration_properties 的区别:
| 特性 | @Value | @configuration_properties |
|---|---|---|
| 适用场景 | 只需要几个配置值 | 需要绑定一整组配置 |
| 用法 | Annotated[str, Value(key="...")] + @value_config |
类装饰器 @configuration_properties(prefix="user") |
| 默认值 | 支持 default=xxx |
字段默认值 |
| 嵌套路径 | 支持点分隔 user.address.city |
自动绑定嵌套 dataclass |
| 类型注解 | ✅ 保留 | ✅ 配合 @dataclass |
| 只读 | ✅ 禁止直接赋值 | ❌ 可修改 |
| kebab-case 自动转换 | ❌ 需手动写完整路径 | ✅ 自动转换 |
| aliases 支持 | ❌ 需手动写完整路径 | ✅ 支持 |
8. 使用单例容器
from yaml_config_loader import component, get_bean
@component
class MyService:
def hello(self):
return "Hello, World!"
# 获取单例实例(支持直接传类对象)
service = get_bean(MyService)
print(service.hello()) # Hello, World!
# 也支持传类名字符串
service2 = get_bean("MyService")
print(service is service2) # True(单例)
9. 直接使用 YAML 加载工具
from yaml_config_loader import load_yaml, get_yaml_config, find_yaml
# 自动查找并加载 application.yml
load_yaml()
# 获取全局配置
config = get_yaml_config()
print(config["user"]["name"]) # 张三
# 查找配置文件路径
path = find_yaml()
print(path)
API 参考
装饰器/类
| 装饰器/类 | 说明 |
|---|---|
@configuration_properties(prefix="xxx", aliases={...}) |
绑定 YAML 配置到类属性,支持 aliases 别名映射(含嵌套路径)和自动 kebab-case 转换 |
@value_config |
类装饰器,扫描 Annotated 中的 Value 元数据,自动创建描述符 |
@component |
注册为单例 Bean |
Value(key="...", default=xxx) |
单个配置值注入描述符(类似 Spring Boot @Value) |
函数
| 函数 | 说明 |
|---|---|
init_config(filename="application.yml", verbose=False) |
一行初始化配置(查找 + 加载,默认静默,print 仅在 verbose=True 时输出) |
set_config_search_dir(dir_path) |
显式指定配置文件搜索起点目录(适用于 PyInstaller 打包等 inspect.stack 不可靠场景) |
load_yaml(path=None) |
加载 YAML 配置到全局缓存 |
find_yaml(filename="application.yml") |
递归查找 application.yml 文件路径 |
get_yaml_config() |
获取全局配置字典 |
get_loaded_yaml_path() |
获取已加载的配置文件路径 |
get_bean(cls_or_name) |
获取单例 Bean 实例(支持类对象或类名) |
list_beans() |
列出所有已注册的 Bean |
to_dot_dict(d, kebab_to_snake=False) |
将普通字典转为 DotDict,可选 kebab-case 转换 |
类
| 类 | 说明 |
|---|---|
DotDict |
支持点访问的字典,构造时递归转换嵌套 dict |
Value |
单个配置值注入描述符,支持嵌套路径和默认值,只读 |
配置文件查找规则
find_yaml() 会按以下顺序递归查找:
- 用户显式指定的目录(调用
set_config_search_dir()时,优先级最高) - 当前脚本所在目录
- 当前目录下的常见配置子目录(
config/、conf/、resources/等) - 定位项目根目录(通过
.git、pyproject.toml等标记) - 在整个项目范围内递归搜索(自动排除
.venv、__pycache__、.git等目录)
支持的文件名:application.yml、application.yaml
搜索起点说明:调用方脚本目录会缓存(同进程只计算一次),
inspect.stack()仅作兜底(失败时回退 cwd)。若运行环境特殊(PyInstaller 打包、C 扩展调用栈),建议显式调用set_config_search_dir()指定搜索起点。
环境变量解析
加载配置时自动递归解析 ${ENV_VAR} 环境变量引用,支持默认值语法 ${ENV_VAR:-default}。
ai:
openai:
api_key: ${ALIYUN_API_KEY} # 读取环境变量 ALIYUN_API_KEY
timeout: ${AI_TIMEOUT:-30} # 环境变量不存在时使用默认值 30
- 环境变量存在:替换为环境变量值
- 环境变量不存在但有默认值:使用默认值
- 环境变量不存在且无默认值:保留原字面量(与 Spring Boot 行为一致)
许可证
MIT License
Metadata
Release files for yaml-config-loader 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| yaml_config_loader-1.3.0.tar.gz | 27.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yaml_config_loader-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.2 kB
Release files / yaml_config_loader-1.3.0.tar.gz
| Download URL | yaml_config_loader-1.3.0.tar.gz |
|---|---|
| Size | 27.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1514d1660f1ffe2f98393ceff2078bf90580f749b3e56dfac240aa04b8b8dafd
|
|
BLAKE2b-256 checksum How to use checksums |
54cb09f0baf79ee3110eef8a06262f8eb1ccbb3cea285cc9465a0bf1076b1012
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.7
|
Release files / yaml_config_loader-1.3.0-py3-none-any.whl
| Download URL | yaml_config_loader-1.3.0-py3-none-any.whl |
|---|---|
| Size | 25.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ac0a47cdf956c91d5275137e22eeb314e6b3cd08bd21783d4a275e816a0c8746
|
|
BLAKE2b-256 checksum How to use checksums |
fdc34fc67b9a0761cd75f796cfc3334b0e0734a3fc46bdb7f9731a059da4b7cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.7
|