Skip to content

Commit

Permalink
Address case where model_construct on a class which defines model_pos…
Browse files Browse the repository at this point in the history
…t_init fails with AttributeError: __pydantic_private__ when subsequently model_copy'd (#9168)

Co-authored-by: David Grimes <david.grimes@axial.net>
  • Loading branch information
babygrimes and David Grimes authored Apr 19, 2024
1 parent 6322b24 commit 77b0e1c
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 3 deletions.
6 changes: 3 additions & 3 deletions pydantic/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ def __copy__(self: Model) -> Model:
_object_setattr(m, '__pydantic_extra__', copy(self.__pydantic_extra__))
_object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__))

if self.__pydantic_private__ is None:
if not hasattr(self, '__pydantic_private__') or self.__pydantic_private__ is None:
_object_setattr(m, '__pydantic_private__', None)
else:
_object_setattr(
Expand All @@ -763,7 +763,7 @@ def __deepcopy__(self: Model, memo: dict[int, Any] | None = None) -> Model:
# and attempting a deepcopy would be marginally slower.
_object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__))

if self.__pydantic_private__ is None:
if not hasattr(self, '__pydantic_private__') or self.__pydantic_private__ is None:
_object_setattr(m, '__pydantic_private__', None)
else:
_object_setattr(
Expand Down Expand Up @@ -923,7 +923,7 @@ def __eq__(self, other: Any) -> bool:
# Perform common checks first
if not (
self_type == other_type
and self.__pydantic_private__ == other.__pydantic_private__
and getattr(self, '__pydantic_private__', None) == getattr(other, '__pydantic_private__', None)
and self.__pydantic_extra__ == other.__pydantic_extra__
):
return False
Expand Down
14 changes: 14 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3280,3 +3280,17 @@ class Y(BaseModel):
x: Union[X, None]

assert Y(x={'y': None}).x.y is None


def test_model_construct_with_model_post_init_and_model_copy() -> None:
class Model(BaseModel):
id: int

def model_post_init(self, context: Any) -> None:
super().model_post_init(context)

m = Model.model_construct(id=1)
copy = m.model_copy(deep=True)

assert m == copy
assert id(m) != id(copy)

0 comments on commit 77b0e1c

Please sign in to comment.