Skip to content

Commit

Permalink
Merge pull request #347 from reagento/doc/why-no-pydantic-main
Browse files Browse the repository at this point in the history
Add "Why not Pydantic?" article
  • Loading branch information
zhPavel authored Nov 23, 2024
2 parents 4252c10 + 43f341f commit 21b4ec1
Show file tree
Hide file tree
Showing 18 changed files with 606 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/benchmarks.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _benchmarks:

==================
Benchmarks
==================
Expand Down
Empty file.
12 changes: 12 additions & 0 deletions docs/examples/why_not_pydantic/aliasing_mess_extra.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from pydantic import BaseModel, ConfigDict, Field


class User(BaseModel):
model_config = ConfigDict(populate_by_name=True, extra="allow")

name: str = Field(alias="full_name")
age: int


data = {"name": "name_value", "age": 20}
assert User.model_validate(data).model_extra == {}
12 changes: 12 additions & 0 deletions docs/examples/why_not_pydantic/implicit_conversions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# mypy: disable-error-code="arg-type"
from decimal import Decimal

from pydantic import BaseModel


class Product(BaseModel):
id: int
amount: Decimal


assert Product(id=1, amount=14.6) == Product(id=1, amount=Decimal("14.6"))
23 changes: 23 additions & 0 deletions docs/examples/why_not_pydantic/implicit_conversions_workaround.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# mypy: disable-error-code="arg-type"
from decimal import Decimal

from pydantic import BaseModel, ConfigDict, ValidationError


class Product(BaseModel):
id: int
amount: Decimal

model_config = ConfigDict(strict=True)


try:
Product(id=1, amount=14.6)
except ValidationError:
pass

assert (
Product.model_validate({"id": 1, "amount": 14.6}, strict=False)
==
Product(id=1, amount=Decimal("14.6"))
)
15 changes: 15 additions & 0 deletions docs/examples/why_not_pydantic/instantiating_penalty_benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# ruff: noqa: T201
from datetime import datetime
from timeit import timeit

from .instantiating_penalty_models import UserDataclass, UserPydantic

stmt = """
User(
id=123,
signup_ts=datetime(year=2019, month=6, day=1, hour=12, minute=22),
tastes={'wine': 9, 'cheese': 7, 'cabbage': '1'},
)
"""
print("pydantic ", timeit(stmt, globals={"User": UserPydantic, "datetime": datetime}))
print("dataclass", timeit(stmt, globals={"User": UserDataclass, "datetime": datetime}))
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# ruff: noqa: T201
from datetime import datetime
from timeit import timeit

from .instantiating_penalty_models import UserDataclass, UserPydantic

stmt = """
User(
id=123,
signup_ts=dt,
tastes={'wine': 9, 'cheese': 7, 'cabbage': '1'},
)
"""
dt = datetime(year=2019, month=6, day=1, hour=12, minute=22)
print(
"pydantic ",
timeit(stmt, globals={"User": UserPydantic, "dt": dt}),
)
print(
"pydantic (model_construct)",
timeit(stmt, globals={"User": UserPydantic.model_construct, "dt": dt}),
)
print(
"dataclass ",
timeit(stmt, globals={"User": UserDataclass, "dt": dt}),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# ruff: noqa: T201
from datetime import datetime
from timeit import timeit

from .instantiating_penalty_benchmark import UserPydantic, stmt

print(
"pydantic (model_construct)",
timeit(stmt, globals={"User": UserPydantic.model_construct, "datetime": datetime}),
)
20 changes: 20 additions & 0 deletions docs/examples/why_not_pydantic/instantiating_penalty_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from dataclasses import dataclass
from datetime import datetime
from typing import Optional

from pydantic import BaseModel, PositiveInt


class UserPydantic(BaseModel):
id: int
name: str = "John Doe"
signup_ts: Optional[datetime]
tastes: dict[str, PositiveInt]


@dataclass(kw_only=True)
class UserDataclass:
id: int
name: str = "John Doe"
signup_ts: Optional[datetime]
tastes: dict[str, PositiveInt]
19 changes: 19 additions & 0 deletions docs/examples/why_not_pydantic/migration_pydantic_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from pydantic import BaseModel

from adaptix import Retort


class Book(BaseModel):
title: str
price: int


data = {
"title": "Fahrenheit 451",
"price": 100,
}

retort = Retort()
book = retort.load(data, Book)
assert book == Book(title="Fahrenheit 451", price=100)
assert retort.dump(book) == data
14 changes: 14 additions & 0 deletions docs/examples/why_not_pydantic/mistakes_silencing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# mypy: disable-error-code="call-arg"
from pydantic import BaseModel


class SomeModel(BaseModel):
a: int
b: int


SomeModel(
a=1,
b=2,
c=3, # unknown filed!
)
21 changes: 21 additions & 0 deletions docs/examples/why_not_pydantic/underdone_class_mapping_default.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# mypy: disable-error-code="call-arg"
from dataclasses import dataclass
from typing import Optional

from pydantic import BaseModel


@dataclass
class Book:
title: str
author: str


class BookDTO(BaseModel):
title: str
writer: Optional[str] = None # alias is forgotten!


book = Book(title="Fahrenheit 451", author="Ray Bradbury")
book_dto = BookDTO.model_validate(book, from_attributes=True)
assert book_dto == BookDTO(title="Fahrenheit 451", author=None)
19 changes: 19 additions & 0 deletions docs/examples/why_not_pydantic/underdone_class_mapping_intro.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from dataclasses import dataclass

from pydantic import BaseModel


@dataclass
class Person:
name: str
age: float


class PersonDTO(BaseModel):
name: str
age: float


person = Person(name="Anna", age=20)
person_dto = PersonDTO.model_validate(person, from_attributes=True)
assert person_dto == PersonDTO(name="Anna", age=20)
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Adaptix

overview
benchmarks
why-not-pydantic

.. toctree::
:maxdepth: 2
Expand Down
2 changes: 2 additions & 0 deletions docs/loading-and-dumping/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ Some facts about ``P``:
situated at field ``name``, placed at model ``Foo``


.. _retort_extension_and_combination:

Retort extension and combination
-------------------------------------

Expand Down
Loading

0 comments on commit 21b4ec1

Please sign in to comment.