From a7ad22e7ace1e97ec260c8c24a6d6e14aa137395 Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Thu, 3 Apr 2025 11:24:51 +0800 Subject: [PATCH 01/13] feat: add IntEnum for sqltypes --- sqlmodel/__init__.py | 1 + sqlmodel/sql/sqltypes.py | 56 +++++++++++++++++++++++++++++++++++++- tests/test_enums.py | 12 +++++--- tests/test_enums_models.py | 8 ++++-- 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/sqlmodel/__init__.py b/sqlmodel/__init__.py index 4f68a60a5c..d2229c61fc 100644 --- a/sqlmodel/__init__.py +++ b/sqlmodel/__init__.py @@ -146,3 +146,4 @@ from .sql.expression import within_group as within_group from .sql.sqltypes import AutoString as AutoString from .sql.sqltypes import UTCDateTime as UTCDateTime +from .sql.sqltypes import IntEnum as IntEnum diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index 0decddd51a..d06105d5b4 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -1,5 +1,6 @@ from datetime import datetime, timedelta, timezone -from typing import Any, cast +from enum import IntEnum as _IntEnum +from typing import Any, Optional, cast from sqlalchemy import types from sqlalchemy.engine.interfaces import Dialect @@ -59,3 +60,56 @@ def load_dialect_impl(self, dialect: Dialect) -> "types.TypeEngine[Any]": if impl.length is None and dialect.name == "mysql": return dialect.type_descriptor(types.String(self.mysql_default_length)) return super().load_dialect_impl(dialect) + + +class IntEnum(types.TypeDecorator): # type: ignore + """TypeDecorator for Integer-enum conversion. + + Automatically converts Python enum.IntEnum <-> database integers. + + Args: + enum_type (enum.IntEnum): Integer enum class (subclass of enum.IntEnum) + + Example: + >>> class HeroStatus(enum.IntEnum): + ... ACTIVE = 1 + ... DISABLE = 2 + >>>> + >>> from sqlmodel import IntEnum + >>> class Hero(SQLModel): + ... hero_status: HeroStatus = Field(sa_type=sqlmodel.IntEnum(HeroStatus)) + >>> user.hero_status == Status.ACTIVE # Loads back as enum + + Returns: + Optional[enum.IntEnum]: Converted enum instance (None if database value is NULL) + + Raises: + TypeError: For invalid enum types + """ + + impl = types.Integer + + def __init__(self, enum_type: _IntEnum, *args, **kwargs): + super().__init__(*args, **kwargs) + + # validate the input enum type + if not issubclass(enum_type, _IntEnum): + raise TypeError(f"Input must be enum.IntEnum") + + self.enum_type = enum_type + + def process_result_value(self, value: Optional[int], dialect) -> Optional[_IntEnum]: + + if value is None: + return None + + result = self.enum_type(value) + return result + + def process_bind_param(self, value: Optional[_IntEnum], dialect) -> Optional[int]: + + if value is None: + return None + + result = value.value + return result diff --git a/tests/test_enums.py b/tests/test_enums.py index 933a24e99e..28874d615d 100644 --- a/tests/test_enums.py +++ b/tests/test_enums.py @@ -61,10 +61,12 @@ def test_json_schema_flat_model_pydantic_v2(): "properties": { "id": {"title": "Id", "type": "string", "format": "uuid"}, "enum_field": {"$ref": "#/$defs/MyEnum1"}, + "int_enum_field": {"$ref": "#/$defs/MyEnum3"}, }, - "required": ["id", "enum_field"], + "required": ["id", "enum_field", "int_enum_field"], "$defs": { - "MyEnum1": {"enum": ["A", "B"], "title": "MyEnum1", "type": "string"} + "MyEnum1": {"enum": ["A", "B"], "title": "MyEnum1", "type": "string"}, + "MyEnum3": {"enum": [1, 2], "title": "MyEnum3", "type": "integer"}, }, } @@ -76,9 +78,11 @@ def test_json_schema_inherit_model_pydantic_v2(): "properties": { "id": {"title": "Id", "type": "string", "format": "uuid"}, "enum_field": {"$ref": "#/$defs/MyEnum2"}, + "int_enum_field": {"$ref": "#/$defs/MyEnum3"}, }, - "required": ["id", "enum_field"], + "required": ["id", "enum_field", "int_enum_field"], "$defs": { - "MyEnum2": {"enum": ["C", "D"], "title": "MyEnum2", "type": "string"} + "MyEnum2": {"enum": ["C", "D"], "title": "MyEnum2", "type": "string"}, + "MyEnum3": {"enum": [1, 2], "title": "MyEnum3", "type": "integer"}, }, } diff --git a/tests/test_enums_models.py b/tests/test_enums_models.py index b46ccb7d2b..04635d12c4 100644 --- a/tests/test_enums_models.py +++ b/tests/test_enums_models.py @@ -1,7 +1,7 @@ import enum import uuid -from sqlmodel import Field, SQLModel +from sqlmodel import Field, SQLModel, IntEnum class MyEnum1(str, enum.Enum): @@ -13,15 +13,19 @@ class MyEnum2(str, enum.Enum): C = "C" D = "D" +class MyEnum3(enum.IntEnum): + E = 1 + F = 2 class BaseModel(SQLModel): id: uuid.UUID = Field(primary_key=True) enum_field: MyEnum2 - + int_enum_field: MyEnum3 class FlatModel(SQLModel, table=True): id: uuid.UUID = Field(primary_key=True) enum_field: MyEnum1 + int_enum_field: MyEnum3 = Field(sa_type=IntEnum(MyEnum3)) class InheritModel(BaseModel, table=True): From fa3d5853e747564a59be286e695472891edc8d81 Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Thu, 3 Apr 2025 12:02:47 +0800 Subject: [PATCH 02/13] fix: type lint check --- sqlmodel/sql/sqltypes.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index d06105d5b4..23581d6f08 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -1,6 +1,6 @@ from datetime import datetime, timedelta, timezone from enum import IntEnum as _IntEnum -from typing import Any, Optional, cast +from typing import Any, Optional, TypeVar, cast from sqlalchemy import types from sqlalchemy.engine.interfaces import Dialect @@ -50,7 +50,7 @@ def process_result_value( return value.astimezone(timezone.utc) -class AutoString(types.TypeDecorator): +class AutoString(types.TypeDecorator): # type: ignore impl = types.String cache_ok = True mysql_default_length = 255 @@ -62,6 +62,9 @@ def load_dialect_impl(self, dialect: Dialect) -> "types.TypeEngine[Any]": return super().load_dialect_impl(dialect) +_TIntEnum = TypeVar("_TIntEnum", bound="_IntEnum") + + class IntEnum(types.TypeDecorator): # type: ignore """TypeDecorator for Integer-enum conversion. @@ -89,7 +92,7 @@ class IntEnum(types.TypeDecorator): # type: ignore impl = types.Integer - def __init__(self, enum_type: _IntEnum, *args, **kwargs): + def __init__(self, enum_type: _TIntEnum, *args, **kwargs): super().__init__(*args, **kwargs) # validate the input enum type @@ -98,7 +101,9 @@ def __init__(self, enum_type: _IntEnum, *args, **kwargs): self.enum_type = enum_type - def process_result_value(self, value: Optional[int], dialect) -> Optional[_IntEnum]: + def process_result_value( + self, value: Optional[int], dialect: Dialect + ) -> Optional[_TIntEnum]: if value is None: return None @@ -106,7 +111,9 @@ def process_result_value(self, value: Optional[int], dialect) -> Optional[_IntEn result = self.enum_type(value) return result - def process_bind_param(self, value: Optional[_IntEnum], dialect) -> Optional[int]: + def process_bind_param( + self, value: Optional[_TIntEnum], dialect: Dialect + ) -> Optional[int]: if value is None: return None From b2a2ec448544a4f4da88ba5e7af8989b56838419 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 03:31:33 +0000 Subject: [PATCH 03/13] =?UTF-8?q?=F0=9F=8E=A8=20[pre-commit.ci]=20Auto=20f?= =?UTF-8?q?ormat=20from=20pre-commit.com=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlmodel/sql/sqltypes.py | 2 +- tests/test_enums_models.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index 23581d6f08..1e7b8289f2 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -97,7 +97,7 @@ def __init__(self, enum_type: _TIntEnum, *args, **kwargs): # validate the input enum type if not issubclass(enum_type, _IntEnum): - raise TypeError(f"Input must be enum.IntEnum") + raise TypeError("Input must be enum.IntEnum") self.enum_type = enum_type diff --git a/tests/test_enums_models.py b/tests/test_enums_models.py index 04635d12c4..c6dac3723a 100644 --- a/tests/test_enums_models.py +++ b/tests/test_enums_models.py @@ -1,7 +1,7 @@ import enum import uuid -from sqlmodel import Field, SQLModel, IntEnum +from sqlmodel import Field, IntEnum, SQLModel class MyEnum1(str, enum.Enum): @@ -13,15 +13,18 @@ class MyEnum2(str, enum.Enum): C = "C" D = "D" + class MyEnum3(enum.IntEnum): E = 1 F = 2 + class BaseModel(SQLModel): id: uuid.UUID = Field(primary_key=True) enum_field: MyEnum2 int_enum_field: MyEnum3 + class FlatModel(SQLModel, table=True): id: uuid.UUID = Field(primary_key=True) enum_field: MyEnum1 From fcf2614e9d876c4560899b161152b5e824bf0e91 Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Thu, 3 Apr 2025 12:50:48 +0800 Subject: [PATCH 04/13] fix: sqltypes lint check --- sqlmodel/sql/sqltypes.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index 1e7b8289f2..e00daabd3b 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -1,6 +1,6 @@ from datetime import datetime, timedelta, timezone from enum import IntEnum as _IntEnum -from typing import Any, Optional, TypeVar, cast +from typing import Any, Optional, TypeVar, Type, cast, Any from sqlalchemy import types from sqlalchemy.engine.interfaces import Dialect @@ -92,7 +92,7 @@ class IntEnum(types.TypeDecorator): # type: ignore impl = types.Integer - def __init__(self, enum_type: _TIntEnum, *args, **kwargs): + def __init__(self, enum_type: Type[_TIntEnum], *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) # validate the input enum type @@ -101,8 +101,10 @@ def __init__(self, enum_type: _TIntEnum, *args, **kwargs): self.enum_type = enum_type - def process_result_value( - self, value: Optional[int], dialect: Dialect + def process_result_value( # type: ignore[override] + self, + value: Optional[int], + dialect: Dialect, ) -> Optional[_TIntEnum]: if value is None: @@ -112,7 +114,9 @@ def process_result_value( return result def process_bind_param( - self, value: Optional[_TIntEnum], dialect: Dialect + self, + value: Optional[_TIntEnum], + dialect: Dialect, ) -> Optional[int]: if value is None: From 9775560852c153a1794590f4aab12e7ffe47de6a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 04:53:07 +0000 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=8E=A8=20[pre-commit.ci]=20Auto=20f?= =?UTF-8?q?ormat=20from=20pre-commit.com=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlmodel/sql/sqltypes.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index e00daabd3b..16a188bcfe 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -1,6 +1,6 @@ from datetime import datetime, timedelta, timezone from enum import IntEnum as _IntEnum -from typing import Any, Optional, TypeVar, Type, cast, Any +from typing import Any, Optional, Type, TypeVar, cast from sqlalchemy import types from sqlalchemy.engine.interfaces import Dialect @@ -106,7 +106,6 @@ def process_result_value( # type: ignore[override] value: Optional[int], dialect: Dialect, ) -> Optional[_TIntEnum]: - if value is None: return None @@ -118,7 +117,6 @@ def process_bind_param( value: Optional[_TIntEnum], dialect: Dialect, ) -> Optional[int]: - if value is None: return None From 0a4dd7dc549b32459ba326d401d5bac7345cf6f7 Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Thu, 17 Apr 2025 22:58:24 +0800 Subject: [PATCH 06/13] doc: no class docstring like other s --- sqlmodel/sql/sqltypes.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index 16a188bcfe..c59b02cdfa 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -66,30 +66,6 @@ def load_dialect_impl(self, dialect: Dialect) -> "types.TypeEngine[Any]": class IntEnum(types.TypeDecorator): # type: ignore - """TypeDecorator for Integer-enum conversion. - - Automatically converts Python enum.IntEnum <-> database integers. - - Args: - enum_type (enum.IntEnum): Integer enum class (subclass of enum.IntEnum) - - Example: - >>> class HeroStatus(enum.IntEnum): - ... ACTIVE = 1 - ... DISABLE = 2 - >>>> - >>> from sqlmodel import IntEnum - >>> class Hero(SQLModel): - ... hero_status: HeroStatus = Field(sa_type=sqlmodel.IntEnum(HeroStatus)) - >>> user.hero_status == Status.ACTIVE # Loads back as enum - - Returns: - Optional[enum.IntEnum]: Converted enum instance (None if database value is NULL) - - Raises: - TypeError: For invalid enum types - """ - impl = types.Integer def __init__(self, enum_type: Type[_TIntEnum], *args: Any, **kwargs: Any): From d0cd18eacc950fd7c050768a0ca61b5a9a28ef56 Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Thu, 17 Apr 2025 22:59:01 +0800 Subject: [PATCH 07/13] perfomance: add cache and remove warning --- sqlmodel/sql/sqltypes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index c59b02cdfa..9827852669 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -67,6 +67,7 @@ def load_dialect_impl(self, dialect: Dialect) -> "types.TypeEngine[Any]": class IntEnum(types.TypeDecorator): # type: ignore impl = types.Integer + cache_ok = True def __init__(self, enum_type: Type[_TIntEnum], *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) From 18b8bac190256b22db85ef00549704aeb77c4088 Mon Sep 17 00:00:00 2001 From: sunkunxi Date: Mon, 22 Sep 2025 15:11:42 +0800 Subject: [PATCH 08/13] Apply suggestions from code review Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> --- sqlmodel/sql/sqltypes.py | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index 9827852669..cb1b3c1027 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -1,6 +1,7 @@ +import enum from datetime import datetime, timedelta, timezone from enum import IntEnum as _IntEnum -from typing import Any, Optional, Type, TypeVar, cast +from typing import Any, Optional, TypeVar, cast from sqlalchemy import types from sqlalchemy.engine.interfaces import Dialect @@ -63,39 +64,29 @@ def load_dialect_impl(self, dialect: Dialect) -> "types.TypeEngine[Any]": _TIntEnum = TypeVar("_TIntEnum", bound="_IntEnum") - - -class IntEnum(types.TypeDecorator): # type: ignore +class IntEnum(types.TypeDecorator[Optional[_TIntEnum]]): impl = types.Integer cache_ok = True - def __init__(self, enum_type: Type[_TIntEnum], *args: Any, **kwargs: Any): + def __init__(self, enum_type: type[_TIntEnum], *args: Any, **kwargs: Any): super().__init__(*args, **kwargs) # validate the input enum type - if not issubclass(enum_type, _IntEnum): + if not issubclass(enum_type, enum.IntEnum): raise TypeError("Input must be enum.IntEnum") self.enum_type = enum_type - def process_result_value( # type: ignore[override] + def process_result_value( self, value: Optional[int], dialect: Dialect, ) -> Optional[_TIntEnum]: - if value is None: - return None - - result = self.enum_type(value) - return result + return None if (value is None) else self.enum_type(value) def process_bind_param( self, value: Optional[_TIntEnum], dialect: Dialect, ) -> Optional[int]: - if value is None: - return None - - result = value.value - return result + return None if (value is None) else value.value From ea4083d788a02a24e6c7dd03d6fb1ae58fdb4817 Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Mon, 22 Sep 2025 16:48:06 +0800 Subject: [PATCH 09/13] test: add sa_type to BaseModel.int_enum_field --- tests/test_enums_models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_enums_models.py b/tests/test_enums_models.py index c6dac3723a..5edfb534ea 100644 --- a/tests/test_enums_models.py +++ b/tests/test_enums_models.py @@ -22,7 +22,7 @@ class MyEnum3(enum.IntEnum): class BaseModel(SQLModel): id: uuid.UUID = Field(primary_key=True) enum_field: MyEnum2 - int_enum_field: MyEnum3 + int_enum_field: MyEnum3 = Field(sa_type=IntEnum(MyEnum3)) class FlatModel(SQLModel, table=True): From a9a45fa62bc2534107f2a94924be3182e9e8a01c Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Mon, 22 Sep 2025 16:49:48 +0800 Subject: [PATCH 10/13] update: Uses SmallInteger type for IntEnum Updates the `IntEnum` SQLAlchemy type to `SmallInteger`. This change reduces the storage size required for `IntEnum` columns when the full range of `Integer` is not needed. --- sqlmodel/sql/sqltypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index cb1b3c1027..1efb167d29 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -65,7 +65,7 @@ def load_dialect_impl(self, dialect: Dialect) -> "types.TypeEngine[Any]": _TIntEnum = TypeVar("_TIntEnum", bound="_IntEnum") class IntEnum(types.TypeDecorator[Optional[_TIntEnum]]): - impl = types.Integer + impl = types.SmallInteger cache_ok = True def __init__(self, enum_type: type[_TIntEnum], *args: Any, **kwargs: Any): From 0b86f1801628f16d534eeb4171b99fce0008e490 Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Mon, 22 Sep 2025 16:50:11 +0800 Subject: [PATCH 11/13] test: Adds tests for integer enum fields Adds tests to ensure that integer enum fields are correctly handled in both Postgres and SQLite DDL generation. --- tests/test_enums.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_enums.py b/tests/test_enums.py index 28874d615d..63606a2183 100644 --- a/tests/test_enums.py +++ b/tests/test_enums.py @@ -42,6 +42,7 @@ def test_postgres_ddl_sql(clear_sqlmodel, capsys: pytest.CaptureFixture[str]): captured = capsys.readouterr() assert "CREATE TYPE myenum1 AS ENUM ('A', 'B');" in captured.out assert "CREATE TYPE myenum2 AS ENUM ('C', 'D');" in captured.out + assert "int_enum_field SMALLINT NOT NULL" in captured.out def test_sqlite_ddl_sql(clear_sqlmodel, capsys: pytest.CaptureFixture[str]): @@ -51,6 +52,7 @@ def test_sqlite_ddl_sql(clear_sqlmodel, capsys: pytest.CaptureFixture[str]): captured = capsys.readouterr() assert "enum_field VARCHAR(1) NOT NULL" in captured.out, captured + assert "int_enum_field SMALLINT NOT NULL" in captured.out, captured assert "CREATE TYPE" not in captured.out From 3d8db41339d34ca24d57e346c7322e50e88af00f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 23 Sep 2026 10:14:55 +0000 Subject: [PATCH 12/13] =?UTF-8?q?=F0=9F=8E=A8=20Auto=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sqlmodel/__init__.py | 2 +- sqlmodel/sql/sqltypes.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/sqlmodel/__init__.py b/sqlmodel/__init__.py index d2229c61fc..63f528c9f5 100644 --- a/sqlmodel/__init__.py +++ b/sqlmodel/__init__.py @@ -145,5 +145,5 @@ from .sql.expression import type_coerce as type_coerce from .sql.expression import within_group as within_group from .sql.sqltypes import AutoString as AutoString -from .sql.sqltypes import UTCDateTime as UTCDateTime from .sql.sqltypes import IntEnum as IntEnum +from .sql.sqltypes import UTCDateTime as UTCDateTime diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index 1efb167d29..c7a7338acf 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -64,6 +64,8 @@ def load_dialect_impl(self, dialect: Dialect) -> "types.TypeEngine[Any]": _TIntEnum = TypeVar("_TIntEnum", bound="_IntEnum") + + class IntEnum(types.TypeDecorator[Optional[_TIntEnum]]): impl = types.SmallInteger cache_ok = True @@ -79,14 +81,14 @@ def __init__(self, enum_type: type[_TIntEnum], *args: Any, **kwargs: Any): def process_result_value( self, - value: Optional[int], + value: int | None, dialect: Dialect, - ) -> Optional[_TIntEnum]: + ) -> _TIntEnum | None: return None if (value is None) else self.enum_type(value) def process_bind_param( self, - value: Optional[_TIntEnum], + value: _TIntEnum | None, dialect: Dialect, - ) -> Optional[int]: + ) -> int | None: return None if (value is None) else value.value From a69a29ba68772a783181f04d4e94ee0b1817a96e Mon Sep 17 00:00:00 2001 From: KunxiSun Date: Wed, 23 Sep 2026 19:31:21 +0800 Subject: [PATCH 13/13] style: remove Optional and type ignore --- sqlmodel/sql/sqltypes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py index c7a7338acf..e4710e990b 100644 --- a/sqlmodel/sql/sqltypes.py +++ b/sqlmodel/sql/sqltypes.py @@ -1,7 +1,7 @@ import enum from datetime import datetime, timedelta, timezone from enum import IntEnum as _IntEnum -from typing import Any, Optional, TypeVar, cast +from typing import Any, TypeVar, cast from sqlalchemy import types from sqlalchemy.engine.interfaces import Dialect @@ -51,7 +51,7 @@ def process_result_value( return value.astimezone(timezone.utc) -class AutoString(types.TypeDecorator): # type: ignore +class AutoString(types.TypeDecorator): impl = types.String cache_ok = True mysql_default_length = 255 @@ -66,7 +66,7 @@ def load_dialect_impl(self, dialect: Dialect) -> "types.TypeEngine[Any]": _TIntEnum = TypeVar("_TIntEnum", bound="_IntEnum") -class IntEnum(types.TypeDecorator[Optional[_TIntEnum]]): +class IntEnum(types.TypeDecorator[_TIntEnum | None]): impl = types.SmallInteger cache_ok = True