Skip to content

Commit 77b0e1c

Browse files
babygrimesDavid Grimes
and
David Grimes
authoredApr 19, 2024··
Address case where model_construct on a class which defines model_post_init fails with AttributeError: __pydantic_private__ when subsequently model_copy'd (#9168)
Co-authored-by: David Grimes <[email protected]>
1 parent 6322b24 commit 77b0e1c

File tree

2 files changed

+17
-3
lines changed

2 files changed

+17
-3
lines changed
 

‎pydantic/main.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ def __copy__(self: Model) -> Model:
742742
_object_setattr(m, '__pydantic_extra__', copy(self.__pydantic_extra__))
743743
_object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__))
744744

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

766-
if self.__pydantic_private__ is None:
766+
if not hasattr(self, '__pydantic_private__') or self.__pydantic_private__ is None:
767767
_object_setattr(m, '__pydantic_private__', None)
768768
else:
769769
_object_setattr(
@@ -923,7 +923,7 @@ def __eq__(self, other: Any) -> bool:
923923
# Perform common checks first
924924
if not (
925925
self_type == other_type
926-
and self.__pydantic_private__ == other.__pydantic_private__
926+
and getattr(self, '__pydantic_private__', None) == getattr(other, '__pydantic_private__', None)
927927
and self.__pydantic_extra__ == other.__pydantic_extra__
928928
):
929929
return False

‎tests/test_main.py

+14
Original file line numberDiff line numberDiff line change
@@ -3280,3 +3280,17 @@ class Y(BaseModel):
32803280
x: Union[X, None]
32813281

32823282
assert Y(x={'y': None}).x.y is None
3283+
3284+
3285+
def test_model_construct_with_model_post_init_and_model_copy() -> None:
3286+
class Model(BaseModel):
3287+
id: int
3288+
3289+
def model_post_init(self, context: Any) -> None:
3290+
super().model_post_init(context)
3291+
3292+
m = Model.model_construct(id=1)
3293+
copy = m.model_copy(deep=True)
3294+
3295+
assert m == copy
3296+
assert id(m) != id(copy)

0 commit comments

Comments
 (0)