错误处理
当 Pydantic 在其验证的数据中发现错误时,将引发 ValidationError
。
注意
验证代码不应自行引发 ValidationError
,而应引发 ValueError
或 AssertionError
(或其子类),这些异常将被捕获并用于填充最终的 ValidationError
。
有关更多详细信息,请参阅验证器文档的专用部分。
该 ValidationError
将包含有关所有错误及其发生方式的信息。
您可以通过多种方式访问这些错误
方法 | 描述 |
---|---|
errors() |
返回在输入数据中找到的 ErrorDetails 错误列表。 |
error_count() |
返回错误数量。 |
json() |
返回错误列表的 JSON 表示形式。 |
str(e) |
返回错误的易于理解的表示形式。 |
ErrorDetails
对象是一个字典。它包含以下内容
属性 | 描述 |
---|---|
ctx |
一个可选对象,其中包含呈现错误消息所需的值。 |
input |
为验证提供的输入。 |
loc |
错误的位置,以列表形式表示。 |
msg |
错误的易于理解的解释。 |
type |
错误类型的计算机可读标识符。 |
url |
提供有关错误信息的文档 URL。 |
loc
列表中的第一项将是发生错误的字段,如果该字段是子模型,则将存在后续项以指示错误的嵌套位置。
作为一个演示
from pydantic import BaseModel, Field, ValidationError, field_validator
class Location(BaseModel):
lat: float = 0.1
lng: float = 10.1
class Model(BaseModel):
is_required: float
gt_int: int = Field(gt=42)
list_of_ints: list[int]
a_float: float
recursive_model: Location
@field_validator('a_float', mode='after')
@classmethod
def validate_float(cls, value: float) -> float:
if value > 2.0:
raise ValueError('Invalid float value')
return value
data = {
'list_of_ints': ['1', 2, 'bad'],
'a_float': 3.0,
'recursive_model': {'lat': 4.2, 'lng': 'New York'},
'gt_int': 21,
}
try:
Model(**data)
except ValidationError as e:
print(e)
"""
5 validation errors for Model
is_required
Field required [type=missing, input_value={'list_of_ints': ['1', 2,...ew York'}, 'gt_int': 21}, input_type=dict]
gt_int
Input should be greater than 42 [type=greater_than, input_value=21, input_type=int]
list_of_ints.2
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='bad', input_type=str]
a_float
Value error, Invalid float value [type=value_error, input_value=3.0, input_type=float]
recursive_model.lng
Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='New York', input_type=str]
"""
try:
Model(**data)
except ValidationError as e:
print(e.errors())
"""
[
{
'type': 'missing',
'loc': ('is_required',),
'msg': 'Field required',
'input': {
'list_of_ints': ['1', 2, 'bad'],
'a_float': 3.0,
'recursive_model': {'lat': 4.2, 'lng': 'New York'},
'gt_int': 21,
},
'url': 'https://errors.pydantic.dev/2/v/missing',
},
{
'type': 'greater_than',
'loc': ('gt_int',),
'msg': 'Input should be greater than 42',
'input': 21,
'ctx': {'gt': 42},
'url': 'https://errors.pydantic.dev/2/v/greater_than',
},
{
'type': 'int_parsing',
'loc': ('list_of_ints', 2),
'msg': 'Input should be a valid integer, unable to parse string as an integer',
'input': 'bad',
'url': 'https://errors.pydantic.dev/2/v/int_parsing',
},
{
'type': 'value_error',
'loc': ('a_float',),
'msg': 'Value error, Invalid float value',
'input': 3.0,
'ctx': {'error': ValueError('Invalid float value')},
'url': 'https://errors.pydantic.dev/2/v/value_error',
},
{
'type': 'float_parsing',
'loc': ('recursive_model', 'lng'),
'msg': 'Input should be a valid number, unable to parse string as a number',
'input': 'New York',
'url': 'https://errors.pydantic.dev/2/v/float_parsing',
},
]
"""
错误消息¶
Pydantic 尝试为验证和用法错误提供有用的默认错误消息,可以在此处找到
自定义错误消息¶
您可以通过创建自定义错误处理程序来自定义错误消息。
from pydantic_core import ErrorDetails
from pydantic import BaseModel, HttpUrl, ValidationError
CUSTOM_MESSAGES = {
'int_parsing': 'This is not an integer! 🤦',
'url_scheme': 'Hey, use the right URL scheme! I wanted {expected_schemes}.',
}
def convert_errors(
e: ValidationError, custom_messages: dict[str, str]
) -> list[ErrorDetails]:
new_errors: list[ErrorDetails] = []
for error in e.errors():
custom_message = custom_messages.get(error['type'])
if custom_message:
ctx = error.get('ctx')
error['msg'] = (
custom_message.format(**ctx) if ctx else custom_message
)
new_errors.append(error)
return new_errors
class Model(BaseModel):
a: int
b: HttpUrl
try:
Model(a='wrong', b='ftp://example.com')
except ValidationError as e:
errors = convert_errors(e, CUSTOM_MESSAGES)
print(errors)
"""
[
{
'type': 'int_parsing',
'loc': ('a',),
'msg': 'This is not an integer! 🤦',
'input': 'wrong',
'url': 'https://errors.pydantic.dev/2/v/int_parsing',
},
{
'type': 'url_scheme',
'loc': ('b',),
'msg': "Hey, use the right URL scheme! I wanted 'http' or 'https'.",
'input': 'ftp://example.com',
'ctx': {'expected_schemes': "'http' or 'https'"},
'url': 'https://errors.pydantic.dev/2/v/url_scheme',
},
]
"""
一个常见的用例是翻译错误消息。例如,在上面的示例中,我们可以通过将 CUSTOM_MESSAGES
字典替换为翻译字典来翻译错误消息。
另一个示例是自定义错误的 'loc'
值的表示方式。
from typing import Any, Union
from pydantic import BaseModel, ValidationError
def loc_to_dot_sep(loc: tuple[Union[str, int], ...]) -> str:
path = ''
for i, x in enumerate(loc):
if isinstance(x, str):
if i > 0:
path += '.'
path += x
elif isinstance(x, int):
path += f'[{x}]'
else:
raise TypeError('Unexpected type')
return path
def convert_errors(e: ValidationError) -> list[dict[str, Any]]:
new_errors: list[dict[str, Any]] = e.errors()
for error in new_errors:
error['loc'] = loc_to_dot_sep(error['loc'])
return new_errors
class TestNestedModel(BaseModel):
key: str
value: str
class TestModel(BaseModel):
items: list[TestNestedModel]
data = {'items': [{'key': 'foo', 'value': 'bar'}, {'key': 'baz'}]}
try:
TestModel.model_validate(data)
except ValidationError as e:
print(e.errors()) # (1)!
"""
[
{
'type': 'missing',
'loc': ('items', 1, 'value'),
'msg': 'Field required',
'input': {'key': 'baz'},
'url': 'https://errors.pydantic.dev/2/v/missing',
}
]
"""
pretty_errors = convert_errors(e)
print(pretty_errors) # (2)!
"""
[
{
'type': 'missing',
'loc': 'items[1].value',
'msg': 'Field required',
'input': {'key': 'baz'},
'url': 'https://errors.pydantic.dev/2/v/missing',
}
]
"""
- 默认情况下,
e.errors()
生成一个错误列表,其中loc
值采用元组形式。 - 使用我们的自定义
loc_to_dot_sep
函数,我们修改了loc
表示形式的形式。
from typing import Any
from pydantic import BaseModel, ValidationError
def loc_to_dot_sep(loc: tuple[str | int, ...]) -> str:
path = ''
for i, x in enumerate(loc):
if isinstance(x, str):
if i > 0:
path += '.'
path += x
elif isinstance(x, int):
path += f'[{x}]'
else:
raise TypeError('Unexpected type')
return path
def convert_errors(e: ValidationError) -> list[dict[str, Any]]:
new_errors: list[dict[str, Any]] = e.errors()
for error in new_errors:
error['loc'] = loc_to_dot_sep(error['loc'])
return new_errors
class TestNestedModel(BaseModel):
key: str
value: str
class TestModel(BaseModel):
items: list[TestNestedModel]
data = {'items': [{'key': 'foo', 'value': 'bar'}, {'key': 'baz'}]}
try:
TestModel.model_validate(data)
except ValidationError as e:
print(e.errors()) # (1)!
"""
[
{
'type': 'missing',
'loc': ('items', 1, 'value'),
'msg': 'Field required',
'input': {'key': 'baz'},
'url': 'https://errors.pydantic.dev/2/v/missing',
}
]
"""
pretty_errors = convert_errors(e)
print(pretty_errors) # (2)!
"""
[
{
'type': 'missing',
'loc': 'items[1].value',
'msg': 'Field required',
'input': {'key': 'baz'},
'url': 'https://errors.pydantic.dev/2/v/missing',
}
]
"""
- 默认情况下,
e.errors()
生成一个错误列表,其中loc
值采用元组形式。 - 使用我们的自定义
loc_to_dot_sep
函数,我们修改了loc
表示形式的形式。