From 45215fcecad3ce2ed0aac40c44818d256e5b19ec Mon Sep 17 00:00:00 2001 From: Sofie Van Landeghem Date: Wed, 8 Oct 2025 18:26:33 +0200 Subject: [PATCH] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Add=20support=20for=20Pyth?= =?UTF-8?q?on=203.14=20(#1578)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 8 +++++--- pyproject.toml | 1 + sqlmodel/_compat.py | 16 +++++++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4fdb911..fb01245f 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 @@ -47,7 +46,10 @@ jobs: python-version: "3.12" pydantic-version: pydantic-v1 - os: ubuntu-latest - python-version: "3.12" + python-version: "3.13" + pydantic-version: pydantic-v1 + - os: macos-latest + python-version: "3.13" pydantic-version: pydantic-v2 fail-fast: false runs-on: ${{ matrix.os }} diff --git a/pyproject.toml b/pyproject.toml index 902fffdc..cd47f5ec 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", diff --git a/sqlmodel/_compat.py b/sqlmodel/_compat.py index dc806d38..230f8cc3 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,20 @@ if IS_PYDANTIC_V2: 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", {})