Pydantic -解析来自YAML配置文件的对象列表



我想从一个YAML文件中读取一个对象列表:

- entry1:
attribute: "Test1"
amount: 1
price: 123.45
- entry2:
attribute: "Test1"
amount: 10
price: 56.78
对于这个数据结构,我创建了三个嵌套模型,如下所示:
# Models
class EntryValues(BaseModel):
attribute: str
amount: int
price: float
class Entry(BaseModel):
entry1: EntryValues
entry2: EntryValues
class Config(BaseModel):
__root__: list[Entry]

读取YAML配置文件的代码如下所示:

# get YAML config path
def get_cfg_path() -> Path:
return CWD
# read YAML file
def read_cfg(file_name: str, file_path: Path = None) -> YAML:
if not file_path:
file_path = get_cfg_path()
if file_path:
try:
file = open(file_path / file_name, "r")
except Exception as e:
print(f"open file {file_name} failed", e)
sys.exit(1)
else:
return load(file.read())
else:
raise Exception(f"Config file {file_name} not found!")

现在我想打开YAML的值我的模型。为此,我试图用**操作符解包值。我想我在这里少了一个循环,但我不能让它工作。

# Unpack and create config file
def create_cfg(file_name: str = None) -> Config:
config_file = read_cfg(file_name=file_name)
_config = Config(**config_file.data)
return _config

我很感激你的帮助。

<标题>

更新我摆弄模型结构有点不使用YAML文件。我不明白为什么以下抛出ValidationError:

考虑以下条目列表(这与我从YAML文件接收到的数据结构相同):

entries = [
{'entry1': {'attribute': 'Test1', 'amount': 1, 'price': 123.45}}, 
{'entry2': {'attribute': 'Test2', 'amount': 10, 'price': 56.78}}
]

如果我运行下面的简单循环,Pydantic抛出一个ValidationError:

for entry in entries:
Entry(**entry)

错误:

ValidationError: 1 validation error for Entry
entry2
field required (type=value_error.missing)

但是,如果列表只包含一个条目字典,则它可以工作:

class Entry(BaseModel):
entry1: EntryValues
#entry2: EntryValues
entries = [
{'entry1': {'attribute': 'Test1', 'amount': 1, 'price': 123.45}}
]
for entry in entries:
Entry(**entry)
有人能解释一下这个或者我在这里做错了什么吗?

在您的更新中,第二种情况有效而不是第一种情况的原因是解包操作符(**)采用包含所有必要键的单个字典对象。在第一种情况下,你有一个包含所有必要信息的字典;在第二种情况下,它分布在两个字典中,它们不能一起打开。一种可能的解决方法是将它们合并到一个字典中。但据我所知,更好的解决方案是通过删除每行中的前两个字符来更改YAML以首先提供此功能:

entry1:
attribute: "Test1"
amount: 1
price: 123.45
entry2:
attribute: "Test1"
amount: 10
price: 56.78

然后:

_config = Config(__root__=[Entry(**entries)])

原始答:

你的代码有很多问题,但我认为你要做的是将YAML解析成字典,并从每个项目实例化一个EntryValues。它看起来像这样:

from pydantic import BaseModel
from pathlib import Path
from typing import List
import yaml

def create_cfg(file_name: str = None) -> Config:
config_file = read_cfg(file_name=file_name)
entries = yaml.safe_load(config_file)
_config = [
EntryValues(**di[name]) for di, name in zip(entries, ["entry1", "entry2"])
]
return _config

最新更新