跳转到内容

验证文件数据

pydantic 是一个用于验证来自各种来源的数据的强大工具。在本节中,我们将探讨如何验证来自不同类型文件的数据。

注意

如果您正在使用以下任何文件格式来解析配置/设置,您可能需要考虑使用 pydantic-settings 库,它为解析此类数据提供了内置支持。

JSON 数据

.json 文件是一种以人类可读格式存储键/值数据的常用方式。这是一个 .json 文件的示例

{
    "name": "John Doe",
    "age": 30,
    "email": "[email protected]"
}

为了验证这些数据,我们可以使用一个 pydantic 模型

import pathlib

from pydantic import BaseModel, EmailStr, PositiveInt


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


json_string = pathlib.Path('person.json').read_text()
person = Person.model_validate_json(json_string)
print(person)
#> name='John Doe' age=30 email='[email protected]'

如果文件中的数据无效,pydantic 将会引发一个 ValidationError。假设我们有以下 .json 文件

{
    "age": -30,
    "email": "not-an-email-address"
}

这份数据存在三处问题

  1. 它缺少 name 字段。
  2. age 字段是负数。
  3. email 字段不是一个有效的电子邮件地址。

当我们尝试验证这些数据时,pydantic 会引发一个包含上述所有问题的 ValidationError

import pathlib

from pydantic import BaseModel, EmailStr, PositiveInt, ValidationError


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


json_string = pathlib.Path('person.json').read_text()
try:
    person = Person.model_validate_json(json_string)
except ValidationError as err:
    print(err)
    """
    3 validation errors for Person
    name
    Field required [type=missing, input_value={'age': -30, 'email': 'not-an-email-address'}, input_type=dict]
        For further information visit https://errors.pydantic.dev/2.10/v/missing
    age
    Input should be greater than 0 [type=greater_than, input_value=-30, input_type=int]
        For further information visit https://errors.pydantic.dev/2.10/v/greater_than
    email
    value is not a valid email address: An email address must have an @-sign. [type=value_error, input_value='not-an-email-address', input_type=str]
    """

通常情况下,一个 .json 文件中可能会包含大量的某种类型的数据。例如,您可能有一个人员列表

[
    {
        "name": "John Doe",
        "age": 30,
        "email": "[email protected]"
    },
    {
        "name": "Jane Doe",
        "age": 25,
        "email": "[email protected]"
    }
]

在这种情况下,您可以使用 list[Person] 模型来验证数据

import pathlib

from pydantic import BaseModel, EmailStr, PositiveInt, TypeAdapter


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


person_list_adapter = TypeAdapter(list[Person])  # (1)!

json_string = pathlib.Path('people.json').read_text()
people = person_list_adapter.validate_json(json_string)
print(people)
#> [Person(name='John Doe', age=30, email='[email protected]'), Person(name='Jane Doe', age=25, email='[email protected]')]
  1. 我们使用 TypeAdapter 来验证一个 Person 对象的列表。TypeAdapter 是 Pydantic 中用于针对单一类型验证数据的构造。

JSON Lines 文件

与验证 .json 文件中的对象列表类似,您也可以验证 .jsonl 文件中的对象列表。.jsonl 文件是由换行符分隔的 JSON 对象序列。

考虑以下 .jsonl 文件

{"name": "John Doe", "age": 30, "email": "[email protected]"}
{"name": "Jane Doe", "age": 25, "email": "[email protected]"}

我们可以使用与处理 .json 文件类似的方法来验证这些数据

import pathlib

from pydantic import BaseModel, EmailStr, PositiveInt


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


json_lines = pathlib.Path('people.jsonl').read_text().splitlines()
people = [Person.model_validate_json(line) for line in json_lines]
print(people)
#> [Person(name='John Doe', age=30, email='[email protected]'), Person(name='Jane Doe', age=25, email='[email protected]')]

CSV 文件

CSV 是存储表格数据最常见的文件格式之一。要验证来自 CSV 文件的数据,您可以使用 Python 标准库中的 csv 模块加载数据,并使用 Pydantic 模型进行验证。

考虑以下 CSV 文件

name,age,email
John Doe,30,[email protected]
Jane Doe,25,[email protected]

以下是我们如何验证该数据

import csv

from pydantic import BaseModel, EmailStr, PositiveInt


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


with open('people.csv') as f:
    reader = csv.DictReader(f)
    people = [Person.model_validate(row) for row in reader]

print(people)
#> [Person(name='John Doe', age=30, email='[email protected]'), Person(name='Jane Doe', age=25, email='[email protected]')]

TOML 文件

TOML 文件因其简洁性和可读性而常用于配置。

考虑以下 TOML 文件

name = "John Doe"
age = 30
email = "[email protected]"

以下是我们如何验证该数据

import tomllib

from pydantic import BaseModel, EmailStr, PositiveInt


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


with open('person.toml', 'rb') as f:
    data = tomllib.load(f)

person = Person.model_validate(data)
print(person)
#> name='John Doe' age=30 email='[email protected]'

YAML 文件

YAML(YAML Ain't Markup Language)是一种人类可读的数据序列化格式,常用于配置文件。

考虑以下 YAML 文件

name: John Doe
age: 30
email: [email protected]

以下是我们如何验证该数据

import yaml

from pydantic import BaseModel, EmailStr, PositiveInt


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


with open('person.yaml') as f:
    data = yaml.safe_load(f)

person = Person.model_validate(data)
print(person)
#> name='John Doe' age=30 email='[email protected]'

XML 文件

XML(eXtensible Markup Language)是一种标记语言,它定义了一套规则,用于以一种既人类可读又机器可读的格式编码文档。

考虑以下 XML 文件

<?xml version="1.0"?>
<person>
    <name>John Doe</name>
    <age>30</age>
    <email>[email protected]</email>
</person>

以下是我们如何验证该数据

import xml.etree.ElementTree as ET

from pydantic import BaseModel, EmailStr, PositiveInt


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


tree = ET.parse('person.xml').getroot()
data = {child.tag: child.text for child in tree}
person = Person.model_validate(data)
print(person)
#> name='John Doe' age=30 email='[email protected]'

INI 文件

INI 文件是一种简单的配置文件格式,使用节(sections)和键值对。它们在 Windows 应用程序和旧版软件中很常用。

考虑以下 INI 文件

[PERSON]
name = John Doe
age = 30
email = [email protected]

以下是我们如何验证该数据

import configparser

from pydantic import BaseModel, EmailStr, PositiveInt


class Person(BaseModel):
    name: str
    age: PositiveInt
    email: EmailStr


config = configparser.ConfigParser()
config.read('person.ini')
person = Person.model_validate(config['PERSON'])
print(person)
#> name='John Doe' age=30 email='[email protected]'