簡體   English   中英

Pydantic - 從 YAML 配置文件中解析對象列表

[英]Pydantic - parse a list of objects from YAML configuration file

我想從 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM