엄격 모드
??? api "API 문서" pydantic.types.Strict
기본적으로 Pydantic은 가능하면 값을 원하는 유형으로 강제 변환하려고 시도합니다. 예를 들어 문자열 "123"
int
필드에 대한 입력으로 전달할 수 있으며 이는 123
으로 변환됩니다. 이 강제 동작은 UUID, URL 매개변수, HTTP 헤더, 환경 변수, 사용자 입력 등 다양한 시나리오에서 유용합니다.
그러나 이것이 바람직하지 않은 상황도 있으며, Pydantic이 데이터를 강제하는 대신 오류를 일으키기를 원합니다.
이 사용 사례를 더 잘 지원하기 위해 Pydantic은 모델별, 필드별 또는 유효성 검사 호출별로 활성화할 수 있는 "엄격 모드"를 제공합니다. 엄격 모드가 활성화되면 Pydantic은 데이터를 강제할 때 훨씬 덜 관대해지며 대신 데이터가 올바른 유형이 아닌 경우 오류가 발생합니다.
다음은 엄격한 검증 동작과 기본/"느슨한" 모드 간의 차이점을 보여주는 간단한 예입니다.
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을 사용하는 동안 엄격 모드 유효성 검사를 수행하는 다양한 방법이 있으며, 이에 대해서는 아래에서 자세히 설명합니다.
BaseModel.model_validate
,TypeAdapter.validate_python
및 JSON과 유사한 유효성 검사 메서드에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
사용한 엄격 모드¶
모델의 개별 필드에 대해 field에서 strict=True
설정할 수 있습니다. 이렇게 하면 strict=True
없이 유효성 검사 메서드가 호출되는 경우에도 해당 필드에 대해 엄격 모드 유효성 검사가 사용됩니다.
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()]
사용한 엄격한 모드¶
??? 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
¶
엄격 모드는 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]
"""
本文总阅读量次