Zum Inhalt

Fehlerbehandlung

Pydantic löst einen ValidationError aus, wenn es einen Fehler in den zu validierenden Daten findet.

!!! Hinweis Der Validierungscode sollte nicht ValidationError selbst auslösen, sondern einen ValueError oder AssertionError (oder eine Unterklasse davon), der abgefangen und zum Auffüllen ValidationError verwendet wird.

Unabhängig von der Anzahl der gefundenen Fehler wird eine Ausnahme ausgelöst. ValidationError enthält Informationen zu allen Fehlern und deren Entstehung.

Sie können auf verschiedene Arten auf diese Fehler zugreifen:


Verfahren

Beschreibung
e.errors()
Gibt eine Liste der in den Eingabedaten gefundenen Fehler zurück.
e.error_count()
Gibt die Anzahl der in errors gefundenen Fehler zurück.
e.json()
Gibt eine JSON-Darstellung von errors zurück.
str(e)
Gibt eine für Menschen lesbare Darstellung der Fehler zurück.

Jedes Fehlerobjekt enthält:


Eigentum

Beschreibung
ctx
Ein optionales Objekt, das Werte enthält, die zum Rendern der Fehlermeldung erforderlich sind.
input
Die zur Validierung bereitgestellte Eingabe.
loc
Der Ort des Fehlers als Liste.
msg
Eine für Menschen lesbare Erklärung des Fehlers.
type
Eine computerlesbare Kennung des Fehlertyps.
url
Die URL zu weiteren Informationen zum Fehler.

Das erste Element in der loc -Liste ist das Feld, in dem der Fehler aufgetreten ist. Wenn es sich bei dem Feld um ein Untermodell handelt, sind nachfolgende Elemente vorhanden, um die verschachtelte Position des Fehlers anzuzeigen.

Als Demonstration:

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',
        },
    ]
    """

Benutzerdefinierte Fehler

In Ihren benutzerdefinierten Datentypen oder Validatoren sollten Sie ValueError oder AssertionError verwenden, um Fehler auszulösen.

Weitere Informationen zur Verwendung des @validator Dekorators finden Sie unter Validatoren .

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',
        }
    ]
    """

Sie können auch PydanticCustomError verwenden, um die Fehlerstruktur vollständig zu steuern:

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]
    """

Fehlermeldungen

Pydantic versucht, nützliche Standardfehlermeldungen für Validierungs- und Verwendungsfehler bereitzustellen.

Wir haben in den folgenden Abschnitten Dokumentation für Standardfehlercodes bereitgestellt:

Passen Sie Fehlermeldungen an

Sie können Fehlermeldungen anpassen, indem Sie einen benutzerdefinierten Fehlerhandler erstellen.

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',
        },
    ]
    """

Ein häufiger Anwendungsfall wäre die Übersetzung von Fehlermeldungen. Im obigen Beispiel könnten wir beispielsweise die Fehlermeldungen übersetzen und dabei das Wörterbuch CUSTOM_MESSAGES durch ein Wörterbuch mit Übersetzungen ersetzen.

Ein weiteres Beispiel ist die Anpassung der Art und Weise, wie der 'loc' -Wert eines Fehlers dargestellt wird.

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',
        }
    ]
    """
  1. Standardmäßig erzeugt e.errors() eine Liste von Fehlern mit loc -Werten, die die Form von Tupeln annehmen.
  2. Mit unserer benutzerdefinierten Funktion loc_to_dot_sep haben wir die Form der loc -Darstellung geändert.

本文总阅读量