使用PyYAML解析YAML配置中的环境变量时遭遇'TypeError: 'type' object is not iterable'错误
PyYAML解析YAML配置中的环境变量时遭遇'TypeError: 'type' object is not iterable'错误
嘿,我帮你定位到问题根源啦!你遇到的这个TypeError完全是因为调用yaml.add_implicit_resolver时的参数位置传错了,咱们一步步来解决:
错误原因拆解
你当前的代码里写了:
yaml.add_implicit_resolver("!pathex", env_pattern, yaml.SafeLoader)
但PyYAML的add_implicit_resolver方法签名是:
def add_implicit_resolver(tag, regexp, first=None, Loader=None)
这里的第三个参数first是用来指定触发解析的起始字符集合(比如/$这类字符),而你把yaml.SafeLoader(一个类型对象)传到了这个位置。PyYAML尝试遍历这个类型对象来检查起始字符,自然就抛出了“类型对象不可迭代”的错误。
修正方案(完整可运行代码)
我帮你调整了代码,不仅修复了参数位置问题,还优化了几处细节:
# base_model.py import yaml import os import re from pydantic import BaseModel from typing import Union from pathlib import Path # 优化正则:只匹配${VAR}格式的内容,避免多余的.*?导致的匹配问题 env_pattern = re.compile(r"\${(.*?)}") def env_constructor(loader, node): value = loader.construct_scalar(node) # 遍历所有匹配的环境变量 for group in env_pattern.findall(value): # 给环境变量加默认值,避免None被直接插入 env_value = os.environ.get(group, "") value = value.replace(f"${{{group}}}", env_value) return value # 修正参数位置:把Loader放到第四个参数的位置(用关键字参数更清晰) yaml.add_implicit_resolver("!pathex", env_pattern, Loader=yaml.SafeLoader) yaml.add_constructor("!pathex", env_constructor, yaml.SafeLoader) class YamlModel(BaseModel): @classmethod def from_yaml(cls, yaml_file_path: Union[str, Path]) -> "YamlModel": yaml_file = Path(yaml_file_path) with open(yaml_file, "r") as f: # 这里用safe_load是对的,因为我们注册的是SafeLoader的构造器 file_content = yaml.safe_load(f) return cls.parse_obj(file_content)
额外注意事项
测试前务必设置环境变量
你的测试用例里断言config.car.name == "BMW",所以测试函数里要先设置对应的环境变量,否则会因为环境变量不存在替换成空字符串导致断言失败:# 修正后的测试代码 import pytest import os from src.example_model import Config def test_config_positive(): # 先设置环境变量 os.environ["CAR_NAME"] = "BMW" config = Config.from_yaml("tests/config_positive.yaml") assert config.owner.name == "John Doe" assert config.owner.age == 30 assert config.car.name == "BMW"环境变量不存在的处理
我在代码里给os.environ.get加了空字符串默认值,如果你希望环境变量不存在时抛出错误(更严谨),可以改成:env_value = os.environ.get(group) if env_value is None: raise ValueError(f"环境变量 {group} 未设置!")正则表达式优化
原来的r".*?\${(.*?)}.*?"会匹配整个包含变量的字符串,改成r"\${(.*?)}"后,更精准地匹配环境变量占位符,避免不必要的匹配范围。
这样调整后,你的代码应该就能正常解析YAML中的环境变量,测试也能顺利通过啦!
备注:内容来源于stack exchange,提问作者mascai
相关产品推荐
相关产品推荐

