Pydantic v2.8 现已发布!您现在可以通过 PyPi 或您喜欢的包管理器安装它
pip install --upgrade pydantic
此版本包含了超过 50 位贡献者的工作成果!在这篇文章中,我们将介绍此版本的亮点。您可以在 github 上查看完整的更新日志。
此版本尤其侧重于类型相关的错误修复和改进,以及一些可选的性能增强功能。
新功能
快速失败验证
Pydantic v2.8 引入了一项名为快速失败验证的新功能。此功能目前仅适用于有限数量的序列类型,包括 list
、tuple
、set
和 frozenset
。当您使用 FailFast
验证时,Pydantic 将在遇到错误时立即停止验证。
当您更关心数据的有效性而不是验证错误的彻底性时,此功能非常有用。对于许多人来说,这种错误特异性的权衡非常值得性能的提升。
您可以将 FailFast()
用作类型注解,或者在 Field
构造函数中指定 fail_fast
参数。
例如
from typing import List
from typing_extensions import Annotated
from pydantic import BaseModel, FailFast, Field, ValidationError
class Model(BaseModel):
x: Annotated[List[int], FailFast()]
y: List[int] = Field(..., fail_fast=True)
# This will raise a single error for the first invalid value in each list
# At which point, validation for said field will stop
try:
obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c'], y=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c'])
except ValidationError as e:
print(e)
"""
2 validation errors for Model
x.2
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
For further information visit https://errors.pydantic.dev/2.8/v/int_parsing
y.2
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
For further information visit https://errors.pydantic.dev/2.8/v/int_parsing
"""
我们计划在未来将此功能扩展到其他类型!
您可以在 API 参考 中阅读有关 FailFast
的更多信息
JSON Schema 中的模型/字段弃用
在 v2.7 中,我们引入了弃用模型和字段的功能。在 v2.8 中,我们扩展了此功能,在 JSON Schema 中包含了弃用信息。
from typing_extensions import deprecated
from pydantic import BaseModel, Field
@deprecated('DeprecatedModel is... sadly deprecated')
class DeprecatedModel(BaseModel):
deprecated_field: str = Field(..., deprecated=True)
json_schema = DeprecatedModel.schema()
assert json_schema['deprecated'] is True
assert json_schema['properties']['deprecated_field']['deprecated'] is True
程序化标题生成
这项新功能允许您使用可调用对象为您的模型和字段生成标题。当您想要根据模型或字段的属性动态生成标题时,这非常有用。
您可以在模型和字段之间共享可调用标题生成器,这有助于保持您的代码 DRY(不要重复自己)。
import json
from pydantic import BaseModel, ConfigDict, Field
class MyModel(BaseModel):
foo: str = Field(..., field_title_generator=lambda name, field_info: f'title-{name}-from-field')
bar: str
model_config = ConfigDict(
field_title_generator=lambda name, field_info: f'title-{name}-from-config',
model_title_generator=lambda cls: f'title-{cls.__name__}-from-config',
)
print(json.dumps(MyModel.model_json_schema(), indent=2))
"""
{
"properties": {
"foo": {
"title": "title-foo-from-field",
"type": "string"
},
"bar": {
"title": "title-bar-from-config",
"type": "string"
},
},
"required": [
"foo",
"bar",
],
"title": "title-MyModel-from-config",
"type": "object"
}
"""
想了解更多?请查看 JSON Schema 自定义文档。
TypeAdapter
的序列化上下文
在 v2.7 中,我们添加了对为 BaseModel
的序列化器传递上下文的支持。在 v2.8 中,我们将该支持扩展到了 TypeAdapter
的序列化方法。
这是一个简单的示例,我们在 context
中使用提供的 unit
来转换 distance
字段
from typing_extensions import Annotated
from pydantic import SerializationInfo, TypeAdapter, PlainSerializer
def serialize_distance(v: float, info: SerializationInfo) -> float:
"""We assume a distance is provided in meters, but we can convert it to other units if a context is provided."""
context = info.context
if context and 'unit' in context:
if context['unit'] == 'km':
v /= 1000 # convert to kilometers
elif context['unit'] == 'cm':
v *= 100 # convert to centimeters
return v
distance_adapter = TypeAdapter(Annotated[float, PlainSerializer(serialize_distance)])
print(distance_adapter.dump_python(500)) # no context, dumps in meters
# > 500.0
print(distance_adapter.dump_python(500, context={'unit': 'km'})) # with context, dumps in kilometers
# > 0.5
print(distance_adapter.dump_python(500, context={'unit': 'cm'})) # with context, dumps in centimeters
# > 50000
实验性功能
在 v2.8.0 中,我们引入了一种用于引入实验性功能和设置的新模式。我们在 版本策略 中添加了一个部分,解释了我们未来将如何处理实验性功能。
您可以在 实验性功能 部分找到我们新的实验性功能的文档。
实验性功能将是
- 位于
experimental
模块中,因此您可以通过from pydantic.experimental import ...
导入它们 - 以
experimental
为前缀,因此您可以像some_func(experimental_param=...)
或some_model.experimental_method(...)
这样使用它们
当您从 experimental
模块导入实验性功能时,您将看到 PydanticExperimentalWarning
。您可以通过以下方式过滤此警告
import warnings
from pydantic import PydanticExperimentalWarning
warnings.filterwarnings('ignore', category=PydanticExperimentalWarning)
在我们的版本策略中,我们还提到了实验性功能的 生命周期。实验性功能很可能会在未来的版本中经历不向后兼容的更改或被完全删除,因此在选择使用它们时请注意它们的易变性。
Pipeline API — 实验性
Pydantic v2.8.0 引入了一个实验性的 “pipeline” API,它允许以比现有 API 更类型安全的方式组合解析(验证)、约束和转换。
通常,pipeline API 用于定义应用于传入数据的验证步骤序列。以下示例说明了如何使用 pipeline API 首先将 int 验证为字符串,去除多余的空格,然后将其解析为 int,最后确保它大于或等于 0。
import warnings
from typing_extensions import Annotated
from pydantic import BaseModel, PydanticExperimentalWarning, ValidationError
warnings.filterwarnings('ignore', category=PydanticExperimentalWarning)
from pydantic.experimental.pipeline import validate_as
class Model(BaseModel):
data: Annotated[str, validate_as(str).str_strip().validate_as(...).ge(0)]
print(repr(Model(data=' 123 ')))
#> Model(data=123)
try:
Model(data=' -123 ')
except ValidationError as e:
print(e)
"""
1 validation error for Model
data
Input should be greater than or equal to 0 [type=greater_than_equal, input_value=' -123 ', input_type=str]
For further information visit https://errors.pydantic.dev/2.8/v/greater_than_equal
"""
请注意,validate_as(...)
等同于 validate_as(<type_in_annotation>)
。因此,对于上面的示例,validate_as(...)
等同于 validate_as(int)
。
如果您想了解更多信息,我们在 pipeline 文档 中添加了一些其他示例。
defer_build
支持 `TypeAdapter — 实验性
Pydantic BaseModel
目前在其配置中支持 defer_build
设置,允许延迟 schema 构建(直到第一次验证调用)。这可以帮助减少可能具有大量复杂模型(这些模型承担着沉重的 schema 构建成本)的应用程序的启动时间。
在 v2.8 中,我们为 TypeAdapter
的配置添加了实验性 defer_build
支持。
以下是如何使用此新实验性功能的示例
from pydantic import ConfigDict, TypeAdapter
from typing import TypeAlias
# in practice, this would be some complex type for which schema building
# takes a while, hence the value of deferring the build
SuperDuperComplexType: TypeAlias = int
ta = TypeAdapter(
SuperDuperComplexType,
config=ConfigDict(
defer_build=True,
experimental_defer_build_mode=('model', 'type_adapter'),
),
)
assert ta._core_schema is None
print(ta.validate_python(0))
# after a call is made that requires the core schema, it's built and cached
assert ta.core_schema == {'type': 'int'}
性能改进
codeflash
持续优化
我们一直在与 codeflash
团队合作,对 Pydantic 的源代码进行 LLM 驱动的优化。到目前为止,我们在内部逻辑中进行了一些小的优化,我们期待在未来合作进行更重大的改进。
我们还希望将 codeflash
集成到我们的 CI/CD pipeline 中,以确保我们始终如一地检查优化机会。
显著改进 / 修复
支持 Python 3.13
Pydantic V2 现在支持 Python 3.13!
我们的一些面向测试的依赖项尚不兼容 Python 3.13,但我们计划尽快升级它们。这意味着并非所有测试都可以在 Python 3.13 上运行(只有少数几个尚不兼容),但这应该只会影响贡献者。
对于用户而言,Pydantic 应该可以在 Python 3.13 上正常工作。如果您遇到任何问题,请 告诉我们!
更智能的 smart
Union
验证
在针对类型联合验证数据时,Pydantic 提供了 smart
模式和 left_to_right
模式。
我们对 smart
模式进行了一些改进,以改善针对包含许多相同字段的类型联合进行验证时的行为。以下示例展示了旧行为与新行为的示例
from pydantic import BaseModel, TypeAdapter
class ModelA(BaseModel):
a: int
class ModelB(ModelA):
b: str
ta = TypeAdapter(ModelA | ModelB)
print(repr(ta.validate_python({'a': 1, 'b': 'foo'})))
#> old behavior: ModelA(a=1)
#> new behavior: ModelB(a=1, b='foo')
在许多其他更复杂的情况下,新行为更加直观和正确。总体思路是,除了匹配的精确度(在 strict、lax 等方面)之外,我们现在还将有效字段的数量纳入评分算法。
我们记录了匹配评分 算法,以提供透明度和可预测性。但是,我们保留在未来修改智能联合算法以进一步改进其行为的权利。一般来说,我们预计此类更改只会影响边缘情况,并且我们只会在它们几乎普遍改善此类边缘情况的处理时才进行此类更改。
更好地理解此算法还可以帮助您选择哪种联合模式适合您的用例。
如果您正在寻找比智能模式提供更高性能的联合验证,我们建议您使用 标记联合。
在约束字符串验证中尊重 Regex 标志
Python 的 re
模块支持可以传递给 regex 模式以更改其行为的标志。例如,re.IGNORECASE
标志使模式不区分大小写。在以前版本的 Pydantic 中,即使在使用 python-re
regex 引擎时,这些标志也会被忽略。
现在,我们通过以下方式改进了 Pydantic 的约束字符串验证:
- 不重新编译 Python regex 模式(这更高效)
- 尊重传递给已编译模式的标志
!!! note 如果您使用已编译的 regex 模式,则无论此设置如何,都将使用 python-re 引擎。这是为了使诸如 re.IGNORECASE
之类的标志得到尊重。
这是一个说明这些标志作用的示例
import re
from typing_extensions import Annotated
from pydantic import BaseModel, ConfigDict, StringConstraints
class Model(BaseModel):
a: Annotated[str, StringConstraints(pattern=re.compile(r'[A-Z]+', re.IGNORECASE))]
model_config = ConfigDict(regex_engine='python-re')
# allows lowercase letters, even though the pattern is uppercase only due to the re.IGNORECASE flag
assert Model(a='abc').a == 'abc'
您可以在我们的 模型配置文档 中了解有关 regex_engine
设置的更多信息
结论
凭借这些新功能和性能改进,Pydantic v2.8.0 是迄今为止最好且功能最丰富的 Pydantic 版本。如果您有任何问题或反馈,请打开一个 Github 讨论。如果您遇到任何错误,请打开一个 Github issue。
感谢我们所有的贡献者使此版本成为可能!我们特别要感谢以下个人对本次发布的重大贡献
Pydantic Logfire
如果您喜欢 Pydantic,您可能会非常喜欢 Pydantic Logfire,这是 Pydantic 团队构建的新型可观测性工具。您现在可以 免费试用 Logfire,在我们公开 Beta 测试期间。如果您能加入 Pydantic Logfire Slack 并告诉我们您的想法,我们将非常高兴!