Open1

pydantic v2 memo

名無し。名無し。
  • tagged union
tagged_union.py
from typing import Literal, NewType
from decimal import Decimal
from pydantic import BaseModel, TypeAdapter


class UnitQuantity(BaseModel):
    kind: Literal["unit"]
    quantity: int


class KilogramQuantity(BaseModel):
    kind: Literal["kilogram"]
    quantity: Decimal


type OrderQuantity = UnitQuantity | KilogramQuantity

CheckNumber = NewType("CheckNumber", int)
CardNumber = NewType("CardNumber", str)
"""単純型"""


if __name__ == "__main__":
    examples = [
        {"kind": "unit", "quantity": 10},
        {"kind": "kilogram", "quantity": "2.5"},
    ]
    adapter = TypeAdapter(OrderQuantity)
    for data in examples:
        oq = adapter.validate_python(data)
        print(f"Parsed {data} to {oq} (type : {type(oq)})")

    examples = [
        UnitQuantity(kind="unit", quantity=10),
        UnitQuantity(kind="unit", quantity=20),
        UnitQuantity(kind="unit", quantity=333),
        KilogramQuantity(kind="kilogram", quantity=Decimal("4.5")),
        KilogramQuantity(kind="kilogram", quantity=Decimal("2.5")),
    ]
    for data in examples:
        match data:
            case UnitQuantity(kind="unit", quantity=quantity):
                print(f"Unit quantity: {quantity}")
            case KilogramQuantity(kind="kilogram", quantity=quantity):
                print(f"Kilogram quantity: {quantity}")
            case _:
                raise ValueError(
                    f"Unknown quantity type {data.kind}, {type(data) = }, {data = }"
                )
    simple_types = [
        CheckNumber(12345678901234567890),
        CardNumber("1234567890123456"),
    ]
    for data in simple_types:
        print(f"Simple type: {data} (type : {type(data)})")

uv run python --version
# >>> Python 3.13.2
uv run python tagged_union.py 
# >>> Parsed {'kind': 'unit', 'quantity': 10} to kind='unit' quantity=10 (type : <class '__main__.UnitQuantity'>)
# >>> Parsed {'kind': 'kilogram', 'quantity': '2.5'} to kind='kilogram' quantity=Decimal('2.5') (type : <class '__main__.KilogramQuantity'>)