Compare commits

..

16 Commits

Author SHA1 Message Date
Sebastián Ramírez
22ccca21fc 🔖 Release version 0.120.2 2025-10-29 14:44:41 +01:00
github-actions[bot]
d2a703d5cc 📝 Update release notes
[skip ci]
2025-10-29 13:43:35 +00:00
Sebastián Ramírez
35aa12b9bd 🔧 Add sponsor: SerpApi (#14248) 2025-10-29 14:43:11 +01:00
github-actions[bot]
c01b5dd96f 📝 Update release notes
[skip ci]
2025-10-29 13:09:57 +00:00
Sebastián Ramírez
6a657f360d 🐛 Fix separation of schemas with nested models introduced in 0.119.0 (#14246) 2025-10-29 14:09:30 +01:00
github-actions[bot]
7132a69046 📝 Update release notes
[skip ci]
2025-10-28 07:50:28 +00:00
github-actions[bot]
db7feb5a3e 📝 Update release notes
[skip ci]
2025-10-28 07:50:26 +00:00
github-actions[bot]
448ea5ec82 📝 Update release notes
[skip ci]
2025-10-28 07:48:51 +00:00
pre-commit-ci[bot]
b618e0f9d4 ⬆ [pre-commit.ci] pre-commit autoupdate (#14237)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.14.1 → v0.14.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.1...v0.14.2)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-10-28 08:48:46 +01:00
dependabot[bot]
ccf50ca477 ⬆ Bump actions/download-artifact from 5 to 6 (#14236)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-28 08:48:36 +01:00
dependabot[bot]
a0ef245067 ⬆ Bump actions/upload-artifact from 4 to 5 (#14235)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-28 08:48:28 +01:00
Sebastián Ramírez
78c94c3f56 🔖 Release version 0.120.1 2025-10-27 18:51:46 +01:00
github-actions[bot]
4b0301b280 📝 Update release notes
[skip ci]
2025-10-27 17:50:15 +00:00
Motov Yurii
436932aef5 ⬆️ Bump Starlette to <0.50.0 (#14234) 2025-10-27 18:49:54 +01:00
github-actions[bot]
3ea6a4a0b1 📝 Update release notes
[skip ci]
2025-10-27 14:47:51 +00:00
Motov Yurii
96dd32718b 🔧 Add license and license-files to pyproject.toml, remove License from classifiers (#14230) 2025-10-27 15:45:14 +01:00
16 changed files with 273 additions and 27 deletions

View File

@@ -118,7 +118,7 @@ jobs:
path: docs/${{ matrix.lang }}/.cache
- name: Build Docs
run: python ./scripts/docs.py build-lang ${{ matrix.lang }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v5
with:
name: docs-site-${{ matrix.lang }}
path: ./site/**

View File

@@ -49,7 +49,7 @@ jobs:
run: |
rm -rf ./site
mkdir ./site
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v6
with:
path: ./site/
pattern: docs-site-*

View File

@@ -34,7 +34,7 @@ jobs:
requirements**.txt
pyproject.toml
- run: uv pip install -r requirements-github-actions.txt
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v6
with:
name: coverage-html
path: htmlcov

View File

@@ -97,7 +97,7 @@ jobs:
COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }}
CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }}
- name: Store coverage files
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: coverage-${{ matrix.python-version }}-${{ matrix.pydantic-version }}
path: coverage
@@ -126,7 +126,7 @@ jobs:
- name: Install Dependencies
run: uv pip install -r requirements-tests.txt
- name: Get coverage files
uses: actions/download-artifact@v5
uses: actions/download-artifact@v6
with:
pattern: coverage-*
path: coverage
@@ -136,7 +136,7 @@ jobs:
- run: coverage report
- run: coverage html --title "Coverage for ${{ github.sha }}"
- name: Store coverage HTML
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: coverage-html
path: htmlcov

View File

@@ -14,7 +14,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.1
rev: v0.14.2
hooks:
- id: ruff
args:

View File

@@ -55,6 +55,7 @@ The key features are:
<a href="https://www.coderabbit.ai/?utm_source=fastapi&utm_medium=badge&utm_campaign=fastapi" target="_blank" title="Cut Code Review Time & Bugs in Half with CodeRabbit"><img src="https://fastapi.tiangolo.com/img/sponsors/coderabbit.png"></a>
<a href="https://subtotal.com/?utm_source=fastapi&utm_medium=sponsorship&utm_campaign=open-source" target="_blank" title="The Gold Standard in Retail Account Linking"><img src="https://fastapi.tiangolo.com/img/sponsors/subtotal.svg"></a>
<a href="https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi" target="_blank" title="Deploy enterprise applications at startup speed"><img src="https://fastapi.tiangolo.com/img/sponsors/railway.png"></a>
<a href="https://serpapi.com/?utm_source=fastapi_website" target="_blank" title="SerpApi: Web Search API"><img src="https://fastapi.tiangolo.com/img/sponsors/serpapi.png"></a>
<a href="https://databento.com/?utm_source=fastapi&utm_medium=sponsor&utm_content=display" target="_blank" title="Pay as you go for market data"><img src="https://fastapi.tiangolo.com/img/sponsors/databento.svg"></a>
<a href="https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship" target="_blank" title="SDKs for your API | Speakeasy"><img src="https://fastapi.tiangolo.com/img/sponsors/speakeasy.png"></a>
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>

View File

@@ -26,6 +26,9 @@ gold:
- url: https://docs.railway.com/guides/fastapi?utm_medium=integration&utm_source=docs&utm_campaign=fastapi
title: Deploy enterprise applications at startup speed
img: https://fastapi.tiangolo.com/img/sponsors/railway.png
- url: https://serpapi.com/?utm_source=fastapi_website
title: "SerpApi: Web Search API"
img: https://fastapi.tiangolo.com/img/sponsors/serpapi.png
silver:
- url: https://databento.com/?utm_source=fastapi&utm_medium=sponsor&utm_content=display
title: Pay as you go for market data

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -7,6 +7,29 @@ hide:
## Latest Changes
## 0.120.2
### Fixes
* 🐛 Fix separation of schemas with nested models introduced in 0.119.0. PR [#14246](https://github.com/fastapi/fastapi/pull/14246) by [@tiangolo](https://github.com/tiangolo).
### Internal
* 🔧 Add sponsor: SerpApi. PR [#14248](https://github.com/fastapi/fastapi/pull/14248) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Bump actions/download-artifact from 5 to 6. PR [#14236](https://github.com/fastapi/fastapi/pull/14236) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#14237](https://github.com/fastapi/fastapi/pull/14237) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
* ⬆ Bump actions/upload-artifact from 4 to 5. PR [#14235](https://github.com/fastapi/fastapi/pull/14235) by [@dependabot[bot]](https://github.com/apps/dependabot).
## 0.120.1
### Upgrades
* ⬆️ Bump Starlette to <`0.50.0`. PR [#14234](https://github.com/fastapi/fastapi/pull/14234) by [@YuriiMotov](https://github.com/YuriiMotov).
### Internal
* 🔧 Add `license` and `license-files` to `pyproject.toml`, remove `License` from `classifiers`. PR [#14230](https://github.com/fastapi/fastapi/pull/14230) by [@YuriiMotov](https://github.com/YuriiMotov).
## 0.120.0
There are no major nor breaking changes in this release. ☕️

View File

@@ -80,6 +80,12 @@
<img class="sponsor-image" src="/img/sponsors/railway-banner.png" />
</a>
</div>
<div class="item">
<a title="SerpApi: Web Search API" style="display: block; position: relative;" href="https://serpapi.com/?utm_source=fastapi_website" target="_blank">
<span class="sponsor-badge">sponsor</span>
<img class="sponsor-image" src="/img/sponsors/serpapi-banner.png" />
</a>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.120.0"
__version__ = "0.120.2"
from starlette import status as status

View File

@@ -207,11 +207,31 @@ def get_definitions(
override_mode: Union[Literal["validation"], None] = (
None if separate_input_output_schemas else "validation"
)
flat_models = get_flat_models_from_fields(fields, known_models=set())
flat_model_fields = [
ModelField(field_info=FieldInfo(annotation=model), name=model.__name__)
for model in flat_models
validation_fields = [field for field in fields if field.mode == "validation"]
serialization_fields = [field for field in fields if field.mode == "serialization"]
flat_validation_models = get_flat_models_from_fields(
validation_fields, known_models=set()
)
flat_serialization_models = get_flat_models_from_fields(
serialization_fields, known_models=set()
)
flat_validation_model_fields = [
ModelField(
field_info=FieldInfo(annotation=model),
name=model.__name__,
mode="validation",
)
for model in flat_validation_models
]
flat_serialization_model_fields = [
ModelField(
field_info=FieldInfo(annotation=model),
name=model.__name__,
mode="serialization",
)
for model in flat_serialization_models
]
flat_model_fields = flat_validation_model_fields + flat_serialization_model_fields
input_types = {f.type_ for f in fields}
unique_flat_model_fields = {
f for f in flat_model_fields if f.type_ not in input_types

View File

@@ -7,6 +7,8 @@ name = "fastapi"
dynamic = ["version"]
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
readme = "README.md"
license = "MIT"
license-files = ["LICENSE"]
requires-python = ">=3.8"
authors = [
{ name = "Sebastián Ramírez", email = "tiangolo@gmail.com" },
@@ -31,7 +33,6 @@ classifiers = [
"Framework :: Pydantic :: 1",
"Framework :: Pydantic :: 2",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
@@ -44,7 +45,7 @@ classifiers = [
"Topic :: Internet :: WWW/HTTP",
]
dependencies = [
"starlette>=0.40.0,<0.49.0",
"starlette>=0.40.0,<0.50.0",
"pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0",
"typing-extensions>=4.8.0",
"annotated-doc>=0.0.2",

View File

@@ -0,0 +1,203 @@
# Test with parts from, and to verify the report in:
# https://github.com/fastapi/fastapi/discussions/14177
# Made an issue in:
# https://github.com/fastapi/fastapi/issues/14247
from enum import Enum
from typing import List
from fastapi import FastAPI
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
from pydantic import BaseModel, Field
from tests.utils import pydantic_snapshot
class MessageEventType(str, Enum):
alpha = "alpha"
beta = "beta"
class MessageEvent(BaseModel):
event_type: MessageEventType = Field(default=MessageEventType.alpha)
output: str
class MessageOutput(BaseModel):
body: str = ""
events: List[MessageEvent] = []
class Message(BaseModel):
input: str
output: MessageOutput
app = FastAPI(title="Minimal FastAPI App", version="1.0.0")
@app.post("/messages", response_model=Message)
async def create_message(input_message: str) -> Message:
return Message(
input=input_message,
output=MessageOutput(body=f"Processed: {input_message}"),
)
client = TestClient(app)
def test_create_message():
response = client.post("/messages", params={"input_message": "Hello"})
assert response.status_code == 200, response.text
assert response.json() == {
"input": "Hello",
"output": {"body": "Processed: Hello", "events": []},
}
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text
assert response.json() == snapshot(
{
"openapi": "3.1.0",
"info": {"title": "Minimal FastAPI App", "version": "1.0.0"},
"paths": {
"/messages": {
"post": {
"summary": "Create Message",
"operationId": "create_message_messages_post",
"parameters": [
{
"name": "input_message",
"in": "query",
"required": True,
"schema": {"type": "string", "title": "Input Message"},
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Message"
}
}
},
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
},
},
},
}
}
},
"components": {
"schemas": {
"HTTPValidationError": {
"properties": {
"detail": {
"items": {
"$ref": "#/components/schemas/ValidationError"
},
"type": "array",
"title": "Detail",
}
},
"type": "object",
"title": "HTTPValidationError",
},
"Message": {
"properties": {
"input": {"type": "string", "title": "Input"},
"output": {"$ref": "#/components/schemas/MessageOutput"},
},
"type": "object",
"required": ["input", "output"],
"title": "Message",
},
"MessageEvent": {
"properties": {
"event_type": pydantic_snapshot(
v2=snapshot(
{
"$ref": "#/components/schemas/MessageEventType",
"default": "alpha",
}
),
v1=snapshot(
{
"allOf": [
{
"$ref": "#/components/schemas/MessageEventType"
}
],
"default": "alpha",
}
),
),
"output": {"type": "string", "title": "Output"},
},
"type": "object",
"required": ["output"],
"title": "MessageEvent",
},
"MessageEventType": pydantic_snapshot(
v2=snapshot(
{
"type": "string",
"enum": ["alpha", "beta"],
"title": "MessageEventType",
}
),
v1=snapshot(
{
"type": "string",
"enum": ["alpha", "beta"],
"title": "MessageEventType",
"description": "An enumeration.",
}
),
),
"MessageOutput": {
"properties": {
"body": {"type": "string", "title": "Body", "default": ""},
"events": {
"items": {"$ref": "#/components/schemas/MessageEvent"},
"type": "array",
"title": "Events",
"default": [],
},
},
"type": "object",
"title": "MessageOutput",
},
"ValidationError": {
"properties": {
"loc": {
"items": {
"anyOf": [{"type": "string"}, {"type": "integer"}]
},
"type": "array",
"title": "Location",
},
"msg": {"type": "string", "title": "Message"},
"type": {"type": "string", "title": "Error Type"},
},
"type": "object",
"required": ["loc", "msg", "type"],
"title": "ValidationError",
},
}
},
}
)

View File

@@ -1028,17 +1028,6 @@ def test_openapi_schema():
"type": "object",
"title": "HTTPValidationError",
},
"SubItem-Output": {
"properties": {
"new_sub_name": {
"type": "string",
"title": "New Sub Name",
}
},
"type": "object",
"required": ["new_sub_name"],
"title": "SubItem",
},
"ValidationError": {
"properties": {
"loc": {
@@ -1113,11 +1102,11 @@ def test_openapi_schema():
"title": "New Description",
},
"new_sub": {
"$ref": "#/components/schemas/SubItem-Output"
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__SubItem"
},
"new_multi": {
"items": {
"$ref": "#/components/schemas/SubItem-Output"
"$ref": "#/components/schemas/tests__test_pydantic_v1_v2_multifile__modelsv2__SubItem"
},
"type": "array",
"title": "New Multi",