Skip to content

Commit 1b7b3aa

Browse files
authored
🐛 Fix class initialization compatibility with Pydantic and SQLModel, fixing errors revealed by the latest Pydantic (#807)
1 parent 0c7def8 commit 1b7b3aa

File tree

3 files changed

+11
-13
lines changed

3 files changed

+11
-13
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ jobs:
6262
run: python -m poetry install
6363
- name: Install Pydantic v1
6464
if: matrix.pydantic-version == 'pydantic-v1'
65-
run: pip install "pydantic>=1.10.0,<2.0.0"
65+
run: pip install --upgrade "pydantic>=1.10.0,<2.0.0"
6666
- name: Install Pydantic v2
6767
if: matrix.pydantic-version == 'pydantic-v2'
68-
run: pip install "pydantic>=2.0.2,<3.0.0"
68+
run: pip install --upgrade "pydantic>=2.0.2,<3.0.0"
6969
- name: Lint
7070
# Do not run on Python 3.7 as mypy behaves differently
7171
if: matrix.python-version != '3.7' && matrix.pydantic-version == 'pydantic-v2'

sqlmodel/_compat.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,10 @@ def set_config_value(
9797
def get_model_fields(model: InstanceOrType["SQLModel"]) -> Dict[str, "FieldInfo"]:
9898
return model.model_fields
9999

100-
def set_fields_set(
101-
new_object: InstanceOrType["SQLModel"], fields: Set["FieldInfo"]
102-
) -> None:
103-
object.__setattr__(new_object, "__pydantic_fields_set__", fields)
100+
def init_pydantic_private_attrs(new_object: InstanceOrType["SQLModel"]) -> None:
101+
object.__setattr__(new_object, "__pydantic_fields_set__", set())
102+
object.__setattr__(new_object, "__pydantic_extra__", None)
103+
object.__setattr__(new_object, "__pydantic_private__", None)
104104

105105
def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]:
106106
return class_dict.get("__annotations__", {})
@@ -387,10 +387,8 @@ def set_config_value(
387387
def get_model_fields(model: InstanceOrType["SQLModel"]) -> Dict[str, "FieldInfo"]:
388388
return model.__fields__ # type: ignore
389389

390-
def set_fields_set(
391-
new_object: InstanceOrType["SQLModel"], fields: Set["FieldInfo"]
392-
) -> None:
393-
object.__setattr__(new_object, "__fields_set__", fields)
390+
def init_pydantic_private_attrs(new_object: InstanceOrType["SQLModel"]) -> None:
391+
object.__setattr__(new_object, "__fields_set__", set())
394392

395393
def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]:
396394
return resolve_annotations( # type: ignore[no-any-return]

sqlmodel/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@
7070
get_model_fields,
7171
get_relationship_to,
7272
get_type_from_field,
73+
init_pydantic_private_attrs,
7374
is_field_noneable,
7475
is_table_model_class,
7576
post_init_field_info,
7677
set_config_value,
77-
set_fields_set,
7878
sqlmodel_init,
7979
sqlmodel_validate,
8080
)
@@ -686,12 +686,12 @@ class Config:
686686

687687
def __new__(cls, *args: Any, **kwargs: Any) -> Any:
688688
new_object = super().__new__(cls)
689-
# SQLAlchemy doesn't call __init__ on the base class
689+
# SQLAlchemy doesn't call __init__ on the base class when querying from DB
690690
# Ref: https://docs.sqlalchemy.org/en/14/orm/constructors.html
691691
# Set __fields_set__ here, that would have been set when calling __init__
692692
# in the Pydantic model so that when SQLAlchemy sets attributes that are
693693
# added (e.g. when querying from DB) to the __fields_set__, this already exists
694-
set_fields_set(new_object, set())
694+
init_pydantic_private_attrs(new_object)
695695
return new_object
696696

697697
def __init__(__pydantic_self__, **data: Any) -> None:

0 commit comments

Comments
 (0)