Strikter Modus
??? API „API-Dokumentation“ pydantic.types.Strict
Standardmäßig versucht Pydantic, wenn möglich, Werte in den gewünschten Typ zu zwingen. Sie können beispielsweise die Zeichenfolge "123"
als Eingabe an ein int
-Feld übergeben und sie wird in 123
konvertiert. Dieses Zwangsverhalten ist in vielen Szenarien nützlich – denken Sie an: UUIDs, URL-Parameter, HTTP-Header, Umgebungsvariablen, Benutzereingaben usw.
Es gibt jedoch auch Situationen, in denen dies nicht wünschenswert ist und Sie möchten, dass Pydantic Fehler macht, anstatt Daten zu erzwingen.
Um diesen Anwendungsfall besser zu unterstützen, bietet Pydantic einen „strikten Modus“, der pro Modell, pro Feld oder sogar pro Validierungsaufruf aktiviert werden kann. Wenn der strikte Modus aktiviert ist, ist Pydantic beim Erzwingen von Daten viel weniger nachsichtig und gibt stattdessen einen Fehler aus, wenn die Daten nicht vom richtigen Typ sind.
Hier ist ein kurzes Beispiel, das den Unterschied zwischen dem Validierungsverhalten im strengen und dem Standard-/„laxen“ Modus zeigt:
from pydantic import BaseModel, ValidationError
class MyModel(BaseModel):
x: int
print(MyModel.model_validate({'x': '123'})) # lax mode
#> x=123
try:
MyModel.model_validate({'x': '123'}, strict=True) # strict mode
except ValidationError as exc:
print(exc)
"""
1 validation error for MyModel
x
Input should be a valid integer [type=int_type, input_value='123', input_type=str]
"""
Es gibt verschiedene Möglichkeiten, bei der Verwendung von Pydantic eine Validierung im strengen Modus zu erhalten, die im Folgenden ausführlicher erläutert wird:
- Übergeben von
strict=True
an die Validierungsmethoden wieBaseModel.model_validate
,TypeAdapter.validate_python
und ähnliches für JSON - Verwenden von
Field(strict=True)
mit Feldern einesBaseModel
,dataclass
oderTypedDict
- Verwendung von
pydantic.types.Strict
als Typanmerkung für ein Feld- Pydantic stellt einige Typaliase bereit, die bereits mit
Strict
annotiert sind, wie zum Beispielpydantic.types.StrictInt
- Pydantic stellt einige Typaliase bereit, die bereits mit
- Verwenden von
ConfigDict(strict=True)
Geben Sie Zwänge im strikten Modus ein¶
Bei den meisten Typen werden bei der Validierung von Daten aus Python im strikten Modus nur die Instanzen der exakten Typen akzeptiert. Wenn Sie beispielsweise ein int
-Feld validieren, werden nur Instanzen von int
akzeptiert. Die Übergabe von float
oder str
Instanzen führt zur Auslösung eines ValidationError
.
Beachten Sie, dass wir bei der Validierung von Daten aus JSON im strikten Modus lockerer vorgehen. Wenn Sie beispielsweise ein UUID
-Feld validieren, werden Instanzen von str
bei der Validierung von JSON akzeptiert, nicht jedoch von Python:
import json
from uuid import UUID
from pydantic import BaseModel, ValidationError
class MyModel(BaseModel):
guid: UUID
data = {'guid': '12345678-1234-1234-1234-123456789012'}
print(MyModel.model_validate(data)) # OK: lax
#> guid=UUID('12345678-1234-1234-1234-123456789012')
print(
MyModel.model_validate_json(json.dumps(data), strict=True)
) # OK: strict, but from json
#> guid=UUID('12345678-1234-1234-1234-123456789012')
try:
MyModel.model_validate(data, strict=True) # Not OK: strict, from python
except ValidationError as exc:
print(exc.errors(include_url=False))
"""
[
{
'type': 'is_instance_of',
'loc': ('guid',),
'msg': 'Input should be an instance of UUID',
'input': '12345678-1234-1234-1234-123456789012',
'ctx': {'class': 'UUID'},
}
]
"""
Weitere Einzelheiten dazu, welche Typen im strikten Modus als Eingaben zulässig sind, finden Sie in der Konvertierungstabelle .
Strikter Modus bei Methodenaufrufen¶
Alle bisher enthaltenen Beispiele erhalten eine Validierung im strengen Modus durch die Verwendung von strict=True
als Schlüsselwortargument für die Validierungsmethoden. Während wir dies für BaseModel.model_validate
gezeigt haben, funktioniert dies durch die Verwendung von TypeAdapter
auch mit beliebigen Typen:
from pydantic import TypeAdapter, ValidationError
print(TypeAdapter(bool).validate_python('yes')) # OK: lax
#> True
try:
TypeAdapter(bool).validate_python('yes', strict=True) # Not OK: strict
except ValidationError as exc:
print(exc)
"""
1 validation error for bool
Input should be a valid boolean [type=bool_type, input_value='yes', input_type=str]
"""
Beachten Sie, dass dies auch funktioniert, wenn Sie „komplexere“ Typen in TypeAdapter
verwenden:
from dataclasses import dataclass
from pydantic import TypeAdapter, ValidationError
@dataclass
class MyDataclass:
x: int
try:
TypeAdapter(MyDataclass).validate_python({'x': '123'}, strict=True)
except ValidationError as exc:
print(exc)
"""
1 validation error for MyDataclass
Input should be an instance of MyDataclass [type=dataclass_exact_type, input_value={'x': '123'}, input_type=dict]
"""
Dies funktioniert auch mit den Methoden TypeAdapter.validate_json
und BaseModel.model_validate_json
:
import json
from typing import List
from uuid import UUID
from pydantic import BaseModel, TypeAdapter, ValidationError
try:
TypeAdapter(List[int]).validate_json('["1", 2, "3"]', strict=True)
except ValidationError as exc:
print(exc)
"""
2 validation errors for list[int]
0
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
2
Input should be a valid integer [type=int_type, input_value='3', input_type=str]
"""
class Model(BaseModel):
x: int
y: UUID
data = {'x': '1', 'y': '12345678-1234-1234-1234-123456789012'}
try:
Model.model_validate(data, strict=True)
except ValidationError as exc:
# Neither x nor y are valid in strict mode from python:
print(exc)
"""
2 validation errors for Model
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
y
Input should be an instance of UUID [type=is_instance_of, input_value='12345678-1234-1234-1234-123456789012', input_type=str]
"""
json_data = json.dumps(data)
try:
Model.model_validate_json(json_data, strict=True)
except ValidationError as exc:
# From JSON, x is still not valid in strict mode, but y is:
print(exc)
"""
1 validation error for Model
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
Strikter Modus mit Field
¶
Für einzelne Felder in einem Modell können Sie strict=True
für das Feld festlegen . Dadurch wird für dieses Feld eine Validierung im strengen Modus verwendet, auch wenn die Validierungsmethoden ohne strict=True
aufgerufen werden.
Es sind nur die Felder betroffen, für die strict=True
gesetzt ist:
from pydantic import BaseModel, Field, ValidationError
class User(BaseModel):
name: str
age: int
n_pets: int
user = User(name='John', age='42', n_pets='1')
print(user)
#> name='John' age=42 n_pets=1
class AnotherUser(BaseModel):
name: str
age: int = Field(strict=True)
n_pets: int
try:
anotheruser = AnotherUser(name='John', age='42', n_pets='1')
except ValidationError as e:
print(e)
"""
1 validation error for AnotherUser
age
Input should be a valid integer [type=int_type, input_value='42', input_type=str]
"""
Beachten Sie, dass sich die Striktisierung von Feldern auch auf die Validierung auswirkt, die beim Instanziieren der Modellklasse durchgeführt wird:
from pydantic import BaseModel, Field, ValidationError
class Model(BaseModel):
x: int = Field(strict=True)
y: int = Field(strict=False)
try:
Model(x='1', y='2')
except ValidationError as exc:
print(exc)
"""
1 validation error for Model
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
Field
als Anmerkung verwenden¶
Beachten Sie, dass Field(strict=True)
(oder mit anderen Schlüsselwortargumenten) bei Bedarf als Anmerkung verwendet werden kann, z. B. bei der Arbeit mit TypedDict
:
from typing_extensions import Annotated, TypedDict
from pydantic import Field, TypeAdapter, ValidationError
class MyDict(TypedDict):
x: Annotated[int, Field(strict=True)]
try:
TypeAdapter(MyDict).validate_python({'x': '1'})
except ValidationError as exc:
print(exc)
"""
1 validation error for typed-dict
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
Strikter Modus mit Annotated[..., Strict()]
¶
??? API „API-Dokumentation“ pydantic.types.Strict
Pydantic stellt auch die Strict
-Klasse bereit, die als Metadaten mit der Klasse typing.Annotated
verwendet werden soll; Diese Anmerkung gibt an, dass das mit Anmerkungen versehene Feld im strikten Modus validiert werden sollte:
from typing_extensions import Annotated
from pydantic import BaseModel, Strict, ValidationError
class User(BaseModel):
name: str
age: int
is_active: Annotated[bool, Strict()]
User(name='David', age=33, is_active=True)
try:
User(name='David', age=33, is_active='True')
except ValidationError as exc:
print(exc)
"""
1 validation error for User
is_active
Input should be a valid boolean [type=bool_type, input_value='True', input_type=str]
"""
Dies ist in der Tat die Methode, mit der einige der von Pydantic bereitgestellten strikten Standardtypen implementiert werden, z. B. StrictInt
.
Strikter Modus mit ConfigDict
¶
BaseModel
¶
Wenn Sie den strikten Modus für alle Felder eines komplexen Eingabetyps aktivieren möchten, können Sie ConfigDict(strict=True)
in model_config
verwenden:
from pydantic import BaseModel, ConfigDict, ValidationError
class User(BaseModel):
model_config = ConfigDict(strict=True)
name: str
age: int
is_active: bool
try:
User(name='David', age='33', is_active='yes')
except ValidationError as exc:
print(exc)
"""
2 validation errors for User
age
Input should be a valid integer [type=int_type, input_value='33', input_type=str]
is_active
Input should be a valid boolean [type=bool_type, input_value='yes', input_type=str]
"""
!!! Hinweis Wenn Sie strict=True
über die model_config
eines Modells verwenden, können Sie die Strenge einzelner Felder dennoch überschreiben, indem Sie strict=False
für einzelne Felder festlegen:
```py
from pydantic import BaseModel, ConfigDict, Field
class User(BaseModel):
model_config = ConfigDict(strict=True)
name: str
age: int = Field(strict=False)
```
Beachten Sie, dass der strikte Modus nicht rekursiv auf verschachtelte Modellfelder angewendet wird:
from pydantic import BaseModel, ConfigDict, ValidationError
class Inner(BaseModel):
y: int
class Outer(BaseModel):
model_config = ConfigDict(strict=True)
x: int
inner: Inner
print(Outer(x=1, inner=Inner(y='2')))
#> x=1 inner=Inner(y=2)
try:
Outer(x='1', inner=Inner(y='2'))
except ValidationError as exc:
print(exc)
"""
1 validation error for Outer
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
(Dies gilt auch für Datenklassen und TypedDict
.)
Wenn dies unerwünscht ist, sollten Sie sicherstellen, dass für alle beteiligten Typen der strikte Modus aktiviert ist. Dies kann beispielsweise für Modellklassen durch die Verwendung einer gemeinsam genutzten Basisklasse mit erfolgen model_config = ConfigDict(strict=True)
:
from pydantic import BaseModel, ConfigDict, ValidationError
class MyBaseModel(BaseModel):
model_config = ConfigDict(strict=True)
class Inner(MyBaseModel):
y: int
class Outer(MyBaseModel):
x: int
inner: Inner
try:
Outer.model_validate({'x': 1, 'inner': {'y': '2'}})
except ValidationError as exc:
print(exc)
"""
1 validation error for Outer
inner.y
Input should be a valid integer [type=int_type, input_value='2', input_type=str]
"""
Datenklassen und TypedDict
¶
Pydantic-Datenklassen verhalten sich ähnlich wie die oben gezeigten Beispiele mit BaseModel
, nur dass Sie anstelle von model_config
das Schlüsselwortargument config
verwenden sollten @pydantic.dataclasses.dataclass
Dekorateur.
Wenn möglich, können Sie einen verschachtelten strikten Modus für Vanilla-Datenklassen oder TypedDict
Unterklassen erreichen, indem Sie Felder mit der Annotation pydantic.types.Strict
annotieren.
Wenn dies jedoch nicht möglich ist (z. B. wenn Sie mit Typen von Drittanbietern arbeiten), können Sie die Konfiguration festlegen, die Pydantic für den Typ verwenden soll, indem Sie das Attribut __pydantic_config__
für den Typ festlegen:
from typing_extensions import TypedDict
from pydantic import ConfigDict, TypeAdapter, ValidationError
class Inner(TypedDict):
y: int
Inner.__pydantic_config__ = ConfigDict(strict=True)
class Outer(TypedDict):
x: int
inner: Inner
adapter = TypeAdapter(Outer)
print(adapter.validate_python({'x': '1', 'inner': {'y': 2}}))
#> {'x': 1, 'inner': {'y': 2}}
try:
adapter.validate_python({'x': '1', 'inner': {'y': '2'}})
except ValidationError as exc:
print(exc)
"""
1 validation error for typed-dict
inner.y
Input should be a valid integer [type=int_type, input_value='2', input_type=str]
"""
TypeAdapter
¶
Sie können den strikten Modus auch durch die Verwendung des Schlüsselwortarguments config für die TypeAdapter
-Klasse erreichen:
from pydantic import ConfigDict, TypeAdapter, ValidationError
adapter = TypeAdapter(bool, config=ConfigDict(strict=True))
try:
adapter.validate_python('yes')
except ValidationError as exc:
print(exc)
"""
1 validation error for bool
Input should be a valid boolean [type=bool_type, input_value='yes', input_type=str]
"""
@validate_call
¶
Der strikte Modus kann auch mit dem @validate_call
-Dekorator verwendet werden, indem das Schlüsselwortargument config
übergeben wird:
from pydantic import ConfigDict, ValidationError, validate_call
@validate_call(config=ConfigDict(strict=True))
def foo(x: int) -> int:
return x
try:
foo('1')
except ValidationError as exc:
print(exc)
"""
1 validation error for foo
0
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
本文总阅读量次