Skip to content

Commit d589082

Browse files
xr843claude
andcommitted
Fixed PrivateAttr defaults lost when loading from database (#149)
When SQLAlchemy reconstructs a model instance from a database query (bypassing __init__), it goes through __new__ which calls init_pydantic_private_attrs(). That function was setting __pydantic_private__ = None instead of initializing it with the private attribute defaults. This caused AttributeError when accessing PrivateAttr fields on database-loaded instances. The fix introspects the class's __private_attributes__ dict and calls get_default() on each entry, mirroring what Pydantic's own __init__ does. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 530c268 commit d589082

File tree

1 file changed

+12
-1
lines changed

1 file changed

+12
-1
lines changed

sqlmodel/_compat.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,18 @@ def get_model_fields(model: InstanceOrType[BaseModel]) -> dict[str, "FieldInfo"]
9494
def init_pydantic_private_attrs(new_object: InstanceOrType["SQLModel"]) -> None:
9595
object.__setattr__(new_object, "__pydantic_fields_set__", set())
9696
object.__setattr__(new_object, "__pydantic_extra__", None)
97-
object.__setattr__(new_object, "__pydantic_private__", None)
97+
# Initialize __pydantic_private__ with defaults from __private_attributes__,
98+
# mirroring what Pydantic's own BaseModel.__init__ does. Previously this was
99+
# set to None, which caused AttributeError when accessing PrivateAttr fields
100+
# on instances reconstructed from the database (via __new__, bypassing __init__).
101+
pydantic_private = {}
102+
for k, v in new_object.__class__.__private_attributes__.items():
103+
pydantic_private[k] = v.get_default(call_default_factory=True)
104+
object.__setattr__(
105+
new_object,
106+
"__pydantic_private__",
107+
pydantic_private if pydantic_private else None,
108+
)
98109

99110

100111
def get_annotations(class_dict: dict[str, Any]) -> dict[str, Any]:

0 commit comments

Comments
 (0)