Able to raise error when the args does not match with predefined type
# from dataclasses import dataclass
from pydantic.dataclasses import dataclass
@dataclass
class Company:
corporate_id: int
name: str
country_id: int
good_company = Company(corporate_id=1, name="熊本株式会社", country_id=81)
print(good_company.corporate_id, good_company.name, good_company.country_id) # debug
# pydantic.error_wrappers.ValidationError: 1 validation error for Company corporate_id value is not a valid integer (type=type_error.integer)
bad_company1 = Company(corporate_id="not int", name="鹿児島株式会社", country_id=81)
pydantic is primarily a parsing library, not a validation library. Validation is a means to an end: building a model which conforms to the types and constraints provided. In other words,
pydantic guarantees the types and constraints of the output model, not the input data.
https://pydantic-docs.helpmanual.io/usage/models/#data-conversion
It means, when the args is castable to the predefined type, it won't raise error.
from pydantic.dataclasses import dataclass
@dataclass
class Company:
corporate_id: int
name: str
country_id: int
# 勝手にcast出来るものはcastされる
bad_company2 = Company(corporate_id=2.1, name=3.14, country_id="2")
print(bad_company2.corporate_id, type(bad_company2.corporate_id)) # 2 <class 'int'>
print(bad_company2.name, type(bad_company2.name)) # 3.14 <class 'str'>
print(bad_company2.country_id, type(bad_company2.country_id)) # 2 <class 'int'>
import dataclasses
import json
from pydantic.dataclasses import dataclass
from pydantic.json import pydantic_encoder
@dataclass
class User:
id: int
name: str = "John Doe"
friends: list[int] = dataclasses.field(default_factory=lambda: [0])
user = User(id="42")
# JSON化
user_json = json.dumps(user, indent=4, default=pydantic_encoder)
from datetime import datetime, timedelta
from pydantic import (
EmailStr,
FutureDate,
HttpUrl,
PastDate,
PositiveFloat,
PositiveInt,
confloat,
conint,
SecretStr,
)
from pydantic.dataclasses import dataclass
@dataclass
class User:
user_id: int
auth_date: PastDate
expire_date: FutureDate
email_addres: EmailStr
user_page: HttpUrl
age: PositiveInt
height: PositiveFloat
money: conint(gt=1000, lt=1024)
score: confloat(ge=3.5, lt=5)
password: SecretStr
user = User(
user_id=1,
auth_date=datetime.now() - timedelta(days=1),
expire_date=datetime.now() + timedelta(days=1),
email_addres="[email protected]",
user_page="https://zenn.dev/",
age=12,
height=1.72,
money=1001,
score=3.5,
password="hogehoge",
)
ref: https://pydantic-docs.helpmanual.io/usage/types/#pydantic-types
from pydantic import validator
from pydantic.dataclasses import dataclass
@dataclass
class User:
name: str
nick_name: str
password1: str
password2: str
@validator("name")
def name_must_contain_space(cls, v):
if " " not in v:
raise ValueError("must contain a space")
return v.title()
@validator("password2")
def passwords_match(cls, v, values, **kwargs):
# vとvaluesにはそれぞれフィールド値と該当のフィールド以外のデータが入ったdictがある
print("v", v) # hogehoge
print("values", values) # {'name': 'くまもと はまち', 'nick_name': 'kagoshima', 'password1': 'hogehoge'}
if "password1" in values and v != values["password1"]:
raise ValueError("passwords do not match")
return v
@validator("nick_name")
def username_alphanumeric(cls, v):
assert v.isalnum(), "must be alphanumeric"
return v
user = User(
name="くまもと はまち",
nick_name="kagoshima",
password1="hogehoge",
password2="hogehoge"
)
able to reuse validator function like this:
from pydantic import validator
from pydantic.dataclasses import dataclass
def name_must_contain_space(cls, v):
if " " not in v:
raise ValueError("must contain a space")
return v.title()
@dataclass
class Person1:
name: str
# validators
_normalize_name = validator("name", allow_reuse=True)(name_must_contain_space)
@dataclass
class Person2:
name: str
# validators
_normalize_name = validator("name", allow_reuse=True)(name_must_contain_space)
kagoshima = Person1(name="kagoshima gyoko")
print("kagoshima.name", kagoshima.name) # debug
kumamoto = Person2(name="kumamoto hamachi")
print("kumamoto.name", kumamoto.name) # debug
def get_config() -> Config:
with open(CONFIG_FILE_NAME, "rb") as f:
d = json.load(f)
return Config(**d)