Python/Utils

파이썬 데이터 유효성 검증 모듈 pydantic 사용법 정리

jimmy_AI 2024. 6. 5. 01:10
반응형

Python은 기본적으로 변수를 정의할 때, 데이터 타입 및 조건 검증 과정을 거치지 않는데요.

따라서, 데이터를 정의하는 과정에서 타입 등 유효성 조건이 맞는지 확인하는 과정이 필요하다면

별도의 검증 과정을 따로 구현해야 합니다.

 

이 과정에서 pydantic 모듈을 활용하면 검증 단계를 매우 쉽게 진행할 수 있는데요.

이번 글에서는 해당 라이브러리의 사용 방법을 간략하게 예제로 정리해보도록 하겠습니다.

 

 

모듈 설치 방법

pydantic 모듈은 !pip install pydantic 명령어로 쉽게 설치가 가능합니다.

 

 

BaseModel 정의

데이터의 타입을 특정 종류로 지정하기 위해서는 BaseModel을 불러와

클래스에 상속시켜주는 과정이 필요합니다. 코드의 예시는 다음과 같습니다.

from pydantic import BaseModel
from datetime import datetime
from typing import Optional, List

class User(BaseModel):
    id: int
    name: str
    birth_time : Optional[datetime] = None
    hobby: List[str]

User라는 데이터 객체의 id는 정수, name은 문자열로 강제되며,

birth_time은 필수는 아니지만 입력을 받게 된다면 datetime 객체여야 하며,

hobby는 문자열로 구성된 리스트여야 한다는 것을 쉽게 이해해볼 수 있습니다.

 

User 객체를 선언하고, 이를 print해본 결과는 다음과 같습니다.

user = User(
    id=1,
    name='Jimmy',
    birth_time=datetime.now(),
    hobby=["baseball", "piano"]
)

print(user)
# id=1 name='Jimmy' birth_time=datetime.datetime(2024, 6, 4, 15, 48, 39, 160154) hobby=['baseball', 'piano']

 

만일, 위 조건에 위배되는 사항이 있다면 다음과 같이 오류 메시지를 반환하게 됩니다.

invalid_user = User(id='정수가 아님', name="example", hobby=["eaxmple"])

# 오류 메시지 예시
ValidationError: 1 validation error for User
id
  Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='정수가 아님', input_type=str]
    For further information visit https://errors.pydantic.dev/2.7/v/int_parsing

id 항목이 int가 아닌 str이라서 선언이 불가능하다는 것을 알 수 있습니다.

 

참고로, 이렇게 선언한 객체의 경우 dict나 json 객체로 쉽게 변환이 가능합니다.

# 딕셔너리로 변환
user_dict = user.dict()

# JSON 문자열로 변환
user_json = user.json()

 

 

BaseModel 중첩

BaseModel로 선언한 객체의 경우 중첩을 시켜 더 복합적인 객체의 유효성도

검증하는 것이 가능해집니다. 코드의 예시는 다음과 같습니다.

class Address(BaseModel):
    city: str
    country: str

class User(BaseModel):
    id: int
    name: str
    address: Address

address_data = {
    'city': 'Seoul',
    'country': 'South Korea'
}

user_data = {
    'id': 1,
    'name': 'Jimmy',
    'address': address_data
}

user = User(**user_data)
print(user) # id=1 name='Jimmy' address=Address(city='Seoul', country='South Korea')

User 객체 내에 Address라는 다른 객체가 중첩되고, User 선언 시에는

Address 객체의 조건에 해당하는 유효성까지 모두 만족시켜야 할 것입니다.

 

 

@validator 선언으로 커스텀 검증

만일, 특정 속성에 대한 검증 과정이 단순히 자료형 등만 보는 것이 아니라

더 복합적인 조건을 가진 경우 @validator를 클래스 내부에 선언하여

커스텀 검증 조건을 추가할 수 있습니다. 코드의 예시는 다음과 같습니다.

from pydantic import validator
from typing import Optional

class User(BaseModel):
    id: int
    name: str
    email: str

    @validator('email')
    def is_valid_email(cls, v):
        if '@' not in v:
            raise ValueError('must contain an "@" symbol')
        return v

invalid_user = User(id=1, name='Jimmy', email='not-an-email')
# 오류 발생
ValidationError: 1 validation error for User
email
  Value error, must contain an "@" symbol [type=value_error, input_value='not-an-email', input_type=str]
    For further information visit https://errors.pydantic.dev/2.7/v/value_error

email이라는 속성의 경우 @가 들어갔는지 추가로 검사하게 되며,

위에서 선언을 시도한 객체의 경우에는 @가 포함되지 않아 오류가 발생했습니다.

 

 

환경 변수 유효성 검증

pydantic의 추가 기능을 활용하면 환경 변수에 대해서도 유효성 검증이 가능합니다.

이 경우, pydantic-settings 모듈의 설치가 필요하며,

이는 !pip install pydantic-settings 명령어로 쉽게 가능합니다.

 

이 과정에서는 위의 BaseModel가 마찬가지로 BaseSettings가 사용되는데,

환경 변수의 유효성을 검증하는 코드의 예시는 다음과 같습니다.

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    name: str
    age: int
    level: int = 0
    
    @validator("age")
    def is_valid_age(cls, v):
        if v < 0:
            raise ValueError("age cannot be a negative number")
        return v

settings = Settings()

age의 경우에는 validator를 활용하여 음수인 경우에는 무효로 처리하였습니다.

 

level의 경우는 Optional의 케이스로 생각해주시면 되며,

환경 변수 입력 생략 시 0이 기본 값으로 설정된 케이스입니다.

 

이렇게 Settings로 선언한 객체에서 환경 변수를 가져오는 과정은

다음과 같이 매우 간단하게 수행할 수 있어 이후 환경 변수를 불러오는 과정도 편리해집니다.

print(settings.name)
print(settings.age)
print(settings.level)