pydantic은 데이터 검증 및 설정 관리를 위해 사용하는 python 라이브러리이다. 데이터 모델링을 위한 python 클래스와 타입 힌트를 기반으로 작동하며, 주로 FastAPI와 같은 프레임워크에서 많이 사용된다.
input 데이터가 1) 올바른 url, 2) 1-10 사이의 정수, 3) 올바른 폴더 이름을 입력했는지 검증해보자.
from pydantic import BaseModel, HttpUrl, Field, DirectoryPath
class Validation(BaseModel):
url: HttpUrl # 올바른 url인가?
rate: int = Field(ge=1, le=10) # 1-10 사이의 정수인가?
target_dir: DirectoryPath # 존재하는 디렉토리인가?
일반 python class나 dataclass 라이브러리를 사용할 수도 있지만, pydantic을 활용하면 훨씬 간결하게 validation을 할 수 있다. 자주 쓰이는 타입들(http url, db url, enum, ...)에 대한 validation은 이미 만들어져 있다. custom type에 대한 validation은 여기 참조.
from pydantic import ValidationError
VALID_INPUT = {
"url": "https://content.presspage.com/uploads/2658/c800_logo-stackoverflow-square.jpg?98978",
"rate": 4,
"target_dir": os.path.join(os.getcwd(), "examples"),
}
INVALID_INPUT = {"url": "WRONG_URL", "rate": 11, "target_dir": "WRONG_DIR"}
valid_pydantic_model_input = Validation(**VALID_INPUT)
try:
invalid_pydantic_model_input = Validation(**INVALID_INPUT) # error
except ValidationError as exc:
print("pydantic model input validation error: ", exc.json())
작성한 Validation 클래스를 이용해서 위와 같이 제대로 된 데이터를 입력했는지 검증할 수 있다. 어디서 에러가 발생했는지, location, type, message 등을 알려준다.
configuration은 코드 내에 상수로 작성하거나, yaml 파일로 관리할 수도 있지만, 배포 환경 별로 yaml 파일을 생성해야하는 번거로움도 있고, 보안 정보가 파일에 노출되기 때문에 주의가 필요하다.
from pydantic import BaseSettings, Field
from enum import Enum
class ConfigEnv(str, Enum):
DEV = "dev"
PROD = "prod"
class DBConfig(BaseSettings):
host: str = Field(default="localhost", env="db_host")
port: int = Field(default=3306, env="db_port")
username: str = Field(default="user", env="db_username")
password: str = Field(default="user", env="db_password")
database: str = Field(default="dev", env="db_database")
class AppConfig(BaseSettings):
env: ConfigEnv = Field(default="dev", env="env")
db: DBConfig = DBConfig()
with open("dev_config.yaml", "r") as f:
config = load(f, FullLoader)
config_with_pydantic = AppConfig(**config)
assert config_with_pydantic.env == "dev"
assert config_with_pydantic.db.dict() == expected
그러나 pydantic을 이용하면 환경 변수에 설정 값을 저장하고 코드에서 환경 변수를 읽어오기 때문에 보안 정보가 노출되지 않는다. yaml 등의 파일을 추가적으로 만들지 않아도 된다.
# 환경 변수로 필드를 오버라이딩
os.environ["ENV"] = "prod"
os.environ["DB_HOST"] = "mysql"
os.environ["DB_USERNAME"] = "admin"
os.environ["DB_PASSWORD"] = "PASSWORD"
prod_config_with_pydantic = AppConfig()
assert prod_config_with_pydantic.env == "prod"
assert prod_config_with_pydantic.dict() != expected
# cleanup
os.remove("dev_config.yaml")