-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Initial Checks
- I confirm that I'm using Pydantic V2
Description
Apparently the type safety of Pydantic models has deteriorated significantly from v1 to v2 due to the exposure of a __setattr__ method that accepts Any. This opens the door for a lot of serious bugs, because the type checkers fail to catch fundamental bugs like the following.
Example Code
from pydantic import BaseModel
class Foo(BaseModel):
some_field: int
def patch_object(foo: Foo) -> None:
# Ohoh, we got the field name wrong...
foo.some_feeld = 42
foo = Foo(some_field=1)
patch_object(foo)
assert foo.some_field == 42With Pydantic V1 this obvious bug was detected by both mypy and pyright. Mypy would for instance produce a very clear and helpful type error here:
error: "Foo" has no attribute "some_feeld"; maybe "some_field"? [attr-defined]
With Pydantic V2, the type checker completely misses the bug.
It should be quite straightforward to make the field access of BaseModel type safe again, by simply not exposing the __setattr__ method towards type checkers. Basically just this pattern (example on mypy playground):
from typing import Any, TYPE_CHECKING
class BaseModel:
if not TYPE_CHECKING:
def __setattr__(self, name: str, value: Any) -> None:
...
class Foo(BaseModel):
some_field: int
def patch_object(foo: Foo) -> None:
# Now the type checker will see the bug...
foo.some_feeld = 42Of course, in a completely strict sense this would be a "breaking" change, but since it looks rather like an bug/accident compared to V1, it would be really nice if this could be made type safe again. We just ran into such a fundamental bug resulting from this regression. This behavior is highly bug prone and also totally unexpected: Any type annotated dataclass-like type (including Pydantic V1 models) is naturally expected to respect the field annotations. After all, getting a field name wrong is one of the most basic of all bugs, and a primary reason for people to use type annotations and type checkers. If the code does not work at runtime (it crashes!), it should be flagged at type checking time.
Python, Pydantic & OS Version
I tried a range of pydantic versions including the upcoming 2.6.0b1. It looks like this used to work in 1.X but has started to fail in 2.X.
pydantic version: 2.6.0b1
pydantic-core version: 2.16.1
pydantic-core build: profile=release pgo=true
install path: /home/ekf2abt/git/scripts/pi_23/debug_pydantic_v2/venv/lib/python3.8/site-packages/pydantic
python version: 3.8.10 (default, Nov 22 2023, 10:22:35) [GCC 9.4.0]
platform: Linux-5.4.0-166-generic-x86_64-with-glibc2.29
related packages: typing_extensions-4.9.0 mypy-1.8.0
commit: unknown