Strikte modus
??? api "API-documentatie" pydantic.types.Strict
Standaard zal Pydantic proberen waar mogelijk waarden naar het gewenste type te dwingen. U kunt bijvoorbeeld de tekenreeks "123"
doorgeven als invoer voor een int
-veld, waarna deze wordt geconverteerd naar 123
. Dit dwanggedrag is nuttig in veel scenario's - denk aan: UUID's, URL-parameters, HTTP-headers, omgevingsvariabelen, gebruikersinvoer, enz.
Er zijn echter ook situaties waarin dit niet wenselijk is en u wilt dat Pydantic fouten maakt in plaats van gegevens af te dwingen.
Om dit gebruiksscenario beter te ondersteunen, biedt Pydantic een "strikte modus" die kan worden ingeschakeld per model, per veld of zelfs per validatie-oproep. Wanneer de strikte modus is ingeschakeld, zal Pydantic veel minder toegeeflijk zijn bij het afdwingen van gegevens, en in plaats daarvan fouten maken als de gegevens niet van het juiste type zijn.
Hier is een kort voorbeeld dat het verschil laat zien tussen validatiegedrag in de strikte en de standaard/"lax"-modus:
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]
"""
Er zijn verschillende manieren om validatie in de strikte modus te verkrijgen tijdens het gebruik van Pydantic, die hieronder in meer detail zullen worden besproken:
- Doorgeven
strict=True
aan de validatiemethoden , zoalsBaseModel.model_validate
,TypeAdapter.validate_python
en vergelijkbaar voor JSON Field(strict=True)
gebruiken met velden van eenBaseModel
,dataclass
ofTypedDict
pydantic.types.Strict
gebruiken als typeannotatie in een veld- Pydantic biedt een aantal typealiassen die al zijn geannoteerd met
Strict
, zoalspydantic.types.StrictInt
- Pydantic biedt een aantal typealiassen die al zijn geannoteerd met
ConfigDict(strict=True)
Typ dwangmaatregelen in strikte modus¶
Voor de meeste typen worden bij het valideren van gegevens uit Python in de strikte modus alleen de exemplaren van de exacte typen geaccepteerd. Bij het valideren van een int
veld worden bijvoorbeeld alleen exemplaren van int
geaccepteerd; het doorgeven van exemplaren van float
of str
zal resulteren in het genereren van een ValidationError
.
Houd er rekening mee dat we losser zijn bij het valideren van gegevens uit JSON in de strikte modus. Bij het valideren van een UUID
-veld worden bijvoorbeeld exemplaren van str
geaccepteerd bij het valideren vanuit JSON, maar niet vanuit 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'},
}
]
"""
Voor meer details over welke typen zijn toegestaan als invoer in de strikte modus, kunt u de Conversietabel raadplegen.
Strikte modus bij methodeaanroepen¶
Alle tot nu toe opgenomen voorbeelden krijgen validatie in de strikte modus door het gebruik van strict=True
als trefwoordargument voor de validatiemethoden. Hoewel we dit voor BaseModel.model_validate
hebben laten zien, werkt dit ook met willekeurige typen door het gebruik van TypeAdapter
:
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]
"""
Merk op dat dit ook werkt als u meer "complexe" typen gebruikt in TypeAdapter
:
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]
"""
Dit werkt ook met de methoden TypeAdapter.validate_json
en 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]
"""
Strikte modus met Field
¶
Voor individuele velden in een model kunt u strict=True
instellen voor het veld . Dit zorgt ervoor dat er voor dat veld validatie in de strikte modus wordt gebruikt, zelfs als de validatiemethoden worden aangeroepen zonder strict=True
.
Alleen de velden waarvoor strict=True
is ingesteld, worden beïnvloed:
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]
"""
Houd er rekening mee dat het strikt maken van velden ook invloed heeft op de validatie die wordt uitgevoerd bij het instantiëren van de modelklasse:
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
gebruiken als annotatie¶
Houd er rekening mee dat Field(strict=True)
(of met andere trefwoordargumenten) indien nodig als annotatie kan worden gebruikt, bijvoorbeeld wanneer u met TypedDict
werkt:
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]
"""
Strikte modus met Annotated[..., Strict()]
¶
??? api "API-documentatie" pydantic.types.Strict
Pydantic biedt ook de klasse Strict
, die bedoeld is voor gebruik als metadata met de klasse typing.Annotated
; deze annotatie geeft aan dat het geannoteerde veld in de strikte modus moet worden gevalideerd:
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]
"""
Dit is in feite de methode die wordt gebruikt om enkele van de strikt-out-of-the-box typen van Pydantic te implementeren, zoals StrictInt
.
Strikte modus met ConfigDict
¶
BaseModel
¶
Als u de strikte modus wilt inschakelen voor alle velden op een complex invoertype, kunt u ConfigDict(strict=True)
gebruiken in model_config
:
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]
"""
!!! note Wanneer u strict=True
gebruikt via model_config
van een model, kunt u nog steeds de striktheid van individuele velden overschrijven door strict=False
in te stellen voor individuele velden:
```py
from pydantic import BaseModel, ConfigDict, Field
class User(BaseModel):
model_config = ConfigDict(strict=True)
name: str
age: int = Field(strict=False)
```
Houd er rekening mee dat de strikte modus niet recursief wordt toegepast op geneste modelvelden:
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]
"""
(Dit is ook het geval voor dataclasses en TypedDict
.)
Als dit ongewenst is, zorg er dan voor dat de strikte modus is ingeschakeld voor alle betrokken typen. Dit kan bijvoorbeeld voor modelklassen worden gedaan door een gedeelde basisklasse te gebruiken 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]
"""
Dataklassen en TypedDict
¶
Pydantic dataclasses gedragen zich op dezelfde manier als de hierboven getoonde voorbeelden met BaseModel
, alleen dat u in plaats van model_config
het trefwoord config
moet gebruiken voor de @pydantic.dataclasses.dataclass
decorateur.
Indien mogelijk kunt u de geneste strikte modus voor gewone dataclasses of TypedDict
subklassen bereiken door velden te annoteren met de annotatie pydantic.types.Strict
.
Als dit echter niet mogelijk is (bijvoorbeeld als u met typen van derden werkt), kunt u de configuratie instellen die Pydantic voor het type moet gebruiken door het attribuut __pydantic_config__
op het type in te stellen:
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
¶
Je kunt ook de strikte modus verkrijgen door het trefwoord config te gebruiken voor de klasse TypeAdapter
:
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
¶
De strikte modus is ook bruikbaar met de @validate_call
decorateur door het config
trefwoordargument door te geven:
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]
"""
本文总阅读量次