Gestion des erreurs
Pydantic générera une ValidationError
chaque fois qu'il trouvera une erreur dans les données qu'il valide.
!!! note Le code de validation ne doit pas déclencher ValidationError
lui-même, mais plutôt générer une ValueError
ou AssertionError
(ou une sous-classe de celle-ci) qui sera interceptée et utilisée pour remplir ValidationError
.
Une exception sera générée quel que soit le nombre d'erreurs trouvées, ValidationError
contiendra des informations sur toutes les erreurs et comment elles se sont produites.
Vous pouvez accéder à ces erreurs de plusieurs manières:
Méthode | Description |
---|---|
e.errors() | Renvoie une liste des erreurs trouvées dans les données d'entrée. |
e.error_count() | Renvoie le nombre d'erreurs trouvées dans errors . |
e.json() | Renvoie une représentation JSON des errors . |
str(e) | Renvoie une représentation lisible par l'homme des erreurs. |
Chaque objet d'erreur contient:
Propriété | Description |
---|---|
ctx | Un objet facultatif qui contient les valeurs requises pour afficher le message d'erreur. |
input | Entrée fournie pour validation. |
loc | L'emplacement de l'erreur sous forme de liste. |
msg | Une explication lisible par l'homme de l'erreur. |
type | Un identifiant lisible par ordinateur du type d’erreur. |
url | L'URL vers des informations supplémentaires sur l'erreur. |
Le premier élément de la liste loc
sera le champ dans lequel l'erreur s'est produite, et si le champ est un sous-modèle , les éléments suivants seront présents pour indiquer l'emplacement imbriqué de l'erreur.
En guise de démonstration :
from typing import List
from pydantic import BaseModel, ValidationError, conint
class Location(BaseModel):
lat: float = 0.1
lng: float = 10.1
class Model(BaseModel):
is_required: float
gt_int: conint(gt=42)
list_of_ints: List[int] = None
a_float: float = None
recursive_model: Location = None
data = dict(
list_of_ints=['1', 2, 'bad'],
a_float='not a float',
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
Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='not a float', input_type=str]
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': 'not a float',
'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': 'float_parsing',
'loc': ('a_float',),
'msg': 'Input should be a valid number, unable to parse string as a number',
'input': 'not a float',
'url': 'https://errors.pydantic.dev/2/v/float_parsing',
},
{
'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',
},
]
"""
Erreurs personnalisées¶
Dans vos types de données personnalisés ou validateurs, vous devez utiliser ValueError
ou AssertionError
pour générer des erreurs.
Voir validateurs pour plus de détails sur l'utilisation du décorateur @validator
.
from pydantic import BaseModel, ValidationError, field_validator
class Model(BaseModel):
foo: str
@field_validator('foo')
def value_must_equal_bar(cls, v):
if v != 'bar':
raise ValueError('value must be "bar"')
return v
try:
Model(foo='ber')
except ValidationError as e:
print(e)
"""
1 validation error for Model
foo
Value error, value must be "bar" [type=value_error, input_value='ber', input_type=str]
"""
print(e.errors())
"""
[
{
'type': 'value_error',
'loc': ('foo',),
'msg': 'Value error, value must be "bar"',
'input': 'ber',
'ctx': {'error': ValueError('value must be "bar"')},
'url': 'https://errors.pydantic.dev/2/v/value_error',
}
]
"""
Vous pouvez également utiliser PydanticCustomError
pour contrôler entièrement la structure de l'erreur:
from pydantic_core import PydanticCustomError
from pydantic import BaseModel, ValidationError, field_validator
class Model(BaseModel):
foo: str
@field_validator('foo')
def value_must_equal_bar(cls, v):
if v != 'bar':
raise PydanticCustomError(
'not_a_bar',
'value is not "bar", got "{wrong_value}"',
dict(wrong_value=v),
)
return v
try:
Model(foo='ber')
except ValidationError as e:
print(e)
"""
1 validation error for Model
foo
value is not "bar", got "ber" [type=not_a_bar, input_value='ber', input_type=str]
"""
Messages d'erreur¶
Pydantic tente de fournir des messages d'erreur par défaut utiles pour les erreurs de validation et d'utilisation.
Nous avons fourni une documentation sur les codes d'erreur par défaut dans les sections suivantes:
Personnaliser les messages d'erreur¶
Vous pouvez personnaliser les messages d'erreur en créant un gestionnaire d'erreurs personnalisé.
from typing import Dict, List
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',
},
]
"""
Un cas d'utilisation courant serait de traduire des messages d'erreur. Par exemple, dans l'exemple ci-dessus, nous pourrions traduire les messages d'erreur en remplaçant le dictionnaire CUSTOM_MESSAGES
par un dictionnaire de traductions.
Un autre exemple consiste à personnaliser la façon dont la valeur 'loc'
d'une erreur est représentée.
from typing import Any, Dict, List, Tuple, 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',
}
]
"""
- Par défaut,
e.errors()
produit une liste d'erreurs avec des valeursloc
qui prennent la forme de tuples. - Avec notre fonction personnalisée
loc_to_dot_sep
, nous avons modifié la forme de la représentationloc
.
本文总阅读量次