From c970d8a735f75249ae7badb036bf0560c6c2d186 Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Wed, 8 Oct 2025 09:57:37 +0100 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=91=BD=EF=B8=8F=20Ensure=20compatibil?= =?UTF-8?q?ity=20with=20Pydantic=202.12.0=20(#14036)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sofie Van Landeghem Co-authored-by: Victorien <65306057+Viicos@users.noreply.github.com> Co-authored-by: svlandeg Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Co-authored-by: Patrick Arminio --- fastapi/_compat.py | 18 +++++++++++++++--- fastapi/params.py | 16 ++++++++-------- tests/test_multi_body_errors.py | 10 +++++++++- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/fastapi/_compat.py b/fastapi/_compat.py index 26b6638c8..8ea5bf253 100644 --- a/fastapi/_compat.py +++ b/fastapi/_compat.py @@ -1,3 +1,4 @@ +import warnings from collections import deque from copy import copy from dataclasses import dataclass, is_dataclass @@ -109,9 +110,20 @@ if PYDANTIC_V2: return self.field_info.annotation def __post_init__(self) -> None: - self._type_adapter: TypeAdapter[Any] = TypeAdapter( - Annotated[self.field_info.annotation, self.field_info] - ) + with warnings.catch_warnings(): + # Pydantic >= 2.12.0 warns about field specific metadata that is unused + # (e.g. `TypeAdapter(Annotated[int, Field(alias='b')])`). In some cases, we + # end up building the type adapter from a model field annotation so we + # need to ignore the warning: + if PYDANTIC_VERSION_MINOR_TUPLE >= (2, 12): + from pydantic.warnings import UnsupportedFieldAttributeWarning + + warnings.simplefilter( + "ignore", category=UnsupportedFieldAttributeWarning + ) + self._type_adapter: TypeAdapter[Any] = TypeAdapter( + Annotated[self.field_info.annotation, self.field_info] + ) def get_default(self) -> Any: if self.field_info.is_required(): diff --git a/fastapi/params.py b/fastapi/params.py index 8f5601dd3..e85375018 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -22,7 +22,7 @@ class ParamTypes(Enum): cookie = "cookie" -class Param(FieldInfo): +class Param(FieldInfo): # type: ignore[misc] in_: ParamTypes def __init__( @@ -136,7 +136,7 @@ class Param(FieldInfo): return f"{self.__class__.__name__}({self.default})" -class Path(Param): +class Path(Param): # type: ignore[misc] in_ = ParamTypes.path def __init__( @@ -222,7 +222,7 @@ class Path(Param): ) -class Query(Param): +class Query(Param): # type: ignore[misc] in_ = ParamTypes.query def __init__( @@ -306,7 +306,7 @@ class Query(Param): ) -class Header(Param): +class Header(Param): # type: ignore[misc] in_ = ParamTypes.header def __init__( @@ -392,7 +392,7 @@ class Header(Param): ) -class Cookie(Param): +class Cookie(Param): # type: ignore[misc] in_ = ParamTypes.cookie def __init__( @@ -476,7 +476,7 @@ class Cookie(Param): ) -class Body(FieldInfo): +class Body(FieldInfo): # type: ignore[misc] def __init__( self, default: Any = Undefined, @@ -593,7 +593,7 @@ class Body(FieldInfo): return f"{self.__class__.__name__}({self.default})" -class Form(Body): +class Form(Body): # type: ignore[misc] def __init__( self, default: Any = Undefined, @@ -677,7 +677,7 @@ class Form(Body): ) -class File(Form): +class File(Form): # type: ignore[misc] def __init__( self, default: Any = Undefined, diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py index 0102f0f1a..33304827a 100644 --- a/tests/test_multi_body_errors.py +++ b/tests/test_multi_body_errors.py @@ -185,7 +185,15 @@ def test_openapi_schema(): "title": "Age", "anyOf": [ {"exclusiveMinimum": 0.0, "type": "number"}, - {"type": "string"}, + IsOneOf( + # pydantic < 2.12.0 + {"type": "string"}, + # pydantic >= 2.12.0 + { + "type": "string", + "pattern": r"^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$", + }, + ), ], } ) From 32b93b53fc76e21b19c0d17d4b77c3b19380b440 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 8 Oct 2025 08:58:49 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b6e3aeef9..1b3106dae 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,10 @@ hide: ## Latest Changes +### Upgrades + +* 👽️ Ensure compatibility with Pydantic 2.12.0. PR [#14036](https://github.com/fastapi/fastapi/pull/14036) by [@cjwatson](https://github.com/cjwatson). + ### Docs * 📝 Add External Link: Getting started with logging in FastAPI. PR [#14152](https://github.com/fastapi/fastapi/pull/14152) by [@itssimon](https://github.com/itssimon). From 485bfedf5d5d4a51c53b12010d685854174da92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 8 Oct 2025 18:03:21 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=94=A8=20Move=20local=20coverage=20lo?= =?UTF-8?q?gic=20to=20its=20own=20script=20(#14166)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/coverage.sh | 8 ++++++++ scripts/test-cov-html.sh | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100755 scripts/coverage.sh diff --git a/scripts/coverage.sh b/scripts/coverage.sh new file mode 100755 index 000000000..e07b51ec5 --- /dev/null +++ b/scripts/coverage.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e +set -x + +coverage combine +coverage report +coverage html diff --git a/scripts/test-cov-html.sh b/scripts/test-cov-html.sh index 517ac6422..f87f906dc 100755 --- a/scripts/test-cov-html.sh +++ b/scripts/test-cov-html.sh @@ -4,6 +4,4 @@ set -e set -x bash scripts/test.sh ${@} -coverage combine -coverage report -coverage html +bash scripts/coverage.sh From fca8564ea0767bebe6082622fc57df23686030b7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 8 Oct 2025 09:03:50 +0000 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1b3106dae..f00f63a67 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -25,6 +25,7 @@ hide: ### Internal +* 🔨 Move local coverage logic to its own script. PR [#14166](https://github.com/fastapi/fastapi/pull/14166) by [@tiangolo](https://github.com/tiangolo). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#14161](https://github.com/fastapi/fastapi/pull/14161) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * ⬆ Bump griffe-typingdoc from 0.2.8 to 0.2.9. PR [#14144](https://github.com/fastapi/fastapi/pull/14144) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump mkdocs-macros-plugin from 1.3.9 to 1.4.0. PR [#14145](https://github.com/fastapi/fastapi/pull/14145) by [@dependabot[bot]](https://github.com/apps/dependabot). From 01be148429241adb7a9ba5eb8f6cd5e17230b646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Wed, 8 Oct 2025 11:05:44 +0200 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.118.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 2 ++ fastapi/__init__.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index f00f63a67..7d7c7ec5a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,8 @@ hide: ## Latest Changes +## 0.118.1 + ### Upgrades * 👽️ Ensure compatibility with Pydantic 2.12.0. PR [#14036](https://github.com/fastapi/fastapi/pull/14036) by [@cjwatson](https://github.com/cjwatson). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 03a5aaad5..12ebbaf9b 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.118.0" +__version__ = "0.118.1" from starlette import status as status