From c5a6734a3ed44ea63e01dc183543d4015066d92c Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 26 Sep 2025 14:38:05 +0200 Subject: [PATCH 01/11] add 3.14 classifier --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 4ae195ac73..bc596764ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Database", "Topic :: Database :: Database Engines/Servers", "Topic :: Internet", From 78d5880bfe599ad8ad47f1735cc3c77599b21636 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 26 Sep 2025 14:38:29 +0200 Subject: [PATCH 02/11] run test suite on Python 3.14 as well --- .github/workflows/test.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4fdb911a8..ea2e3a2189 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,9 +26,8 @@ jobs: strategy: matrix: os: [ ubuntu-latest, windows-latest, macos-latest ] - python-version: [ "3.13" ] + python-version: [ "3.14" ] pydantic-version: - - pydantic-v1 - pydantic-v2 include: - os: macos-latest @@ -43,11 +42,14 @@ jobs: - os: macos-latest python-version: "3.11" pydantic-version: pydantic-v2 - - os: windows-latest + - os: macos-latest python-version: "3.12" pydantic-version: pydantic-v1 + - os: windows-latest + python-version: "3.13" + pydantic-version: pydantic-v1 - os: ubuntu-latest - python-version: "3.12" + python-version: "3.13" pydantic-version: pydantic-v2 fail-fast: false runs-on: ${{ matrix.os }} From 342e68369b5b5758cdf800588fdf65358a1c162c Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 26 Sep 2025 14:40:55 +0200 Subject: [PATCH 03/11] fix os definitions --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ea2e3a2189..fb01245f45 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,13 +42,13 @@ jobs: - os: macos-latest python-version: "3.11" pydantic-version: pydantic-v2 - - os: macos-latest + - os: windows-latest python-version: "3.12" pydantic-version: pydantic-v1 - - os: windows-latest + - os: ubuntu-latest python-version: "3.13" pydantic-version: pydantic-v1 - - os: ubuntu-latest + - os: macos-latest python-version: "3.13" pydantic-version: pydantic-v2 fail-fast: false From b5f9d972db2f4b7661206a8d33827ca09ec10469 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 26 Sep 2025 14:44:25 +0200 Subject: [PATCH 04/11] allow Python prereleases (for now) --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fb01245f45..1926a9be46 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,6 +59,7 @@ jobs: uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} + allow-prereleases: true - name: Setup uv uses: astral-sh/setup-uv@v6 with: From 9514cbaa70733941c137884596c3339f26aa1c2f Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 26 Sep 2025 14:47:18 +0200 Subject: [PATCH 05/11] preinstall pydantic 2.12.0a1 to run the tests --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1926a9be46..b6fd752b2f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -74,6 +74,9 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} with: limit-access-to-actor: true + - name: Preinstall Pydantic 2.12.0a1 for Python 3.14 + if: matrix.python-version == '3.14' + run: uv pip install --pre "pydantic==2.12.0a1" - name: Install Dependencies run: uv pip install -r requirements-tests.txt - name: Install Pydantic v1 From bdcaafe0ac57ca6c29a738fde87a683d5d3732e0 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 26 Sep 2025 14:48:01 +0200 Subject: [PATCH 06/11] don't upgrade pydantic for python 3.14 --- .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 b6fd752b2f..5d0c3aafa5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,7 +83,7 @@ jobs: if: matrix.pydantic-version == 'pydantic-v1' run: uv pip install --upgrade "pydantic>=1.10.0,<2.0.0" - name: Install Pydantic v2 - if: matrix.pydantic-version == 'pydantic-v2' + if: matrix.pydantic-version == 'pydantic-v2' && matrix.python-version != '3.14' run: uv pip install --upgrade "pydantic>=2.0.2,<3.0.0" - name: Lint if: matrix.pydantic-version == 'pydantic-v2' && matrix.python-version != '3.8' From 96249a4b715ce3fb1b299e9558f118c3529aa5c6 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Fri, 26 Sep 2025 14:51:34 +0200 Subject: [PATCH 07/11] fix indent --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5d0c3aafa5..8dbae9ef23 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -75,8 +75,8 @@ jobs: with: limit-access-to-actor: true - name: Preinstall Pydantic 2.12.0a1 for Python 3.14 - if: matrix.python-version == '3.14' - run: uv pip install --pre "pydantic==2.12.0a1" + if: matrix.python-version == '3.14' + run: uv pip install --pre "pydantic==2.12.0a1" - name: Install Dependencies run: uv pip install -r requirements-tests.txt - name: Install Pydantic v1 From 388b11ab64bed49306304116fd325663e9f26cc7 Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 8 Oct 2025 11:43:39 +0200 Subject: [PATCH 08/11] cleanup now that Python 3.14 and Pydantic 2.12.0 are released --- .github/workflows/test.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8dbae9ef23..fb01245f45 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -59,7 +59,6 @@ jobs: uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - allow-prereleases: true - name: Setup uv uses: astral-sh/setup-uv@v6 with: @@ -74,16 +73,13 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.debug_enabled == 'true' }} with: limit-access-to-actor: true - - name: Preinstall Pydantic 2.12.0a1 for Python 3.14 - if: matrix.python-version == '3.14' - run: uv pip install --pre "pydantic==2.12.0a1" - name: Install Dependencies run: uv pip install -r requirements-tests.txt - name: Install Pydantic v1 if: matrix.pydantic-version == 'pydantic-v1' run: uv pip install --upgrade "pydantic>=1.10.0,<2.0.0" - name: Install Pydantic v2 - if: matrix.pydantic-version == 'pydantic-v2' && matrix.python-version != '3.14' + 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' && matrix.python-version != '3.8' From 881a45289ba9a6a50322b38fcf6e5a049f0d0efd Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 8 Oct 2025 15:34:30 +0200 Subject: [PATCH 09/11] fetch raw_annotations as in Pydantic PR 11991 --- sqlmodel/_compat.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sqlmodel/_compat.py b/sqlmodel/_compat.py index dc806d381b..489e915b8f 100644 --- a/sqlmodel/_compat.py +++ b/sqlmodel/_compat.py @@ -1,3 +1,4 @@ +import sys import types from contextlib import contextmanager from contextvars import ContextVar @@ -123,7 +124,14 @@ def init_pydantic_private_attrs(new_object: InstanceOrType["SQLModel"]) -> None: object.__setattr__(new_object, "__pydantic_private__", None) def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]: - return class_dict.get("__annotations__", {}) # type: ignore[no-any-return] + raw_annotations: dict[str, Any] = class_dict.get("__annotations__", {}) + if sys.version_info >= (3, 14) and "__annotations__" not in class_dict: + # See https://github.com/pydantic/pydantic/pull/11991 + from annotationlib import Format, call_annotate_function, get_annotate_from_class_namespace + + if annotate := get_annotate_from_class_namespace(class_dict): + raw_annotations = call_annotate_function(annotate, format=Format.FORWARDREF) + return raw_annotations def is_table_model_class(cls: Type[Any]) -> bool: config = getattr(cls, "model_config", {}) From 7ddcab1968856b63c0369ba8eb7df67eac5f519a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 13:34:39 +0000 Subject: [PATCH 10/11] =?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/_compat.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sqlmodel/_compat.py b/sqlmodel/_compat.py index 489e915b8f..39dde7318e 100644 --- a/sqlmodel/_compat.py +++ b/sqlmodel/_compat.py @@ -127,10 +127,16 @@ def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]: raw_annotations: dict[str, Any] = class_dict.get("__annotations__", {}) if sys.version_info >= (3, 14) and "__annotations__" not in class_dict: # See https://github.com/pydantic/pydantic/pull/11991 - from annotationlib import Format, call_annotate_function, get_annotate_from_class_namespace + from annotationlib import ( + Format, + call_annotate_function, + get_annotate_from_class_namespace, + ) if annotate := get_annotate_from_class_namespace(class_dict): - raw_annotations = call_annotate_function(annotate, format=Format.FORWARDREF) + raw_annotations = call_annotate_function( + annotate, format=Format.FORWARDREF + ) return raw_annotations def is_table_model_class(cls: Type[Any]) -> bool: From 215d02d584889cc6acdb6c7ce593143cd11ab52e Mon Sep 17 00:00:00 2001 From: svlandeg Date: Wed, 8 Oct 2025 16:13:31 +0200 Subject: [PATCH 11/11] typing Dict with capital --- sqlmodel/_compat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sqlmodel/_compat.py b/sqlmodel/_compat.py index 39dde7318e..230f8cc362 100644 --- a/sqlmodel/_compat.py +++ b/sqlmodel/_compat.py @@ -124,7 +124,7 @@ def init_pydantic_private_attrs(new_object: InstanceOrType["SQLModel"]) -> None: object.__setattr__(new_object, "__pydantic_private__", None) def get_annotations(class_dict: Dict[str, Any]) -> Dict[str, Any]: - raw_annotations: dict[str, Any] = class_dict.get("__annotations__", {}) + raw_annotations: Dict[str, Any] = class_dict.get("__annotations__", {}) if sys.version_info >= (3, 14) and "__annotations__" not in class_dict: # See https://github.com/pydantic/pydantic/pull/11991 from annotationlib import (