From 8fda4099de789f40725f4f98bfa23ef6862b3d09 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 9 Apr 2025 15:13:22 +0200 Subject: [PATCH 01/11] remove unused ignore statement --- sqlmodel/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 45a41997fe..98c1f17956 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -477,7 +477,7 @@ def Relationship( class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): __sqlmodel_relationships__: Dict[str, RelationshipInfo] model_config: SQLModelConfig - model_fields: Dict[str, FieldInfo] # type: ignore[assignment] + model_fields: Dict[str, FieldInfo] __config__: Type[SQLModelConfig] __fields__: Dict[str, ModelField] # type: ignore[assignment] From 902f3a126687f65b7ff85352f1a4da7024aafaa8 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 9 Apr 2025 15:16:36 +0200 Subject: [PATCH 02/11] fix signature of model_validate --- sqlmodel/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 98c1f17956..8b45a402aa 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -846,8 +846,9 @@ def model_validate( strict: Union[bool, None] = None, from_attributes: Union[bool, None] = None, context: Union[Dict[str, Any], None] = None, - update: Union[Dict[str, Any], None] = None, + **kwargs: Any, ) -> _TSQLModel: + update = kwargs.get("update", None) return sqlmodel_validate( cls=cls, obj=obj, From c8b6decba606eec306e424e6e6a1a0b86b97dcf5 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 9 Apr 2025 15:27:00 +0200 Subject: [PATCH 03/11] add ignore statement --- sqlmodel/_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlmodel/_compat.py b/sqlmodel/_compat.py index d6b98aaca7..1d258b7755 100644 --- a/sqlmodel/_compat.py +++ b/sqlmodel/_compat.py @@ -103,7 +103,7 @@ def set_config_value( model.model_config[parameter] = value # type: ignore[literal-required] def get_model_fields(model: InstanceOrType[BaseModel]) -> Dict[str, "FieldInfo"]: - return model.model_fields + return model.model_fields # type: ignore[arg-type] def get_fields_set( object: InstanceOrType["SQLModel"], From 54dbce5014f783e5fe2f2035dec90975d5c1a934 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 9 Apr 2025 15:30:12 +0200 Subject: [PATCH 04/11] fix signature of model_dump --- sqlmodel/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 8b45a402aa..ebbd72d8af 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -864,19 +864,21 @@ def model_dump( mode: Union[Literal["json", "python"], str] = "python", include: Union[IncEx, None] = None, exclude: Union[IncEx, None] = None, - context: Union[Dict[str, Any], None] = None, - by_alias: bool = False, + context: Union[Any, None] = None, + by_alias: Union[bool, None] = False, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, round_trip: bool = False, warnings: Union[bool, Literal["none", "warn", "error"]] = True, + fallback: Union[Callable[[Any], Any], None] = None, serialize_as_any: bool = False, ) -> Dict[str, Any]: if PYDANTIC_MINOR_VERSION >= (2, 7): extra_kwargs: Dict[str, Any] = { "context": context, "serialize_as_any": serialize_as_any, + "fallback": fallback, } else: extra_kwargs = {} @@ -894,6 +896,7 @@ def model_dump( **extra_kwargs, ) else: + assert by_alias is not None return super().dict( include=include, exclude=exclude, From 07f3269738e2598705c315d03d6072f8e87bdfe7 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 9 Apr 2025 15:36:08 +0200 Subject: [PATCH 05/11] prevent linting check on Python 3.8 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 57dba1c286..b812f3da46 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -67,7 +67,7 @@ jobs: if: matrix.pydantic-version == 'pydantic-v2' run: uv pip install --upgrade "pydantic>=2.0.2,<3.0.0" - name: Lint - if: matrix.pydantic-version == 'pydantic-v2' + if: matrix.pydantic-version == 'pydantic-v2' && matrix.python-version != '3.8' run: bash scripts/lint.sh - run: mkdir coverage - name: Test From b23a45734c209c519bc9e7053156a9a6ab8bd260 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 9 Apr 2025 15:48:47 +0200 Subject: [PATCH 06/11] add fallback arg for Pydantic 2.11 and above --- sqlmodel/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index ebbd72d8af..8ad1371b4b 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -871,15 +871,18 @@ def model_dump( exclude_none: bool = False, round_trip: bool = False, warnings: Union[bool, Literal["none", "warn", "error"]] = True, - fallback: Union[Callable[[Any], Any], None] = None, serialize_as_any: bool = False, + **kwargs: Any, ) -> Dict[str, Any]: + fallback = kwargs.get("fallback", None) if PYDANTIC_MINOR_VERSION >= (2, 7): extra_kwargs: Dict[str, Any] = { "context": context, "serialize_as_any": serialize_as_any, - "fallback": fallback, } + if PYDANTIC_MINOR_VERSION >= (2, 11): + extra_kwargs["fallback"] = fallback + else: extra_kwargs = {} if IS_PYDANTIC_V2: From dbd8551a69f85a667a1a9be9324dd5cca15cb446 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Apr 2025 20:29:44 +0200 Subject: [PATCH 07/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Tweak=20`sqlmodel/?= =?UTF-8?q?=5Fcompat.py`=20for=20compatibility=20with=20Pydantic=20v3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlmodel/_compat.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sqlmodel/_compat.py b/sqlmodel/_compat.py index 1d258b7755..38dd501c4a 100644 --- a/sqlmodel/_compat.py +++ b/sqlmodel/_compat.py @@ -103,7 +103,14 @@ def set_config_value( model.model_config[parameter] = value # type: ignore[literal-required] def get_model_fields(model: InstanceOrType[BaseModel]) -> Dict[str, "FieldInfo"]: - return model.model_fields # type: ignore[arg-type] + # TODO: refactor the usage of this function to always pass the class + # not the instance, and then remove this extra check + # this is for compatibility with Pydantic v3 + if isinstance(model, type): + use_model = model + else: + use_model = model.__class__ + return use_model.model_fields def get_fields_set( object: InstanceOrType["SQLModel"], From 2e8be826b4c76d5733ee46aa25c83c0a4af3c439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Apr 2025 20:30:20 +0200 Subject: [PATCH 08/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Update=20model=5Ffie?= =?UTF-8?q?lds,=20type=20them=20with=20compatibility=20for=20Pydantic=20v3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlmodel/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 8ad1371b4b..d8b175a97c 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -477,7 +477,7 @@ def Relationship( class SQLModelMetaclass(ModelMetaclass, DeclarativeMeta): __sqlmodel_relationships__: Dict[str, RelationshipInfo] model_config: SQLModelConfig - model_fields: Dict[str, FieldInfo] + model_fields: ClassVar[Dict[str, FieldInfo]] __config__: Type[SQLModelConfig] __fields__: Dict[str, ModelField] # type: ignore[assignment] From 6147c7dbb6e17c112b7a7953813166980a3dc955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Apr 2025 20:31:08 +0200 Subject: [PATCH 09/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Tweak=20method=20sig?= =?UTF-8?q?natures=20optimizing=20for=20autocompletion=20and=20editor=20su?= =?UTF-8?q?pport=20for=20users?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlmodel/main.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index d8b175a97c..6f1f9c4839 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -839,16 +839,15 @@ def __tablename__(cls) -> str: return cls.__name__.lower() @classmethod - def model_validate( + def model_validate( # type: ignore[override] cls: Type[_TSQLModel], obj: Any, *, strict: Union[bool, None] = None, from_attributes: Union[bool, None] = None, context: Union[Dict[str, Any], None] = None, - **kwargs: Any, + update: Union[Dict[str, Any], None] = None, ) -> _TSQLModel: - update = kwargs.get("update", None) return sqlmodel_validate( cls=cls, obj=obj, @@ -865,16 +864,15 @@ def model_dump( include: Union[IncEx, None] = None, exclude: Union[IncEx, None] = None, context: Union[Any, None] = None, - by_alias: Union[bool, None] = False, + by_alias: Union[bool, None] = None, exclude_unset: bool = False, exclude_defaults: bool = False, exclude_none: bool = False, round_trip: bool = False, warnings: Union[bool, Literal["none", "warn", "error"]] = True, + fallback: Callable[[Any], Any] | None = None, serialize_as_any: bool = False, - **kwargs: Any, ) -> Dict[str, Any]: - fallback = kwargs.get("fallback", None) if PYDANTIC_MINOR_VERSION >= (2, 7): extra_kwargs: Dict[str, Any] = { "context": context, @@ -899,11 +897,10 @@ def model_dump( **extra_kwargs, ) else: - assert by_alias is not None return super().dict( include=include, exclude=exclude, - by_alias=by_alias, + by_alias=by_alias or False, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, exclude_none=exclude_none, From c8dadd568cf0f00b13d42c25a6d021ba6cecdbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Apr 2025 20:46:06 +0200 Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=9A=A8=20Tweak=20type=20for=20older?= =?UTF-8?q?=20Pythons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlmodel/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index 6f1f9c4839..e0b8dfceb4 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -870,7 +870,7 @@ def model_dump( exclude_none: bool = False, round_trip: bool = False, warnings: Union[bool, Literal["none", "warn", "error"]] = True, - fallback: Callable[[Any], Any] | None = None, + fallback: Union[Callable[[Any], Any], None] = None, serialize_as_any: bool = False, ) -> Dict[str, Any]: if PYDANTIC_MINOR_VERSION >= (2, 7): From 16bef835b1d4bfedff22b1494a40890ef8b9cfe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Apr 2025 20:56:57 +0200 Subject: [PATCH 11/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Tweak=20by=5Falias?= =?UTF-8?q?=20for=20Pydantic=20<=202.11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlmodel/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sqlmodel/main.py b/sqlmodel/main.py index e0b8dfceb4..38c85915aa 100644 --- a/sqlmodel/main.py +++ b/sqlmodel/main.py @@ -873,6 +873,8 @@ def model_dump( fallback: Union[Callable[[Any], Any], None] = None, serialize_as_any: bool = False, ) -> Dict[str, Any]: + if PYDANTIC_MINOR_VERSION < (2, 11): + by_alias = by_alias or False if PYDANTIC_MINOR_VERSION >= (2, 7): extra_kwargs: Dict[str, Any] = { "context": context, @@ -880,7 +882,6 @@ def model_dump( } if PYDANTIC_MINOR_VERSION >= (2, 11): extra_kwargs["fallback"] = fallback - else: extra_kwargs = {} if IS_PYDANTIC_V2: