厳格モード
??? API「APIドキュメント」 pydantic.types.Strict
デフォルトでは、Pydantic は可能な場合、値を目的の型に強制しようとします。たとえば、文字列"123"
入力としてint
フィールドに渡すと、それは123
に変換されます。この強制動作は、UUID、URL パラメーター、HTTP ヘッダー、環境変数、ユーザー入力などの多くのシナリオで役立ちます。
ただし、これが望ましくなく、データを強制するのではなく Pydantic にエラーを発生させたい状況もあります。
このユースケースをより適切にサポートするために、Pydantic はモデルごと、フィールドごと、さらには検証呼び出しごとに有効にできる「厳密モード」を提供します。厳密モードが有効になっている場合、Pydantic はデータを強制する際の寛容性が大幅に低下し、データが正しい型でない場合はエラーが発生します。
以下は、strict モードとデフォルト/「lax」モードでの検証動作の違いを示す簡単な例です。
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]
"""
Pydantic の使用中に厳密モードの検証を取得するにはさまざまな方法がありますが、これについては以下で詳しく説明します。
- JSON の
BaseModel.model_validate
、TypeAdapter.validate_python
などの検証メソッドにstrict=True
渡す BaseModel
、dataclass
、またはTypedDict
のフィールドでField(strict=True)
を使用する- フィールドの型アノテーションとして
pydantic.types.Strict
使用する- Pydantic は、
pydantic.types.StrictInt
など、すでにStrict
の注釈が付けられているいくつかの型エイリアスを提供します。
- Pydantic は、
ConfigDict(strict=True)
の使用
厳密モードでの型強制¶
ほとんどの型では、厳密モードで Python からのデータを検証する場合、正確な型のインスタンスのみが受け入れられます。たとえば、 int
フィールドを検証する場合、 int
のインスタンスのみが受け入れられます。 float
またはstr
のインスタンスを渡すと、 ValidationError
が発生します。
厳密モードで JSON からのデータを検証する場合はより緩やかになることに注意してください。たとえば、 UUID
フィールドを検証する場合、JSON から検証する場合はstr
のインスタンスが受け入れられますが、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'},
}
]
"""
厳密モードで入力として許可される型の詳細については、 「変換テーブル」を参照してください。
メソッド呼び出しの厳密モード¶
これまでに含まれているすべての例では、検証メソッドのキーワード引数としてstrict=True
を使用することで、厳密モードの検証が行われます。これはBaseModel.model_validate
について示しましたが、これは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]
"""
これは、 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]
"""
これは、 TypeAdapter.validate_json
と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]
"""
Field
付きストリクトモード¶
モデルの個々のフィールドについては、そのフィールドにstrict=True
を設定できます。これにより、 strict=True
を指定せずに検証メソッドが呼び出された場合でも、そのフィールドに対して strict モードの検証が使用されます。
strict=True
が設定されているフィールドのみが影響を受けます。
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]
"""
フィールドを厳密にすると、モデル クラスをインスタンス化するときに実行される検証にも影響することに注意してください。
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
注釈として使用する¶
Field(strict=True)
(または他のキーワード引数とともに) は、必要に応じて注釈として使用できることに注意してください。たとえば、 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]
"""
Annotated[..., Strict()]
を使用した Strict モード¶
??? API「APIドキュメント」 pydantic.types.Strict
Pydantic は、typing.Annotated
クラスのメタデータとして使用することを目的としたStrict
クラスも提供します。この注釈は、注釈付きフィールドが厳密モードで検証される必要があることを示します。
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]
"""
実際、これは、 StrictInt
など、Pydantic が提供するいくつかのすぐに使える厳密な型を実装するために使用されるメソッドです。
ConfigDict
を使用したストリクト モード¶
BaseModel
¶
複合入力タイプのすべてのフィールドに対して厳密モードを有効にしたい場合は、 model_config
でConfigDict(strict=True)
を使用できます。
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 モデルのmodel_config
でstrict=True
使用する場合でも、個々のフィールドにstrict=False
を設定することで、個々のフィールドの厳密性をオーバーライドできます。
```py
from pydantic import BaseModel, ConfigDict, Field
class User(BaseModel):
model_config = ConfigDict(strict=True)
name: str
age: int = Field(strict=False)
```
厳密モードは、ネストされたモデル フィールドには再帰的に適用されないことに注意してください。
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]
"""
(これはデータクラスとTypedDict
にも当てはまります。)
これが望ましくない場合は、関係するすべてのタイプに対して厳密モードが有効になっていることを確認する必要があります。たとえば、これは、共有基本クラスを使用してモデル クラスに対して実行できます。 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]
"""
データクラスとTypedDict
¶
Pydantic データクラスは、 BaseModel
を使用した上記の例と同様に動作します。ただし、 model_config
の代わりにconfig
キーワード引数を使用する必要がある点が異なります。 @pydantic.dataclasses.dataclass
デコレーター。
可能であれば、フィールドにpydantic.types.Strict
アノテーションを付けることで、バニラ データクラスまたはTypedDict
サブクラスのネストされた厳密モードを実現できます。
ただし、これが_不可能_な場合 (サードパーティの型を使用する場合など)、型の__pydantic_config__
属性を設定することで、Pydantic がその型に使用する構成を設定できます。
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
¶
TypeAdapter
クラスの config キーワード引数を使用して、厳密モードを取得することもできます。
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
¶
Strict モードは、 config
キーワード引数を渡すことで@validate_call
デコレータでも使用できます。
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]
"""
本文总阅读量次