diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d9ab333ad..9c075f68e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.2 + rev: v0.13.3 hooks: - id: ruff args: diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9ca2680cb..7d7c7ec5a 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,12 @@ 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). + ### 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). @@ -21,6 +27,8 @@ 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). * ⬆ Bump markdown-include-variants from 0.0.4 to 0.0.5. PR [#14146](https://github.com/fastapi/fastapi/pull/14146) by [@dependabot[bot]](https://github.com/apps/dependabot). 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 diff --git a/fastapi/_compat.py b/fastapi/_compat.py index 7d18fdeab..21ea1a237 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/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 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*$", + }, + ), ], } )