🐛 Fix class initialization compatibility with Pydantic and SQLModel, fixing errors revealed by the latest Pydantic (#807)
This commit is contained in:
parent
0c7def88b5
commit
1b7b3aa668
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
@ -62,10 +62,10 @@ jobs:
|
|||||||
run: python -m poetry install
|
run: python -m poetry install
|
||||||
- name: Install Pydantic v1
|
- name: Install Pydantic v1
|
||||||
if: matrix.pydantic-version == 'pydantic-v1'
|
if: matrix.pydantic-version == 'pydantic-v1'
|
||||||
run: pip install "pydantic>=1.10.0,<2.0.0"
|
run: pip install --upgrade "pydantic>=1.10.0,<2.0.0"
|
||||||
- name: Install Pydantic v2
|
- name: Install Pydantic v2
|
||||||
if: matrix.pydantic-version == 'pydantic-v2'
|
if: matrix.pydantic-version == 'pydantic-v2'
|
||||||
run: pip install "pydantic>=2.0.2,<3.0.0"
|
run: pip install --upgrade "pydantic>=2.0.2,<3.0.0"
|
||||||
- name: Lint
|
- name: Lint
|
||||||
# Do not run on Python 3.7 as mypy behaves differently
|
# Do not run on Python 3.7 as mypy behaves differently
|
||||||
if: matrix.python-version != '3.7' && matrix.pydantic-version == 'pydantic-v2'
|
if: matrix.python-version != '3.7' && matrix.pydantic-version == 'pydantic-v2'
|
||||||
|
@ -97,10 +97,10 @@ if IS_PYDANTIC_V2:
|
|||||||
def get_model_fields(model: InstanceOrType["SQLModel"]) -> Dict[str, "FieldInfo"]:
|
def get_model_fields(model: InstanceOrType["SQLModel"]) -> Dict[str, "FieldInfo"]:
|
||||||
return model.model_fields
|
return model.model_fields
|
||||||
|
|
||||||
def set_fields_set(
|
def init_pydantic_private_attrs(new_object: InstanceOrType["SQLModel"]) -> None:
|
||||||
new_object: InstanceOrType["SQLModel"], fields: Set["FieldInfo"]
|
object.__setattr__(new_object, "__pydantic_fields_set__", set())
|
||||||
) -> None:
|
object.__setattr__(new_object, "__pydantic_extra__", None)
|
||||||
object.__setattr__(new_object, "__pydantic_fields_set__", fields)
|
object.__setattr__(new_object, "__pydantic_private__", None)
|
||||||
|
|
||||||
def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]:
|
def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
return class_dict.get("__annotations__", {})
|
return class_dict.get("__annotations__", {})
|
||||||
@ -387,10 +387,8 @@ else:
|
|||||||
def get_model_fields(model: InstanceOrType["SQLModel"]) -> Dict[str, "FieldInfo"]:
|
def get_model_fields(model: InstanceOrType["SQLModel"]) -> Dict[str, "FieldInfo"]:
|
||||||
return model.__fields__ # type: ignore
|
return model.__fields__ # type: ignore
|
||||||
|
|
||||||
def set_fields_set(
|
def init_pydantic_private_attrs(new_object: InstanceOrType["SQLModel"]) -> None:
|
||||||
new_object: InstanceOrType["SQLModel"], fields: Set["FieldInfo"]
|
object.__setattr__(new_object, "__fields_set__", set())
|
||||||
) -> None:
|
|
||||||
object.__setattr__(new_object, "__fields_set__", fields)
|
|
||||||
|
|
||||||
def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]:
|
def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
return resolve_annotations( # type: ignore[no-any-return]
|
return resolve_annotations( # type: ignore[no-any-return]
|
||||||
|
@ -70,11 +70,11 @@ from ._compat import ( # type: ignore[attr-defined]
|
|||||||
get_model_fields,
|
get_model_fields,
|
||||||
get_relationship_to,
|
get_relationship_to,
|
||||||
get_type_from_field,
|
get_type_from_field,
|
||||||
|
init_pydantic_private_attrs,
|
||||||
is_field_noneable,
|
is_field_noneable,
|
||||||
is_table_model_class,
|
is_table_model_class,
|
||||||
post_init_field_info,
|
post_init_field_info,
|
||||||
set_config_value,
|
set_config_value,
|
||||||
set_fields_set,
|
|
||||||
sqlmodel_init,
|
sqlmodel_init,
|
||||||
sqlmodel_validate,
|
sqlmodel_validate,
|
||||||
)
|
)
|
||||||
@ -686,12 +686,12 @@ class SQLModel(BaseModel, metaclass=SQLModelMetaclass, registry=default_registry
|
|||||||
|
|
||||||
def __new__(cls, *args: Any, **kwargs: Any) -> Any:
|
def __new__(cls, *args: Any, **kwargs: Any) -> Any:
|
||||||
new_object = super().__new__(cls)
|
new_object = super().__new__(cls)
|
||||||
# SQLAlchemy doesn't call __init__ on the base class
|
# SQLAlchemy doesn't call __init__ on the base class when querying from DB
|
||||||
# Ref: https://docs.sqlalchemy.org/en/14/orm/constructors.html
|
# Ref: https://docs.sqlalchemy.org/en/14/orm/constructors.html
|
||||||
# Set __fields_set__ here, that would have been set when calling __init__
|
# Set __fields_set__ here, that would have been set when calling __init__
|
||||||
# in the Pydantic model so that when SQLAlchemy sets attributes that are
|
# in the Pydantic model so that when SQLAlchemy sets attributes that are
|
||||||
# added (e.g. when querying from DB) to the __fields_set__, this already exists
|
# added (e.g. when querying from DB) to the __fields_set__, this already exists
|
||||||
set_fields_set(new_object, set())
|
init_pydantic_private_attrs(new_object)
|
||||||
return new_object
|
return new_object
|
||||||
|
|
||||||
def __init__(__pydantic_self__, **data: Any) -> None:
|
def __init__(__pydantic_self__, **data: Any) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user