Compare commits

..

52 Commits

Author SHA1 Message Date
Sebastián Ramírez
4efae81a76 🔖 Release version 0.121.0 2025-11-03 11:21:36 +01:00
Sebastián Ramírez
3690140555 📝 Update release notes 2025-11-03 11:19:56 +01:00
github-actions[bot]
ad4d8f24ca 📝 Update release notes
[skip ci]
2025-11-03 10:13:13 +00:00
Sebastián Ramírez
ac438b9934 Add support for dependencies with scopes, support scope="request" for dependencies with yield that exit before the response is sent (#14262)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-11-03 11:12:49 +01:00
github-actions[bot]
425a4c5bb1 📝 Update release notes
[skip ci]
2025-11-03 09:25:02 +00:00
github-actions[bot]
3a223b9073 📝 Update release notes
[skip ci]
2025-11-03 09:24:57 +00:00
Sebastián Ramírez
566e0d60b2 👥 Update FastAPI People - Contributors and Translators (#14273)
Co-authored-by: github-actions <github-actions@github.com>
2025-11-03 10:24:36 +01:00
github-actions[bot]
940ee0c9c3 📝 Update release notes
[skip ci]
2025-11-03 09:24:17 +00:00
Sebastián Ramírez
f8df43d734 👥 Update FastAPI People - Sponsors (#14274)
Co-authored-by: github-actions <github-actions@github.com>
2025-11-03 10:24:09 +01:00
Sebastián Ramírez
dbb7020a4d 👥 Update FastAPI GitHub topic repositories (#14280)
Co-authored-by: github-actions <github-actions@github.com>
2025-11-03 10:23:52 +01:00
github-actions[bot]
32da8ca78b 📝 Update release notes
[skip ci]
2025-11-02 17:15:57 +00:00
dependabot[bot]
8c42d0ce16 ⬆ Bump mkdocs-macros-plugin from 1.4.0 to 1.4.1 (#14277)
Bumps [mkdocs-macros-plugin](https://github.com/fralau/mkdocs_macros_plugin) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/fralau/mkdocs_macros_plugin/releases)
- [Changelog](https://github.com/fralau/mkdocs-macros-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/fralau/mkdocs_macros_plugin/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: mkdocs-macros-plugin
  dependency-version: 1.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-02 18:15:19 +01:00
github-actions[bot]
2a25f6d3a3 📝 Update release notes
[skip ci]
2025-11-02 17:15:00 +00:00
dependabot[bot]
8be5867de7 ⬆ Bump mkdocstrings[python] from 0.26.1 to 0.30.1 (#14279)
Bumps [mkdocstrings[python]](https://github.com/mkdocstrings/mkdocstrings) from 0.26.1 to 0.30.1.
- [Release notes](https://github.com/mkdocstrings/mkdocstrings/releases)
- [Changelog](https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mkdocstrings/mkdocstrings/compare/0.26.1...0.30.1)

---
updated-dependencies:
- dependency-name: mkdocstrings[python]
  dependency-version: 0.30.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-02 18:14:31 +01:00
Sebastián Ramírez
fad35ef43f 🔖 Release version 0.120.4 2025-10-31 19:35:33 +01:00
github-actions[bot]
4d57c13055 📝 Update release notes
[skip ci]
2025-10-31 18:35:03 +00:00
Motov Yurii
496de1816a 🐛 Fix security schemes in OpenAPI when added at the top level app (#14266)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
2025-10-31 19:34:30 +01:00
Sebastián Ramírez
2cf04ee30d 🔖 Release version 0.120.3 2025-10-30 21:40:08 +01:00
github-actions[bot]
ec00f5a90f 📝 Update release notes
[skip ci]
2025-10-30 19:51:03 +00:00
Motov Yurii
8b46d8821b 📝 Update note for untranslated pages (#14257)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-10-30 20:50:37 +01:00
github-actions[bot]
17fcbbe910 📝 Update release notes
[skip ci]
2025-10-30 19:35:31 +00:00
Sebastián Ramírez
dcfb8b9dda ♻️ Reduce internal cyclic recursion in dependencies, from 2 functions calling each other to 1 calling itself (#14256) 2025-10-30 20:35:04 +01:00
github-actions[bot]
1fc586c3a5 📝 Update release notes
[skip ci]
2025-10-30 04:59:14 +00:00
Sebastián Ramírez
bb88a0f94a ♻️ Refactor internals of dependencies, simplify code and remove get_param_sub_dependant (#14255) 2025-10-30 05:58:49 +01:00
github-actions[bot]
9d1a384f4f 📝 Update release notes
[skip ci]
2025-10-30 04:52:12 +00:00
Sebastián Ramírez
c144f9fbd3 ♻️ Refactor internals of dependencies, simplify using dataclasses (#14254) 2025-10-30 05:51:50 +01:00
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
Sebastián Ramírez
cd40c5b40f 🔖 Release version 0.120.0 2025-10-23 22:54:45 +02:00
Sebastián Ramírez
1c6ee57bbf 📝 Update release notes 2025-10-23 22:54:19 +02:00
github-actions[bot]
09f40968cb 📝 Update release notes
[skip ci]
2025-10-23 20:32:06 +00:00
Sebastián Ramírez
d390f2e41f Migrate internal reference documentation from typing_extensions.Doc to annotated_doc.Doc (#14222) 2025-10-23 22:31:35 +02:00
github-actions[bot]
cb7018d782 📝 Update release notes
[skip ci]
2025-10-21 20:32:57 +00:00
Nils-Hero Lindemann
a578ea1fd3 🛠️ Update German LLM prompt and test file (#14189)
Minor fixes in German LLM prompt and test file

Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com>
2025-10-21 22:32:28 +02:00
github-actions[bot]
9c912d1dd6 📝 Update release notes
[skip ci]
2025-10-21 07:53:59 +00:00
pre-commit-ci[bot]
da011f212a ⬆ [pre-commit.ci] pre-commit autoupdate (#14181)
updates:
- [github.com/astral-sh/ruff-pre-commit: v0.13.3 → v0.14.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.13.3...v0.14.1)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2025-10-21 09:53:27 +02:00
github-actions[bot]
046d49b5a9 📝 Update release notes
[skip ci]
2025-10-20 14:00:33 +00:00
Nils-Hero Lindemann
847280450a 🌐 Sync German docs (#14188)
Sync German docs with #14168

Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com>
2025-10-20 16:00:08 +02:00
58 changed files with 1661 additions and 570 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

@@ -48,7 +48,6 @@ jobs:
strategy:
matrix:
python-version:
- "3.14t"
- "3.14"
- "3.13"
- "3.12"
@@ -60,8 +59,6 @@ jobs:
exclude:
- python-version: "3.14"
pydantic-version: "pydantic-v1"
- python-version: "3.14t"
pydantic-version: "pydantic-v1"
fail-fast: false
steps:
- name: Dump GitHub context
@@ -93,10 +90,6 @@ jobs:
- name: Install older AnyIO in Python 3.8
if: matrix.python-version == '3.8'
run: uv pip install "anyio[trio]<4.0.0"
# - name: Set PYTHON_GIL
# if: endsWith(matrix.python-version, 't')
# run: |
# echo "PYTHON_GIL=0" >> "$GITHUB_ENV"
- run: mkdir coverage
- name: Test
run: bash scripts/test.sh
@@ -104,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
@@ -133,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
@@ -143,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.13.3
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

@@ -47,7 +47,7 @@ Das LLM wird dies wahrscheinlich falsch übersetzen. Interessant ist nur, ob es
//// tab | Info
Der Prompt-Designer kann entscheiden, ob neutrale Anführungszeichen in typografische Anführungszeichen umgewandelt werden sollen. Es ist in Ordnung, sie unverändert zu lassen.
Der Promptdesigner kann entscheiden, ob neutrale Anführungszeichen in typografische Anführungszeichen umgewandelt werden sollen. Es ist in Ordnung, sie unverändert zu lassen.
Siehe zum Beispiel den Abschnitt `### Quotes` in `docs/de/llm-prompt.md`.
@@ -459,7 +459,7 @@ Für einige sprachspezifische Anweisungen, siehe z. B. den Abschnitt `### Headin
* der Commit
* der Contextmanager
* die Coroutine
* die Datenbank-Session
* die Datenbanksession
* die Festplatte
* die Domain
* die Engine
@@ -496,7 +496,7 @@ Für einige sprachspezifische Anweisungen, siehe z. B. den Abschnitt `### Headin
//// tab | Info
Dies ist eine nicht vollständige und nicht normative Liste von (meist) technischen Begriffen, die in der Dokumentation vorkommen. Sie kann dem Prompt-Designer helfen herauszufinden, bei welchen Begriffen das LLM Unterstützung braucht. Zum Beispiel, wenn es eine gute Übersetzung immer wieder auf eine suboptimale Übersetzung zurücksetzt. Oder wenn es Probleme hat, einen Begriff in Ihrer Sprache zu konjugieren/deklinieren.
Dies ist eine nicht vollständige und nicht normative Liste von (meist) technischen Begriffen, die in der Dokumentation vorkommen. Sie kann dem Promptdesigner helfen herauszufinden, bei welchen Begriffen das LLM Unterstützung braucht. Zum Beispiel, wenn es eine gute Übersetzung immer wieder auf eine suboptimale Übersetzung zurücksetzt. Oder wenn es Probleme hat, einen Begriff in Ihrer Sprache zu konjugieren/deklinieren.
Siehe z. B. den Abschnitt `### List of English terms and their preferred German translations` in `docs/de/llm-prompt.md`.

View File

@@ -0,0 +1,133 @@
# Von Pydantic v1 zu Pydantic v2 migrieren { #migrate-from-pydantic-v1-to-pydantic-v2 }
Wenn Sie eine ältere FastAPI-App haben, nutzen Sie möglicherweise Pydantic Version 1.
FastAPI unterstützt seit Version 0.100.0 sowohl Pydantic v1 als auch v2.
Wenn Sie Pydantic v2 installiert hatten, wurde dieses verwendet. Wenn stattdessen Pydantic v1 installiert war, wurde jenes verwendet.
Pydantic v1 ist jetzt deprecatet und die Unterstützung dafür wird in den nächsten Versionen von FastAPI entfernt, Sie sollten also zu **Pydantic v2 migrieren**. Auf diese Weise erhalten Sie die neuesten Features, Verbesserungen und Fixes.
/// warning | Achtung
Außerdem hat das Pydantic-Team die Unterstützung für Pydantic v1 in den neuesten Python-Versionen eingestellt, beginnend mit **Python 3.14**.
Wenn Sie die neuesten Features von Python nutzen möchten, müssen Sie sicherstellen, dass Sie Pydantic v2 verwenden.
///
Wenn Sie eine ältere FastAPI-App mit Pydantic v1 haben, zeige ich Ihnen hier, wie Sie sie zu Pydantic v2 migrieren, und die **neuen Features in FastAPI 0.119.0**, die Ihnen bei einer schrittweisen Migration helfen.
## Offizieller Leitfaden { #official-guide }
Pydantic hat einen offiziellen <a href="https://docs.pydantic.dev/latest/migration/" class="external-link" target="_blank">Migrationsleitfaden</a> von v1 zu v2.
Er enthält auch, was sich geändert hat, wie Validierungen nun korrekter und strikter sind, mögliche Stolpersteine, usw.
Sie können ihn lesen, um besser zu verstehen, was sich geändert hat.
## Tests { #tests }
Stellen Sie sicher, dass Sie [Tests](../tutorial/testing.md){.internal-link target=_blank} für Ihre App haben und diese in Continuous Integration (CI) ausführen.
Auf diese Weise können Sie das Update durchführen und sicherstellen, dass weiterhin alles wie erwartet funktioniert.
## `bump-pydantic` { #bump-pydantic }
In vielen Fällen, wenn Sie reguläre Pydantic-Modelle ohne Anpassungen verwenden, können Sie den Großteil des Prozesses der Migration von Pydantic v1 auf Pydantic v2 automatisieren.
Sie können <a href="https://github.com/pydantic/bump-pydantic" class="external-link" target="_blank">`bump-pydantic`</a> vom selben Pydantic-Team verwenden.
Dieses Tool hilft Ihnen, den Großteil des zu ändernden Codes automatisch anzupassen.
Danach können Sie die Tests ausführen und prüfen, ob alles funktioniert. Falls ja, sind Sie fertig. 😎
## Pydantic v1 in v2 { #pydantic-v1-in-v2 }
Pydantic v2 enthält alles aus Pydantic v1 als Untermodul `pydantic.v1`.
Das bedeutet, Sie können die neueste Version von Pydantic v2 installieren und die alten Pydanticv1Komponenten aus diesem Untermodul importieren und verwenden, als hätten Sie das alte Pydantic v1 installiert.
{* ../../docs_src/pydantic_v1_in_v2/tutorial001_an_py310.py hl[1,4] *}
### FastAPI-Unterstützung für Pydantic v1 in v2 { #fastapi-support-for-pydantic-v1-in-v2 }
Seit FastAPI 0.119.0 gibt es außerdem eine teilweise Unterstützung für Pydantic v1 innerhalb von Pydantic v2, um die Migration auf v2 zu erleichtern.
Sie könnten also Pydantic auf die neueste Version 2 aktualisieren und die Importe so ändern, dass das Untermodul `pydantic.v1` verwendet wird, und in vielen Fällen würde es einfach funktionieren.
{* ../../docs_src/pydantic_v1_in_v2/tutorial002_an_py310.py hl[2,5,15] *}
/// warning | Achtung
Beachten Sie, dass, da das PydanticTeam Pydantic v1 in neueren PythonVersionen nicht mehr unterstützt, beginnend mit Python 3.14, auch die Verwendung von `pydantic.v1` unter Python 3.14 und höher nicht unterstützt wird.
///
### Pydantic v1 und v2 in derselben App { #pydantic-v1-and-v2-on-the-same-app }
Es wird von Pydantic **nicht unterstützt**, dass ein Pydanticv2Modell Felder hat, die als Pydanticv1Modelle definiert sind, und umgekehrt.
```mermaid
graph TB
subgraph "❌ Nicht unterstützt"
direction TB
subgraph V2["Pydantic-v2-Modell"]
V1Field["Pydantic-v1-Modell"]
end
subgraph V1["Pydantic-v1-Modell"]
V2Field["Pydantic-v2-Modell"]
end
end
style V2 fill:#f9fff3
style V1 fill:#fff6f0
style V1Field fill:#fff6f0
style V2Field fill:#f9fff3
```
... aber Sie können getrennte Modelle, die Pydantic v1 bzw. v2 nutzen, in derselben App verwenden.
```mermaid
graph TB
subgraph "✅ Unterstützt"
direction TB
subgraph V2["Pydantic-v2-Modell"]
V2Field["Pydantic-v2-Modell"]
end
subgraph V1["Pydantic-v1-Modell"]
V1Field["Pydantic-v1-Modell"]
end
end
style V2 fill:#f9fff3
style V1 fill:#fff6f0
style V1Field fill:#fff6f0
style V2Field fill:#f9fff3
```
In einigen Fällen ist es sogar möglich, sowohl Pydanticv1 als auch Pydanticv2Modelle in derselben **Pfadoperation** Ihrer FastAPIApp zu verwenden:
{* ../../docs_src/pydantic_v1_in_v2/tutorial003_an_py310.py hl[2:3,6,12,21:22] *}
Im obigen Beispiel ist das Eingabemodell ein Pydanticv1Modell, und das Ausgabemodell (definiert in `response_model=ItemV2`) ist ein Pydanticv2Modell.
### Pydantic v1 Parameter { #pydantic-v1-parameters }
Wenn Sie einige der FastAPI-spezifischen Tools für Parameter wie `Body`, `Query`, `Form`, usw. zusammen mit Pydanticv1Modellen verwenden müssen, können Sie die aus `fastapi.temp_pydantic_v1_params` importieren, während Sie die Migration zu Pydantic v2 abschließen:
{* ../../docs_src/pydantic_v1_in_v2/tutorial004_an_py310.py hl[4,18] *}
### In Schritten migrieren { #migrate-in-steps }
/// tip | Tipp
Probieren Sie zuerst `bump-pydantic` aus. Wenn Ihre Tests erfolgreich sind und das funktioniert, sind Sie mit einem einzigen Befehl fertig. ✨
///
Wenn `bump-pydantic` für Ihren Anwendungsfall nicht funktioniert, können Sie die Unterstützung für Pydanticv1 und Pydanticv2Modelle in derselben App nutzen, um die Migration zu Pydantic v2 schrittweise durchzuführen.
Sie könnten zuerst Pydantic auf die neueste Version 2 aktualisieren und die Importe so ändern, dass für all Ihre Modelle `pydantic.v1` verwendet wird.
Anschließend können Sie beginnen, Ihre Modelle gruppenweise von Pydantic v1 auf v2 zu migrieren in kleinen, schrittweisen Etappen. 🚶

View File

@@ -185,7 +185,7 @@ Example:
# FastAPI in Containern - Docker { #fastapi-in-containers-docker }
»»»
3.1) Do not apply rule 3 when there is no space before or no space after the dash.
3.1) Do not apply rule 3 when there is no space before or no space after the hyphen.
Example:
@@ -195,13 +195,13 @@ Example:
## Type hints and annotations { #type-hints-and-annotations }
»»»
Translate with (German) use a short dash:
Translate with (German) notice the hyphen:
«««
## Typhinweise und -annotationen { #type-hints-and-annotations }
»»»
Do NOT translate with (German):
Do NOT translate with (German) notice the dash:
«««
## Typhinweise und annotationen { #type-hints-and-annotations }
@@ -222,7 +222,7 @@ Ich versuche nicht, alles einzudeutschen. Das bezieht sich besonders auf Begriff
### List of English terms and their preferred German translations
Below is a list of English terms and their preferred German translations, separated by a colon («:»). Use these translations, do not use your own. If an existing translation does not use these terms, update it to use them. A term or a translation may be followed by an explanation in brackets, which explains when to translate the term this way. If a translation is preceded by «NOT», then that means: do NOT use this translation for this term. English nouns, starting with the word «the», have the German genus «der», «die», «das» prepended to their German translation, to help you to grammatically decline them in the translation. They are given in singular case, unless they have «(plural)» attached, which means they are given in plural case. Verbs are given in the full infinitive starting with the word «to».
Below is a list of English terms and their preferred German translations, separated by a colon («:»). Use these translations, do not use your own. If an existing translation does not use these terms, update it to use them. In the below list, a term or a translation may be followed by an explanation in brackets, which explains when to translate the term this way. If a translation is preceded by «NOT», then that means: do NOT use this translation for this term. English nouns, starting with the word «the», have the German genus «der», «die», «das» prepended to their German translation, to help you to grammatically decline them in the translation. They are given in singular case, unless they have «(plural)» attached, which means they are given in plural case. Verbs are given in the full infinitive starting with the word «to».
* «/// check»: «/// check | Testen»
* «/// danger»: «/// danger | Gefahr»

View File

@@ -1,11 +1,11 @@
tiangolo:
login: tiangolo
count: 782
count: 794
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
url: https://github.com/tiangolo
dependabot:
login: dependabot
count: 117
count: 126
avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4
url: https://github.com/apps/dependabot
alejsdev:
@@ -15,7 +15,7 @@ alejsdev:
url: https://github.com/alejsdev
pre-commit-ci:
login: pre-commit-ci
count: 45
count: 49
avatarUrl: https://avatars.githubusercontent.com/in/68672?v=4
url: https://github.com/apps/pre-commit-ci
github-actions:
@@ -25,7 +25,7 @@ github-actions:
url: https://github.com/apps/github-actions
Kludex:
login: Kludex
count: 24
count: 25
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4
url: https://github.com/Kludex
dmontagu:
@@ -33,36 +33,36 @@ dmontagu:
count: 17
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
url: https://github.com/dmontagu
YuriiMotov:
login: YuriiMotov
count: 15
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
url: https://github.com/YuriiMotov
nilslindemann:
login: nilslindemann
count: 14
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
euri10:
login: euri10
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
url: https://github.com/euri10
nilslindemann:
login: nilslindemann
svlandeg:
login: svlandeg
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
url: https://github.com/svlandeg
kantandane:
login: kantandane
count: 13
avatarUrl: https://avatars.githubusercontent.com/u/3978368?u=cccc199291f991a73b1ebba5abc735a948e0bd16&v=4
url: https://github.com/kantandane
svlandeg:
login: svlandeg
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
url: https://github.com/svlandeg
zhaohan-dong:
login: zhaohan-dong
count: 11
avatarUrl: https://avatars.githubusercontent.com/u/65422392?u=8260f8781f50248410ebfa4c9bf70e143fe5c9f2&v=4
url: https://github.com/zhaohan-dong
YuriiMotov:
login: YuriiMotov
count: 10
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
url: https://github.com/YuriiMotov
mariacamilagl:
login: mariacamilagl
count: 9
@@ -158,6 +158,11 @@ prostomarkeloff:
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=6918e39a1224194ba636e897461a02a20126d7ad&v=4
url: https://github.com/prostomarkeloff
frankie567:
login: frankie567
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=f3e79acfe4ed207e15c2145161a8a9759925fcd2&v=4
url: https://github.com/frankie567
nsidnev:
login: nsidnev
count: 3
@@ -191,7 +196,7 @@ Serrones:
uriyyo:
login: uriyyo
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/32038156?u=0c68019beb28381ce5205a838937c61e0fe3fee2&v=4
avatarUrl: https://avatars.githubusercontent.com/u/32038156?u=c26ca9b821fcf6499b84db75f553d4980bf8d023&v=4
url: https://github.com/uriyyo
andrew222651:
login: andrew222651
@@ -261,7 +266,7 @@ Nimitha-jagadeesha:
lucaromagnoli:
login: lucaromagnoli
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=e66396859f493b4ddcb3a837a1b2b2039c805417&v=4
avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=15df02e806a2293af40ac619fba11dbe3c0c4fd4&v=4
url: https://github.com/lucaromagnoli
salmantec:
login: salmantec
@@ -328,11 +333,6 @@ svalouch:
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/54674660?v=4
url: https://github.com/svalouch
frankie567:
login: frankie567
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=f3e79acfe4ed207e15c2145161a8a9759925fcd2&v=4
url: https://github.com/frankie567
marier-nico:
login: marier-nico
count: 2
@@ -346,7 +346,7 @@ Dustyposa:
aviramha:
login: aviramha
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=6883cc4fc13a7b2e60d4deddd4be06f9c5287880&v=4
avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=ce5d3ea7037c2e6b3f82eff87e2217d4fb63214b&v=4
url: https://github.com/aviramha
iwpnd:
login: iwpnd

View File

@@ -14,6 +14,9 @@ sponsors:
- login: coderabbitai
avatarUrl: https://avatars.githubusercontent.com/u/132028505?v=4
url: https://github.com/coderabbitai
- login: greptileai
avatarUrl: https://avatars.githubusercontent.com/u/140149887?v=4
url: https://github.com/greptileai
- login: subtotal
avatarUrl: https://avatars.githubusercontent.com/u/176449348?v=4
url: https://github.com/subtotal
@@ -41,9 +44,9 @@ sponsors:
- login: permitio
avatarUrl: https://avatars.githubusercontent.com/u/71775833?v=4
url: https://github.com/permitio
- - login: marvin-robot
avatarUrl: https://avatars.githubusercontent.com/u/41086007?u=b9fcab402d0cd0aec738b6574fe60855cb0cd36d&v=4
url: https://github.com/marvin-robot
- - login: BoostryJP
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
url: https://github.com/BoostryJP
- login: mercedes-benz
avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4
url: https://github.com/mercedes-benz
@@ -53,9 +56,9 @@ sponsors:
- login: LambdaTest-Inc
avatarUrl: https://avatars.githubusercontent.com/u/171592363?u=96606606a45fa170427206199014f2a5a2a4920b&v=4
url: https://github.com/LambdaTest-Inc
- login: BoostryJP
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
url: https://github.com/BoostryJP
- login: requestly
avatarUrl: https://avatars.githubusercontent.com/u/12287519?v=4
url: https://github.com/requestly
- login: acsone
avatarUrl: https://avatars.githubusercontent.com/u/7601056?v=4
url: https://github.com/acsone
@@ -71,27 +74,39 @@ sponsors:
- - login: mainframeindustries
avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4
url: https://github.com/mainframeindustries
- login: yasyf
avatarUrl: https://avatars.githubusercontent.com/u/709645?u=f36736b3c6a85f578886ecc42a740e7b436e7a01&v=4
url: https://github.com/yasyf
- - login: alixlahuec
avatarUrl: https://avatars.githubusercontent.com/u/29543316?u=44357eb2a93bccf30fb9d389b8befe94a3d00985&v=4
url: https://github.com/alixlahuec
- login: Partho
avatarUrl: https://avatars.githubusercontent.com/u/2034301?u=ce195ac36835cca0cdfe6dd6e897bd38873a1524&v=4
url: https://github.com/Partho
- - login: primer-io
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
url: https://github.com/primer-io
- - login: nilslindemann
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
- login: upciti
- login: xsalagarcia
avatarUrl: https://avatars.githubusercontent.com/u/66035908?v=4
url: https://github.com/xsalagarcia
- - login: upciti
avatarUrl: https://avatars.githubusercontent.com/u/43346262?v=4
url: https://github.com/upciti
- login: thisisfixer
avatarUrl: https://avatars.githubusercontent.com/u/14433035?u=076d52a5b7891c764904af9f462bfb45428e25df&v=4
url: https://github.com/thisisfixer
- login: GonnaFlyMethod
avatarUrl: https://avatars.githubusercontent.com/u/60840539?u=edf70b373fd4f1a83d3eb7c6802f4b6addb572cf&v=4
url: https://github.com/GonnaFlyMethod
- login: ChargeStorm
avatarUrl: https://avatars.githubusercontent.com/u/26000165?v=4
url: https://github.com/ChargeStorm
- login: DanielYang59
avatarUrl: https://avatars.githubusercontent.com/u/80093591?u=63873f701c7c74aac83c906800a1dddc0bc8c92f&v=4
url: https://github.com/DanielYang59
- login: nilslindemann
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
- - login: samuelcolvin
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4
url: https://github.com/samuelcolvin
- login: vincentkoc
avatarUrl: https://avatars.githubusercontent.com/u/25068?u=fbd5b2d51142daa4bdbc21e21953a3b8b8188a4a&v=4
url: https://github.com/vincentkoc
- login: otosky
avatarUrl: https://avatars.githubusercontent.com/u/42260747?u=69d089387c743d89427aa4ad8740cfb34045a9e0&v=4
url: https://github.com/otosky
@@ -101,6 +116,9 @@ sponsors:
- login: roboflow
avatarUrl: https://avatars.githubusercontent.com/u/53104118?v=4
url: https://github.com/roboflow
- login: dudikbender
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=3a57542938ebfd57579a0111db2b297e606d9681&v=4
url: https://github.com/dudikbender
- login: ehaca
avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=cec1a3e0643b785288ae8260cc295a85ab344995&v=4
url: https://github.com/ehaca
@@ -113,21 +131,15 @@ sponsors:
- login: Leay15
avatarUrl: https://avatars.githubusercontent.com/u/32212558?u=c4aa9c1737e515959382a5515381757b1fd86c53&v=4
url: https://github.com/Leay15
- login: kaoru0310
avatarUrl: https://avatars.githubusercontent.com/u/80977929?u=1b61d10142b490e56af932ddf08a390fae8ee94f&v=4
url: https://github.com/kaoru0310
- login: DelfinaCare
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
url: https://github.com/DelfinaCare
- login: Karine-Bauch
avatarUrl: https://avatars.githubusercontent.com/u/90465103?u=7feb1018abb1a5631cfd9a91fea723d1ceb5f49b&v=4
url: https://github.com/Karine-Bauch
- login: jugeeem
avatarUrl: https://avatars.githubusercontent.com/u/116043716?u=ae590d79c38ac79c91b9c5caa6887d061e865a3d&v=4
url: https://github.com/jugeeem
- login: dudikbender
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=3a57542938ebfd57579a0111db2b297e606d9681&v=4
url: https://github.com/dudikbender
- login: connorpark24
avatarUrl: https://avatars.githubusercontent.com/u/142128990?u=09b84a4beb1f629b77287a837bcf3729785cdd89&v=4
url: https://github.com/connorpark24
- login: patsatsia
avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=3271b85f7a37b479c8d0ae0a235182e83c166edf&v=4
url: https://github.com/patsatsia
@@ -140,9 +152,12 @@ sponsors:
- login: chickenandstats
avatarUrl: https://avatars.githubusercontent.com/u/79477966?u=ae2b894aa954070db1d7830dab99b49eba4e4567&v=4
url: https://github.com/chickenandstats
- login: dodo5522
avatarUrl: https://avatars.githubusercontent.com/u/1362607?u=9bf1e0e520cccc547c046610c468ce6115bbcf9f&v=4
url: https://github.com/dodo5522
- login: kaoru0310
avatarUrl: https://avatars.githubusercontent.com/u/80977929?u=1b61d10142b490e56af932ddf08a390fae8ee94f&v=4
url: https://github.com/kaoru0310
- login: DelfinaCare
avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4
url: https://github.com/DelfinaCare
- login: knallgelb
avatarUrl: https://avatars.githubusercontent.com/u/2358812?u=c48cb6362b309d74cbf144bd6ad3aed3eb443e82&v=4
url: https://github.com/knallgelb
@@ -170,9 +185,12 @@ sponsors:
- login: Ryandaydev
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=679ff84cb7b988c5795a5fa583857f574a055763&v=4
url: https://github.com/Ryandaydev
- login: vincentkoc
avatarUrl: https://avatars.githubusercontent.com/u/25068?u=fbd5b2d51142daa4bdbc21e21953a3b8b8188a4a&v=4
url: https://github.com/vincentkoc
- login: jaredtrog
avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4
url: https://github.com/jaredtrog
- login: oliverxchen
avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
url: https://github.com/oliverxchen
- login: jstanden
avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4
url: https://github.com/jstanden
@@ -197,6 +215,9 @@ sponsors:
- login: mintuhouse
avatarUrl: https://avatars.githubusercontent.com/u/769950?u=ecfbd79a97d33177e0d093ddb088283cf7fe8444&v=4
url: https://github.com/mintuhouse
- login: dodo5522
avatarUrl: https://avatars.githubusercontent.com/u/1362607?u=9bf1e0e520cccc547c046610c468ce6115bbcf9f&v=4
url: https://github.com/dodo5522
- login: wdwinslow
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=371272f2c69e680e0559a7b0a57385e83a5dc728&v=4
url: https://github.com/wdwinslow
@@ -212,18 +233,15 @@ sponsors:
- login: mjohnsey
avatarUrl: https://avatars.githubusercontent.com/u/16784016?u=38fad2e6b411244560b3af99c5f5a4751bc81865&v=4
url: https://github.com/mjohnsey
- login: enguy-hub
avatarUrl: https://avatars.githubusercontent.com/u/16822912?u=2c45f9e7f427b2f2f3b023d7fdb0d44764c92ae8&v=4
url: https://github.com/enguy-hub
- login: ashi-agrawal
avatarUrl: https://avatars.githubusercontent.com/u/17105294?u=99c7a854035e5398d8e7b674f2d42baae6c957f8&v=4
url: https://github.com/ashi-agrawal
- login: RaamEEIL
avatarUrl: https://avatars.githubusercontent.com/u/20320552?v=4
url: https://github.com/RaamEEIL
- login: jaredtrog
avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4
url: https://github.com/jaredtrog
- login: oliverxchen
avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
url: https://github.com/oliverxchen
- login: ternaus
avatarUrl: https://avatars.githubusercontent.com/u/5481618?u=513a26b02a39e7a28d587cd37c6cc877ea368e6e&v=4
url: https://github.com/ternaus
@@ -242,7 +260,10 @@ sponsors:
- - login: manoelpqueiroz
avatarUrl: https://avatars.githubusercontent.com/u/23669137?u=b12e84b28a84369ab5b30bd5a79e5788df5a0756&v=4
url: https://github.com/manoelpqueiroz
- - login: pawamoy
- - login: ceb10n
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
url: https://github.com/ceb10n
- login: pawamoy
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
url: https://github.com/pawamoy
- login: siavashyj
@@ -260,9 +281,9 @@ sponsors:
- login: hgalytoby
avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=6cc9028f3db63f8f60ad21c17b1ce4b88c4e2e60&v=4
url: https://github.com/hgalytoby
- login: nisutec
avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4
url: https://github.com/nisutec
- login: johnl28
avatarUrl: https://avatars.githubusercontent.com/u/54412955?u=47dd06082d1c39caa90c752eb55566e4f3813957&v=4
url: https://github.com/johnl28
- login: hoenie-ams
avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4
url: https://github.com/hoenie-ams
@@ -278,33 +299,21 @@ sponsors:
- login: petercool
avatarUrl: https://avatars.githubusercontent.com/u/37613029?u=75aa8c6729e6e8f85a300561c4dbeef9d65c8797&v=4
url: https://github.com/petercool
- login: JulioPeixoto
avatarUrl: https://avatars.githubusercontent.com/u/96303574?u=27d4614350cae33653f1be35cb47c92a12627ac9&v=4
url: https://github.com/JulioPeixoto
- login: johnl28
avatarUrl: https://avatars.githubusercontent.com/u/54412955?u=47dd06082d1c39caa90c752eb55566e4f3813957&v=4
url: https://github.com/johnl28
- login: PunRabbit
avatarUrl: https://avatars.githubusercontent.com/u/70463212?u=1a835cfbc99295a60c8282f6aa6199d1b42241a5&v=4
url: https://github.com/PunRabbit
- login: PelicanQ
avatarUrl: https://avatars.githubusercontent.com/u/77930606?v=4
url: https://github.com/PelicanQ
- login: miguelgr
avatarUrl: https://avatars.githubusercontent.com/u/1484589?u=54556072b8136efa12ae3b6902032ea2a39ace4b&v=4
url: https://github.com/miguelgr
- login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=8a80356e3e7d5a417157aba7ea565dabc8678327&v=4
url: https://github.com/WillHogan
- login: my3
avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4
url: https://github.com/my3
- login: Alisa-lisa
avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4
url: https://github.com/Alisa-lisa
- login: moonape1226
avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4
url: https://github.com/moonape1226
- login: danielunderwood
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
url: https://github.com/danielunderwood
- login: rangulvers
avatarUrl: https://avatars.githubusercontent.com/u/5235430?u=e254d4af4ace5a05fa58372ae677c7d26f0d5a53&v=4
url: https://github.com/rangulvers
- login: ddanier
avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4
url: https://github.com/ddanier
@@ -314,24 +323,18 @@ sponsors:
- login: slafs
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
url: https://github.com/slafs
- login: ceb10n
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
url: https://github.com/ceb10n
- login: tochikuji
avatarUrl: https://avatars.githubusercontent.com/u/851759?v=4
url: https://github.com/tochikuji
- login: xncbf
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=a80a7bb349555b277645632ed66639ff43400614&v=4
url: https://github.com/xncbf
- login: DMantis
avatarUrl: https://avatars.githubusercontent.com/u/9536869?u=652dd0d49717803c0cbcbf44f7740e53cf2d4892&v=4
url: https://github.com/DMantis
- login: miguelgr
avatarUrl: https://avatars.githubusercontent.com/u/1484589?u=54556072b8136efa12ae3b6902032ea2a39ace4b&v=4
url: https://github.com/miguelgr
- login: WillHogan
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=8a80356e3e7d5a417157aba7ea565dabc8678327&v=4
url: https://github.com/WillHogan
- login: hard-coders
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
url: https://github.com/hard-coders
- login: supdann
avatarUrl: https://avatars.githubusercontent.com/u/9986994?u=9671810f4ae9504c063227fee34fd47567ff6954&v=4
url: https://github.com/supdann
- login: mntolia
avatarUrl: https://avatars.githubusercontent.com/u/10390224?v=4
url: https://github.com/mntolia
@@ -344,12 +347,9 @@ sponsors:
- login: joshuatz
avatarUrl: https://avatars.githubusercontent.com/u/17817563?u=f1bf05b690d1fc164218f0b420cdd3acb7913e21&v=4
url: https://github.com/joshuatz
- login: danielunderwood
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
url: https://github.com/danielunderwood
- login: rangulvers
avatarUrl: https://avatars.githubusercontent.com/u/5235430?u=e254d4af4ace5a05fa58372ae677c7d26f0d5a53&v=4
url: https://github.com/rangulvers
- login: nisutec
avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4
url: https://github.com/nisutec
- login: sdevkota
avatarUrl: https://avatars.githubusercontent.com/u/5250987?u=4ed9a120c89805a8aefda1cbdc0cf6512e64d1b4&v=4
url: https://github.com/sdevkota
@@ -365,39 +365,45 @@ sponsors:
- login: harsh183
avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4
url: https://github.com/harsh183
- - login: KOZ39
avatarUrl: https://avatars.githubusercontent.com/u/38822500?u=9dfc0a697df1c9628f08e20dc3fb17b1afc4e5a7&v=4
url: https://github.com/KOZ39
- login: rwxd
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
url: https://github.com/rwxd
- login: morzan1001
- login: moonape1226
avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4
url: https://github.com/moonape1226
- login: xncbf
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=a80a7bb349555b277645632ed66639ff43400614&v=4
url: https://github.com/xncbf
- login: DMantis
avatarUrl: https://avatars.githubusercontent.com/u/9536869?u=652dd0d49717803c0cbcbf44f7740e53cf2d4892&v=4
url: https://github.com/DMantis
- - login: morzan1001
avatarUrl: https://avatars.githubusercontent.com/u/47593005?u=c30ab7230f82a12a9b938dcb54f84a996931409a&v=4
url: https://github.com/morzan1001
- login: azharthegeek
avatarUrl: https://avatars.githubusercontent.com/u/51288109?u=0987b2a9f39c21ccb071b6bdce0fc60d8492f8e8&v=4
url: https://github.com/azharthegeek
- login: Olegt0rr
avatarUrl: https://avatars.githubusercontent.com/u/25399456?u=3e87b5239a2f4600975ba13be73054f8567c6060&v=4
url: https://github.com/Olegt0rr
- login: larsyngvelundin
avatarUrl: https://avatars.githubusercontent.com/u/34173819?u=74958599695bf83ac9f1addd935a51548a10c6b0&v=4
url: https://github.com/larsyngvelundin
- login: andrecorumba
avatarUrl: https://avatars.githubusercontent.com/u/37807517?u=9b9be3b41da9bda60957da9ef37b50dbf65baa61&v=4
url: https://github.com/andrecorumba
- login: ChenPu2002
avatarUrl: https://avatars.githubusercontent.com/u/113831763?v=4
url: https://github.com/ChenPu2002
- login: KOZ39
avatarUrl: https://avatars.githubusercontent.com/u/38822500?u=9dfc0a697df1c9628f08e20dc3fb17b1afc4e5a7&v=4
url: https://github.com/KOZ39
- login: rwxd
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
url: https://github.com/rwxd
- login: hippoley
avatarUrl: https://avatars.githubusercontent.com/u/135493401?u=1164ef48a645a7c12664fabc1638fbb7e1c459b0&v=4
url: https://github.com/hippoley
- login: CoderDeltaLAN
avatarUrl: https://avatars.githubusercontent.com/u/152043745?u=4ff541efffb7d134e60c5fcf2dd1e343f90bb782&v=4
url: https://github.com/CoderDeltaLAN
- login: aghents
avatarUrl: https://avatars.githubusercontent.com/u/60949885?u=d8616ddf22cf998a712cdceefd6a0256a178fe9d&v=4
url: https://github.com/aghents
- login: 0ne-stone
- login: chris1ding1
avatarUrl: https://avatars.githubusercontent.com/u/194386334?u=5500604b50e35ed8a5aeb82ce34aa5d3ee3f88c7&v=4
url: https://github.com/chris1ding1
- login: onestn
avatarUrl: https://avatars.githubusercontent.com/u/62360849?u=746dd21c34e7e06eefb11b03e8bb01aaae3c2a4f&v=4
url: https://github.com/0ne-stone
url: https://github.com/onestn
- login: Rubinskiy
avatarUrl: https://avatars.githubusercontent.com/u/62457878?u=f2e35ed3d196a99cfadb5a29a91950342af07e34&v=4
url: https://github.com/Rubinskiy
- login: nayasinghania
avatarUrl: https://avatars.githubusercontent.com/u/74111380?u=752e99a5e139389fdc0a0677122adc08438eb076&v=4
url: https://github.com/nayasinghania
@@ -407,6 +413,9 @@ sponsors:
- login: andreagrandi
avatarUrl: https://avatars.githubusercontent.com/u/636391?u=13d90cb8ec313593a5b71fbd4e33b78d6da736f5&v=4
url: https://github.com/andreagrandi
- login: Olegt0rr
avatarUrl: https://avatars.githubusercontent.com/u/25399456?u=3e87b5239a2f4600975ba13be73054f8567c6060&v=4
url: https://github.com/Olegt0rr
- login: msserpa
avatarUrl: https://avatars.githubusercontent.com/u/6334934?u=82c4489eb1559d88d2990d60001901b14f722bbb&v=4
url: https://github.com/msserpa

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

@@ -1,81 +1,86 @@
- name: full-stack-fastapi-template
html_url: https://github.com/fastapi/full-stack-fastapi-template
stars: 38085
stars: 38779
owner_login: fastapi
owner_html_url: https://github.com/fastapi
- name: Hello-Python
html_url: https://github.com/mouredev/Hello-Python
stars: 32243
stars: 32726
owner_login: mouredev
owner_html_url: https://github.com/mouredev
- name: serve
html_url: https://github.com/jina-ai/serve
stars: 21754
stars: 21779
owner_login: jina-ai
owner_html_url: https://github.com/jina-ai
- name: HivisionIDPhotos
html_url: https://github.com/Zeyi-Lin/HivisionIDPhotos
stars: 19400
stars: 20028
owner_login: Zeyi-Lin
owner_html_url: https://github.com/Zeyi-Lin
- name: sqlmodel
html_url: https://github.com/fastapi/sqlmodel
stars: 16859
stars: 17038
owner_login: fastapi
owner_html_url: https://github.com/fastapi
- name: Douyin_TikTok_Download_API
html_url: https://github.com/Evil0ctal/Douyin_TikTok_Download_API
stars: 14452
stars: 14786
owner_login: Evil0ctal
owner_html_url: https://github.com/Evil0ctal
- name: fastapi-best-practices
html_url: https://github.com/zhanymkanov/fastapi-best-practices
stars: 13613
stars: 13968
owner_login: zhanymkanov
owner_html_url: https://github.com/zhanymkanov
- name: machine-learning-zoomcamp
html_url: https://github.com/DataTalksClub/machine-learning-zoomcamp
stars: 12171
owner_login: DataTalksClub
owner_html_url: https://github.com/DataTalksClub
- name: fastapi_mcp
html_url: https://github.com/tadata-org/fastapi_mcp
stars: 10624
stars: 10976
owner_login: tadata-org
owner_html_url: https://github.com/tadata-org
- name: awesome-fastapi
html_url: https://github.com/mjhea0/awesome-fastapi
stars: 10415
stars: 10618
owner_login: mjhea0
owner_html_url: https://github.com/mjhea0
- name: FastUI
html_url: https://github.com/pydantic/FastUI
stars: 8879
owner_login: pydantic
owner_html_url: https://github.com/pydantic
- name: XHS-Downloader
html_url: https://github.com/JoeanAmier/XHS-Downloader
stars: 8824
owner_login: JoeanAmier
owner_html_url: https://github.com/JoeanAmier
- name: SurfSense
html_url: https://github.com/MODSetter/SurfSense
stars: 8257
stars: 10243
owner_login: MODSetter
owner_html_url: https://github.com/MODSetter
- name: FileCodeBox
html_url: https://github.com/vastsa/FileCodeBox
stars: 7367
owner_login: vastsa
owner_html_url: https://github.com/vastsa
- name: XHS-Downloader
html_url: https://github.com/JoeanAmier/XHS-Downloader
stars: 9062
owner_login: JoeanAmier
owner_html_url: https://github.com/JoeanAmier
- name: FastUI
html_url: https://github.com/pydantic/FastUI
stars: 8892
owner_login: pydantic
owner_html_url: https://github.com/pydantic
- name: polar
html_url: https://github.com/polarsource/polar
stars: 7291
stars: 8084
owner_login: polarsource
owner_html_url: https://github.com/polarsource
- name: FileCodeBox
html_url: https://github.com/vastsa/FileCodeBox
stars: 7494
owner_login: vastsa
owner_html_url: https://github.com/vastsa
- name: nonebot2
html_url: https://github.com/nonebot/nonebot2
stars: 7065
stars: 7128
owner_login: nonebot
owner_html_url: https://github.com/nonebot
- name: hatchet
html_url: https://github.com/hatchet-dev/hatchet
stars: 6070
stars: 6155
owner_login: hatchet-dev
owner_html_url: https://github.com/hatchet-dev
- name: serge
@@ -85,27 +90,27 @@
owner_html_url: https://github.com/serge-chat
- name: fastapi-users
html_url: https://github.com/fastapi-users/fastapi-users
stars: 5599
stars: 5683
owner_login: fastapi-users
owner_html_url: https://github.com/fastapi-users
- name: strawberry
html_url: https://github.com/strawberry-graphql/strawberry
stars: 4422
stars: 4452
owner_login: strawberry-graphql
owner_html_url: https://github.com/strawberry-graphql
- name: chatgpt-web-share
html_url: https://github.com/chatpire/chatgpt-web-share
stars: 4301
stars: 4296
owner_login: chatpire
owner_html_url: https://github.com/chatpire
- name: poem
html_url: https://github.com/poem-web/poem
stars: 4197
stars: 4235
owner_login: poem-web
owner_html_url: https://github.com/poem-web
- name: dynaconf
html_url: https://github.com/dynaconf/dynaconf
stars: 4144
stars: 4174
owner_login: dynaconf
owner_html_url: https://github.com/dynaconf
- name: atrilabs-engine
@@ -115,42 +120,42 @@
owner_html_url: https://github.com/Atri-Labs
- name: Kokoro-FastAPI
html_url: https://github.com/remsky/Kokoro-FastAPI
stars: 3739
stars: 3875
owner_login: remsky
owner_html_url: https://github.com/remsky
- name: logfire
html_url: https://github.com/pydantic/logfire
stars: 3614
stars: 3717
owner_login: pydantic
owner_html_url: https://github.com/pydantic
- name: LitServe
html_url: https://github.com/Lightning-AI/LitServe
stars: 3578
stars: 3615
owner_login: Lightning-AI
owner_html_url: https://github.com/Lightning-AI
- name: datamodel-code-generator
html_url: https://github.com/koxudaxi/datamodel-code-generator
stars: 3496
stars: 3554
owner_login: koxudaxi
owner_html_url: https://github.com/koxudaxi
- name: farfalle
html_url: https://github.com/rashadphz/farfalle
stars: 3459
owner_login: rashadphz
owner_html_url: https://github.com/rashadphz
- name: fastapi-admin
html_url: https://github.com/fastapi-admin/fastapi-admin
stars: 3456
owner_login: fastapi-admin
owner_html_url: https://github.com/fastapi-admin
- name: huma
html_url: https://github.com/danielgtaylor/huma
stars: 3447
stars: 3521
owner_login: danielgtaylor
owner_html_url: https://github.com/danielgtaylor
- name: fastapi-admin
html_url: https://github.com/fastapi-admin/fastapi-admin
stars: 3497
owner_login: fastapi-admin
owner_html_url: https://github.com/fastapi-admin
- name: farfalle
html_url: https://github.com/rashadphz/farfalle
stars: 3476
owner_login: rashadphz
owner_html_url: https://github.com/rashadphz
- name: tracecat
html_url: https://github.com/TracecatHQ/tracecat
stars: 3254
stars: 3310
owner_login: TracecatHQ
owner_html_url: https://github.com/TracecatHQ
- name: opyrator
@@ -160,336 +165,331 @@
owner_html_url: https://github.com/ml-tooling
- name: docarray
html_url: https://github.com/docarray/docarray
stars: 3107
stars: 3108
owner_login: docarray
owner_html_url: https://github.com/docarray
- name: fastapi-realworld-example-app
html_url: https://github.com/nsidnev/fastapi-realworld-example-app
stars: 2936
stars: 2945
owner_login: nsidnev
owner_html_url: https://github.com/nsidnev
- name: uvicorn-gunicorn-fastapi-docker
html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker
stars: 2804
stars: 2809
owner_login: tiangolo
owner_html_url: https://github.com/tiangolo
- name: best-of-web-python
html_url: https://github.com/ml-tooling/best-of-web-python
stars: 2610
owner_login: ml-tooling
owner_html_url: https://github.com/ml-tooling
- name: devpush
html_url: https://github.com/hunvreus/devpush
stars: 2784
owner_login: hunvreus
owner_html_url: https://github.com/hunvreus
- name: mcp-context-forge
html_url: https://github.com/IBM/mcp-context-forge
stars: 2572
stars: 2763
owner_login: IBM
owner_html_url: https://github.com/IBM
- name: best-of-web-python
html_url: https://github.com/ml-tooling/best-of-web-python
stars: 2630
owner_login: ml-tooling
owner_html_url: https://github.com/ml-tooling
- name: fastapi-react
html_url: https://github.com/Buuntu/fastapi-react
stars: 2451
stars: 2464
owner_login: Buuntu
owner_html_url: https://github.com/Buuntu
- name: RasaGPT
html_url: https://github.com/paulpierre/RasaGPT
stars: 2441
owner_login: paulpierre
owner_html_url: https://github.com/paulpierre
- name: FastAPI-template
html_url: https://github.com/s3rius/FastAPI-template
stars: 2424
stars: 2453
owner_login: s3rius
owner_html_url: https://github.com/s3rius
- name: RasaGPT
html_url: https://github.com/paulpierre/RasaGPT
stars: 2444
owner_login: paulpierre
owner_html_url: https://github.com/paulpierre
- name: sqladmin
html_url: https://github.com/aminalaee/sqladmin
stars: 2357
stars: 2423
owner_login: aminalaee
owner_html_url: https://github.com/aminalaee
- name: nextpy
html_url: https://github.com/dot-agent/nextpy
stars: 2324
stars: 2325
owner_login: dot-agent
owner_html_url: https://github.com/dot-agent
- name: supabase-py
html_url: https://github.com/supabase/supabase-py
stars: 2236
stars: 2292
owner_login: supabase
owner_html_url: https://github.com/supabase
- name: 30-Days-of-Python
html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python
stars: 2210
stars: 2214
owner_login: codingforentrepreneurs
owner_html_url: https://github.com/codingforentrepreneurs
- name: Yuxi-Know
html_url: https://github.com/xerrors/Yuxi-Know
stars: 2212
owner_login: xerrors
owner_html_url: https://github.com/xerrors
- name: langserve
html_url: https://github.com/langchain-ai/langserve
stars: 2171
stars: 2191
owner_login: langchain-ai
owner_html_url: https://github.com/langchain-ai
- name: fastapi-utils
html_url: https://github.com/fastapiutils/fastapi-utils
stars: 2164
stars: 2185
owner_login: fastapiutils
owner_html_url: https://github.com/fastapiutils
- name: solara
html_url: https://github.com/widgetti/solara
stars: 2102
stars: 2111
owner_login: widgetti
owner_html_url: https://github.com/widgetti
- name: Yuxi-Know
html_url: https://github.com/xerrors/Yuxi-Know
stars: 1995
owner_login: xerrors
owner_html_url: https://github.com/xerrors
- name: mangum
html_url: https://github.com/Kludex/mangum
stars: 1989
stars: 2011
owner_login: Kludex
owner_html_url: https://github.com/Kludex
- name: python-week-2022
html_url: https://github.com/rochacbruno/python-week-2022
stars: 1816
owner_login: rochacbruno
owner_html_url: https://github.com/rochacbruno
- name: agentkit
html_url: https://github.com/BCG-X-Official/agentkit
stars: 1789
stars: 1826
owner_login: BCG-X-Official
owner_html_url: https://github.com/BCG-X-Official
- name: python-week-2022
html_url: https://github.com/rochacbruno/python-week-2022
stars: 1815
owner_login: rochacbruno
owner_html_url: https://github.com/rochacbruno
- name: manage-fastapi
html_url: https://github.com/ycd/manage-fastapi
stars: 1780
stars: 1787
owner_login: ycd
owner_html_url: https://github.com/ycd
- name: ormar
html_url: https://github.com/collerek/ormar
stars: 1777
stars: 1780
owner_login: collerek
owner_html_url: https://github.com/collerek
- name: vue-fastapi-admin
html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin
stars: 1758
owner_login: mizhexiaoxiao
owner_html_url: https://github.com/mizhexiaoxiao
- name: openapi-python-client
html_url: https://github.com/openapi-generators/openapi-python-client
stars: 1707
stars: 1731
owner_login: openapi-generators
owner_html_url: https://github.com/openapi-generators
- name: piccolo
html_url: https://github.com/piccolo-orm/piccolo
stars: 1695
stars: 1711
owner_login: piccolo-orm
owner_html_url: https://github.com/piccolo-orm
- name: vue-fastapi-admin
html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin
stars: 1695
owner_login: mizhexiaoxiao
owner_html_url: https://github.com/mizhexiaoxiao
- name: fastapi-cache
html_url: https://github.com/long2ice/fastapi-cache
stars: 1653
stars: 1677
owner_login: long2ice
owner_html_url: https://github.com/long2ice
- name: slowapi
html_url: https://github.com/laurentS/slowapi
stars: 1669
owner_login: laurentS
owner_html_url: https://github.com/laurentS
- name: langchain-serve
html_url: https://github.com/jina-ai/langchain-serve
stars: 1635
stars: 1632
owner_login: jina-ai
owner_html_url: https://github.com/jina-ai
- name: termpair
html_url: https://github.com/cs01/termpair
stars: 1624
stars: 1621
owner_login: cs01
owner_html_url: https://github.com/cs01
- name: slowapi
html_url: https://github.com/laurentS/slowapi
stars: 1620
owner_login: laurentS
owner_html_url: https://github.com/laurentS
- name: FastAPI-boilerplate
html_url: https://github.com/benavlabs/FastAPI-boilerplate
stars: 1596
owner_login: benavlabs
owner_html_url: https://github.com/benavlabs
- name: coronavirus-tracker-api
html_url: https://github.com/ExpDev07/coronavirus-tracker-api
stars: 1576
stars: 1573
owner_login: ExpDev07
owner_html_url: https://github.com/ExpDev07
- name: fastapi-crudrouter
html_url: https://github.com/awtkns/fastapi-crudrouter
stars: 1546
stars: 1553
owner_login: awtkns
owner_html_url: https://github.com/awtkns
- name: FastAPI-boilerplate
html_url: https://github.com/benavlabs/FastAPI-boilerplate
stars: 1516
owner_login: benavlabs
owner_html_url: https://github.com/benavlabs
- name: awesome-fastapi-projects
html_url: https://github.com/Kludex/awesome-fastapi-projects
stars: 1481
stars: 1485
owner_login: Kludex
owner_html_url: https://github.com/Kludex
- name: fastapi-pagination
html_url: https://github.com/uriyyo/fastapi-pagination
stars: 1453
stars: 1473
owner_login: uriyyo
owner_html_url: https://github.com/uriyyo
- name: bracket
html_url: https://github.com/evroon/bracket
stars: 1415
stars: 1470
owner_login: evroon
owner_html_url: https://github.com/evroon
- name: awesome-python-resources
html_url: https://github.com/DjangoEx/awesome-python-resources
stars: 1413
owner_login: DjangoEx
owner_html_url: https://github.com/DjangoEx
- name: fastapi-boilerplate
html_url: https://github.com/teamhide/fastapi-boilerplate
stars: 1406
owner_login: teamhide
owner_html_url: https://github.com/teamhide
- name: budgetml
html_url: https://github.com/ebhy/budgetml
stars: 1346
owner_login: ebhy
owner_html_url: https://github.com/ebhy
- name: fastapi-amis-admin
html_url: https://github.com/amisadmin/fastapi-amis-admin
stars: 1342
owner_login: amisadmin
owner_html_url: https://github.com/amisadmin
- name: fastapi-langgraph-agent-production-ready-template
html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template
stars: 1334
stars: 1456
owner_login: wassim249
owner_html_url: https://github.com/wassim249
- name: fastapi-boilerplate
html_url: https://github.com/teamhide/fastapi-boilerplate
stars: 1424
owner_login: teamhide
owner_html_url: https://github.com/teamhide
- name: awesome-python-resources
html_url: https://github.com/DjangoEx/awesome-python-resources
stars: 1420
owner_login: DjangoEx
owner_html_url: https://github.com/DjangoEx
- name: fastapi-amis-admin
html_url: https://github.com/amisadmin/fastapi-amis-admin
stars: 1363
owner_login: amisadmin
owner_html_url: https://github.com/amisadmin
- name: fastcrud
html_url: https://github.com/benavlabs/fastcrud
stars: 1362
owner_login: benavlabs
owner_html_url: https://github.com/benavlabs
- name: budgetml
html_url: https://github.com/ebhy/budgetml
stars: 1345
owner_login: ebhy
owner_html_url: https://github.com/ebhy
- name: fastapi-tutorial
html_url: https://github.com/liaogx/fastapi-tutorial
stars: 1303
stars: 1315
owner_login: liaogx
owner_html_url: https://github.com/liaogx
- name: fastapi_best_architecture
html_url: https://github.com/fastapi-practices/fastapi_best_architecture
stars: 1276
stars: 1311
owner_login: fastapi-practices
owner_html_url: https://github.com/fastapi-practices
- name: fastcrud
html_url: https://github.com/benavlabs/fastcrud
stars: 1272
owner_login: benavlabs
owner_html_url: https://github.com/benavlabs
- name: fastapi-code-generator
html_url: https://github.com/koxudaxi/fastapi-code-generator
stars: 1253
stars: 1270
owner_login: koxudaxi
owner_html_url: https://github.com/koxudaxi
- name: prometheus-fastapi-instrumentator
html_url: https://github.com/trallnag/prometheus-fastapi-instrumentator
stars: 1246
stars: 1264
owner_login: trallnag
owner_html_url: https://github.com/trallnag
- name: bolt-python
html_url: https://github.com/slackapi/bolt-python
stars: 1221
owner_login: slackapi
owner_html_url: https://github.com/slackapi
- name: bedrock-chat
html_url: https://github.com/aws-samples/bedrock-chat
stars: 1220
stars: 1243
owner_login: aws-samples
owner_html_url: https://github.com/aws-samples
- name: bolt-python
html_url: https://github.com/slackapi/bolt-python
stars: 1238
owner_login: slackapi
owner_html_url: https://github.com/slackapi
- name: fastapi_production_template
html_url: https://github.com/zhanymkanov/fastapi_production_template
stars: 1202
stars: 1209
owner_login: zhanymkanov
owner_html_url: https://github.com/zhanymkanov
- name: fastapi-scaff
html_url: https://github.com/atpuxiner/fastapi-scaff
stars: 1193
stars: 1200
owner_login: atpuxiner
owner_html_url: https://github.com/atpuxiner
- name: langchain-extract
html_url: https://github.com/langchain-ai/langchain-extract
stars: 1164
stars: 1173
owner_login: langchain-ai
owner_html_url: https://github.com/langchain-ai
- name: fastapi-alembic-sqlmodel-async
html_url: https://github.com/jonra1993/fastapi-alembic-sqlmodel-async
stars: 1149
stars: 1162
owner_login: jonra1993
owner_html_url: https://github.com/jonra1993
- name: odmantic
html_url: https://github.com/art049/odmantic
stars: 1133
stars: 1137
owner_login: art049
owner_html_url: https://github.com/art049
- name: restish
html_url: https://github.com/rest-sh/restish
stars: 1122
stars: 1129
owner_login: rest-sh
owner_html_url: https://github.com/rest-sh
- name: runhouse
html_url: https://github.com/run-house/runhouse
stars: 1047
- name: kubetorch
html_url: https://github.com/run-house/kubetorch
stars: 1065
owner_login: run-house
owner_html_url: https://github.com/run-house
- name: flock
html_url: https://github.com/Onelevenvy/flock
stars: 1027
stars: 1039
owner_login: Onelevenvy
owner_html_url: https://github.com/Onelevenvy
- name: authx
html_url: https://github.com/yezz123/authx
stars: 999
stars: 1017
owner_login: yezz123
owner_html_url: https://github.com/yezz123
- name: autollm
html_url: https://github.com/viddexa/autollm
stars: 999
stars: 997
owner_login: viddexa
owner_html_url: https://github.com/viddexa
- name: lanarky
html_url: https://github.com/ajndkr/lanarky
stars: 995
stars: 993
owner_login: ajndkr
owner_html_url: https://github.com/ajndkr
- name: titiler
html_url: https://github.com/developmentseed/titiler
stars: 952
owner_login: developmentseed
owner_html_url: https://github.com/developmentseed
- name: energy-forecasting
html_url: https://github.com/iusztinpaul/energy-forecasting
stars: 946
owner_login: iusztinpaul
owner_html_url: https://github.com/iusztinpaul
- name: secure
html_url: https://github.com/TypeError/secure
stars: 944
owner_login: TypeError
owner_html_url: https://github.com/TypeError
- name: langcorn
html_url: https://github.com/msoedov/langcorn
stars: 934
owner_login: msoedov
owner_html_url: https://github.com/msoedov
- name: RuoYi-Vue3-FastAPI
html_url: https://github.com/insistence/RuoYi-Vue3-FastAPI
stars: 930
stars: 974
owner_login: insistence
owner_html_url: https://github.com/insistence
- name: aktools
html_url: https://github.com/akfamily/aktools
stars: 916
stars: 972
owner_login: akfamily
owner_html_url: https://github.com/akfamily
- name: titiler
html_url: https://github.com/developmentseed/titiler
stars: 965
owner_login: developmentseed
owner_html_url: https://github.com/developmentseed
- name: secure
html_url: https://github.com/TypeError/secure
stars: 953
owner_login: TypeError
owner_html_url: https://github.com/TypeError
- name: energy-forecasting
html_url: https://github.com/iusztinpaul/energy-forecasting
stars: 949
owner_login: iusztinpaul
owner_html_url: https://github.com/iusztinpaul
- name: every-pdf
html_url: https://github.com/DDULDDUCK/every-pdf
stars: 907
stars: 942
owner_login: DDULDDUCK
owner_html_url: https://github.com/DDULDDUCK
- name: marker-api
html_url: https://github.com/adithya-s-k/marker-api
stars: 903
owner_login: adithya-s-k
owner_html_url: https://github.com/adithya-s-k
- name: langcorn
html_url: https://github.com/msoedov/langcorn
stars: 933
owner_login: msoedov
owner_html_url: https://github.com/msoedov
- name: fastapi-observability
html_url: https://github.com/blueswen/fastapi-observability
stars: 902
stars: 923
owner_login: blueswen
owner_html_url: https://github.com/blueswen
- name: fastapi-do-zero
html_url: https://github.com/dunossauro/fastapi-do-zero
stars: 900
owner_login: dunossauro
owner_html_url: https://github.com/dunossauro

View File

@@ -776,7 +776,7 @@ pablocm83:
d2a-raudenaerde:
login: d2a-raudenaerde
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/5213150?v=4
avatarUrl: https://avatars.githubusercontent.com/u/5213150?u=e6d0ef65c571c7e544fc1c7ec151c7c0a72fb6bb&v=4
url: https://github.com/d2a-raudenaerde
valentinDruzhinin:
login: valentinDruzhinin
@@ -1206,7 +1206,7 @@ akagaeng:
phamquanganh31101998:
login: phamquanganh31101998
count: 3
avatarUrl: https://avatars.githubusercontent.com/u/43257497?u=36fa4ee689415d869a98453083a7c4213d2136ee&v=4
avatarUrl: https://avatars.githubusercontent.com/u/43257497?u=6b3419ea9e318c356c42a973fb947682590bd8d3&v=4
url: https://github.com/phamquanganh31101998
peebbv6364:
login: peebbv6364
@@ -1806,7 +1806,7 @@ MrL8199:
ivintoiu:
login: ivintoiu
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/1853336?u=5e3d0977f44661fb9712fa297cc8f7608ea6ce48&v=4
avatarUrl: https://avatars.githubusercontent.com/u/1853336?u=b537c905ad08b69993de8796fb235c8d4d47f039&v=4
url: https://github.com/ivintoiu
TechnoService2:
login: TechnoService2
@@ -1841,7 +1841,7 @@ NavesSapnis:
eqsdxr:
login: eqsdxr
count: 2
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=58fddf77ed76966eaa8c73eea9bea4bb0c53b673&v=4
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=d7aaffb29f542b647cf0f6b0e05722490863658a&v=4
url: https://github.com/eqsdxr
syedasamina56:
login: syedasamina56

View File

@@ -1,6 +1,6 @@
nilslindemann:
login: nilslindemann
count: 122
count: 124
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
url: https://github.com/nilslindemann
jaystone776:
@@ -103,6 +103,11 @@ pablocm83:
count: 8
avatarUrl: https://avatars.githubusercontent.com/u/28315068?u=3310fbb05bb8bfc50d2c48b6cb64ac9ee4a14549&v=4
url: https://github.com/pablocm83
tiangolo:
login: tiangolo
count: 7
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
url: https://github.com/tiangolo
ptt3199:
login: ptt3199
count: 7
@@ -118,11 +123,6 @@ batlopes:
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
url: https://github.com/batlopes
tiangolo:
login: tiangolo
count: 6
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
url: https://github.com/tiangolo
lucasbalieiro:
login: lucasbalieiro
count: 6

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,82 @@ hide:
## Latest Changes
## 0.121.0
### Features
* ✨ Add support for dependencies with scopes, support `scope="request"` for dependencies with `yield` that exit before the response is sent. PR [#14262](https://github.com/fastapi/fastapi/pull/14262) by [@tiangolo](https://github.com/tiangolo).
* New docs: [Dependencies with `yield` - Early exit and `scope`](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#early-exit-and-scope).
### Internal
* 👥 Update FastAPI People - Contributors and Translators. PR [#14273](https://github.com/fastapi/fastapi/pull/14273) by [@tiangolo](https://github.com/tiangolo).
* 👥 Update FastAPI People - Sponsors. PR [#14274](https://github.com/fastapi/fastapi/pull/14274) by [@tiangolo](https://github.com/tiangolo).
* 👥 Update FastAPI GitHub topic repositories. PR [#14280](https://github.com/fastapi/fastapi/pull/14280) by [@tiangolo](https://github.com/tiangolo).
* ⬆ Bump mkdocs-macros-plugin from 1.4.0 to 1.4.1. PR [#14277](https://github.com/fastapi/fastapi/pull/14277) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ Bump mkdocstrings[python] from 0.26.1 to 0.30.1. PR [#14279](https://github.com/fastapi/fastapi/pull/14279) by [@dependabot[bot]](https://github.com/apps/dependabot).
## 0.120.4
### Fixes
* 🐛 Fix security schemes in OpenAPI when added at the top level app. PR [#14266](https://github.com/fastapi/fastapi/pull/14266) by [@YuriiMotov](https://github.com/YuriiMotov).
## 0.120.3
### Refactors
* ♻️ Reduce internal cyclic recursion in dependencies, from 2 functions calling each other to 1 calling itself. PR [#14256](https://github.com/fastapi/fastapi/pull/14256) by [@tiangolo](https://github.com/tiangolo).
* ♻️ Refactor internals of dependencies, simplify code and remove `get_param_sub_dependant`. PR [#14255](https://github.com/fastapi/fastapi/pull/14255) by [@tiangolo](https://github.com/tiangolo).
* ♻️ Refactor internals of dependencies, simplify using dataclasses. PR [#14254](https://github.com/fastapi/fastapi/pull/14254) by [@tiangolo](https://github.com/tiangolo).
### Docs
* 📝 Update note for untranslated pages. PR [#14257](https://github.com/fastapi/fastapi/pull/14257) by [@YuriiMotov](https://github.com/YuriiMotov).
## 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. ☕️
The internal reference documentation now uses `annotated_doc.Doc` instead of `typing_extensions.Doc`, this adds a new (very small) dependency on [`annotated-doc`](https://github.com/fastapi/annotated-doc), a package made just to provide that `Doc` documentation utility class.
I would expect `typing_extensions.Doc` to be deprecated and then removed at some point from `typing_extensions`, for that reason there's the new `annotated-doc` micro-package. If you are curious about this, you can read more in the repo for [`annotated-doc`](https://github.com/fastapi/annotated-doc).
This new version `0.120.0` only contains that transition to the new home package for that utility class `Doc`.
### Translations
* 🌐 Sync German docs. PR [#14188](https://github.com/fastapi/fastapi/pull/14188) by [@nilslindemann](https://github.com/nilslindemann).
### Internal
* Migrate internal reference documentation from `typing_extensions.Doc` to `annotated_doc.Doc`. PR [#14222](https://github.com/fastapi/fastapi/pull/14222) by [@tiangolo](https://github.com/tiangolo).
* 🛠️ Update German LLM prompt and test file. PR [#14189](https://github.com/fastapi/fastapi/pull/14189) by [@nilslindemann](https://github.com/nilslindemann).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#14181](https://github.com/fastapi/fastapi/pull/14181) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
## 0.119.1
### Fixes

View File

@@ -184,6 +184,51 @@ If you raise any exception in the code from the *path operation function*, it wi
///
## Early exit and `scope` { #early-exit-and-scope }
Normally the exit code of dependencies with `yield` is executed **after the response** is sent to the client.
But if you know that you won't need to use the dependency after returning from the *path operation function*, you can use `Depends(scope="function")` to tell FastAPI that it should close the dependency after the *path operation function* returns, but **before** the **response is sent**.
{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
`Depends()` receives a `scope` parameter that can be:
* `"function"`: start the dependency before the *path operation function* that handles the request, end the dependency after the *path operation function* ends, but **before** the response is sent back to the client. So, the dependency function will be executed **around** the *path operation **function***.
* `"request"`: start the dependency before the *path operation function* that handles the request (similar to when using `"function"`), but end **after** the response is sent back to the client. So, the dependency function will be executed **around** the **request** and response cycle.
If not specified and the dependency has `yield`, it will have a `scope` of `"request"` by default.
### `scope` for sub-dependencies { #scope-for-sub-dependencies }
When you declare a dependency with a `scope="request"` (the default), any sub-dependency needs to also have a `scope` of `"request"`.
But a dependency with `scope` of `"function"` can have dependencies with `scope` of `"function"` and `scope` of `"request"`.
This is because any dependency needs to be able to run its exit code before the sub-dependencies, as it might need to still use them during its exit code.
```mermaid
sequenceDiagram
participant client as Client
participant dep_req as Dep scope="request"
participant dep_func as Dep scope="function"
participant operation as Path Operation
client ->> dep_req: Start request
Note over dep_req: Run code up to yield
dep_req ->> dep_func: Pass dependency
Note over dep_func: Run code up to yield
dep_func ->> operation: Run path operation with dependency
operation ->> dep_func: Return from path operation
Note over dep_func: Run code after yield
Note over dep_func: ✅ Dependency closed
dep_func ->> client: Send response to client
Note over client: Response sent
Note over dep_req: Run code after yield
Note over dep_req: ✅ Dependency closed
```
## Dependencies with `yield`, `HTTPException`, `except` and Background Tasks { #dependencies-with-yield-httpexception-except-and-background-tasks }
Dependencies with `yield` have evolved over time to cover different use cases and fix some issues.

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,7 +1,9 @@
/// warning
The current page still doesn't have a translation for this language.
This page hasnt been translated into your language yet. 🌍
But you can help translating it: [Contributing](https://fastapi.tiangolo.com/contributing/){.internal-link target=_blank}.
Were currently switching to an automated translation system 🤖, which will help keep all translations complete and up to date.
Learn more: [Contributing Translations](https://fastapi.tiangolo.com/contributing/#translations){.internal-link target=_blank}
///

View File

@@ -1,5 +1,6 @@
from typing import Any
import orjson
from fastapi import FastAPI, Response
app = FastAPI()
@@ -9,8 +10,6 @@ class CustomORJSONResponse(Response):
media_type = "application/json"
def render(self, content: Any) -> bytes:
import orjson
assert orjson is not None, "orjson must be installed"
return orjson.dumps(content, option=orjson.OPT_INDENT_2)

View File

@@ -0,0 +1,15 @@
from fastapi import Depends, FastAPI
app = FastAPI()
def get_username():
try:
yield "Rick"
finally:
print("Cleanup up before response is sent")
@app.get("/users/me")
def get_user_me(username: str = Depends(get_username, scope="function")):
return username

View File

@@ -0,0 +1,16 @@
from fastapi import Depends, FastAPI
from typing_extensions import Annotated
app = FastAPI()
def get_username():
try:
yield "Rick"
finally:
print("Cleanup up before response is sent")
@app.get("/users/me")
def get_user_me(username: Annotated[str, Depends(get_username, scope="function")]):
return username

View File

@@ -0,0 +1,17 @@
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
def get_username():
try:
yield "Rick"
finally:
print("Cleanup up before response is sent")
@app.get("/users/me")
def get_user_me(username: Annotated[str, Depends(get_username, scope="function")]):
return username

View File

@@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.119.1"
__version__ = "0.121.0"
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

@@ -13,6 +13,7 @@ from typing import (
Union,
)
from annotated_doc import Doc
from fastapi import routing
from fastapi.datastructures import Default, DefaultPlaceholder
from fastapi.exception_handlers import (
@@ -43,7 +44,7 @@ from starlette.requests import Request
from starlette.responses import HTMLResponse, JSONResponse, Response
from starlette.routing import BaseRoute
from starlette.types import ASGIApp, ExceptionHandler, Lifespan, Receive, Scope, Send
from typing_extensions import Annotated, Doc, deprecated
from typing_extensions import Annotated, deprecated
AppType = TypeVar("AppType", bound="FastAPI")

View File

@@ -1,7 +1,8 @@
from typing import Any, Callable
from annotated_doc import Doc
from starlette.background import BackgroundTasks as StarletteBackgroundTasks
from typing_extensions import Annotated, Doc, ParamSpec
from typing_extensions import Annotated, ParamSpec
P = ParamSpec("P")

View File

@@ -10,6 +10,7 @@ from typing import (
cast,
)
from annotated_doc import Doc
from fastapi._compat import (
CoreSchema,
GetJsonSchemaHandler,
@@ -22,7 +23,7 @@ from starlette.datastructures import Headers as Headers # noqa: F401
from starlette.datastructures import QueryParams as QueryParams # noqa: F401
from starlette.datastructures import State as State # noqa: F401
from starlette.datastructures import UploadFile as StarletteUploadFile
from typing_extensions import Annotated, Doc
from typing_extensions import Annotated
class UploadFile(StarletteUploadFile):

View File

@@ -1,8 +1,18 @@
import inspect
import sys
from dataclasses import dataclass, field
from typing import Any, Callable, List, Optional, Sequence, Tuple
from functools import cached_property
from typing import Any, Callable, List, Optional, Sequence, Union
from fastapi._compat import ModelField
from fastapi.security.base import SecurityBase
from fastapi.types import DependencyCacheKey
from typing_extensions import Literal
if sys.version_info >= (3, 13): # pragma: no cover
from inspect import iscoroutinefunction
else: # pragma: no cover
from asyncio import iscoroutinefunction
@dataclass
@@ -31,7 +41,43 @@ class Dependant:
security_scopes: Optional[List[str]] = None
use_cache: bool = True
path: Optional[str] = None
cache_key: Tuple[Optional[Callable[..., Any]], Tuple[str, ...]] = field(init=False)
scope: Union[Literal["function", "request"], None] = None
def __post_init__(self) -> None:
self.cache_key = (self.call, tuple(sorted(set(self.security_scopes or []))))
@cached_property
def cache_key(self) -> DependencyCacheKey:
return (
self.call,
tuple(sorted(set(self.security_scopes or []))),
self.computed_scope or "",
)
@cached_property
def is_gen_callable(self) -> bool:
if inspect.isgeneratorfunction(self.call):
return True
dunder_call = getattr(self.call, "__call__", None) # noqa: B004
return inspect.isgeneratorfunction(dunder_call)
@cached_property
def is_async_gen_callable(self) -> bool:
if inspect.isasyncgenfunction(self.call):
return True
dunder_call = getattr(self.call, "__call__", None) # noqa: B004
return inspect.isasyncgenfunction(dunder_call)
@cached_property
def is_coroutine_callable(self) -> bool:
if inspect.isroutine(self.call):
return iscoroutinefunction(self.call)
if inspect.isclass(self.call):
return False
dunder_call = getattr(self.call, "__call__", None) # noqa: B004
return iscoroutinefunction(dunder_call)
@cached_property
def computed_scope(self) -> Union[str, None]:
if self.scope:
return self.scope
if self.is_gen_callable or self.is_async_gen_callable:
return "request"
return None

View File

@@ -1,5 +1,4 @@
import inspect
import sys
from contextlib import AsyncExitStack, contextmanager
from copy import copy, deepcopy
from dataclasses import dataclass
@@ -55,10 +54,12 @@ from fastapi.concurrency import (
contextmanager_in_threadpool,
)
from fastapi.dependencies.models import Dependant, SecurityRequirement
from fastapi.exceptions import DependencyScopeError
from fastapi.logger import logger
from fastapi.security.base import SecurityBase
from fastapi.security.oauth2 import OAuth2, SecurityScopes
from fastapi.security.open_id_connect_url import OpenIdConnect
from fastapi.types import DependencyCacheKey
from fastapi.utils import create_model_field, get_path_param_names
from pydantic import BaseModel
from pydantic.fields import FieldInfo
@@ -74,15 +75,10 @@ from starlette.datastructures import (
from starlette.requests import HTTPConnection, Request
from starlette.responses import Response
from starlette.websockets import WebSocket
from typing_extensions import Annotated, get_args, get_origin
from typing_extensions import Annotated, Literal, get_args, get_origin
from .. import temp_pydantic_v1_params
if sys.version_info >= (3, 13): # pragma: no cover
from inspect import iscoroutinefunction
else: # pragma: no cover
from asyncio import iscoroutinefunction
multipart_not_installed_error = (
'Form data requires "python-multipart" to be installed. \n'
'You can install "python-multipart" with: \n\n'
@@ -125,70 +121,23 @@ def ensure_multipart_is_installed() -> None:
raise RuntimeError(multipart_not_installed_error) from None
def get_param_sub_dependant(
*,
param_name: str,
depends: params.Depends,
path: str,
security_scopes: Optional[List[str]] = None,
) -> Dependant:
assert depends.dependency
return get_sub_dependant(
depends=depends,
dependency=depends.dependency,
path=path,
name=param_name,
security_scopes=security_scopes,
)
def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> Dependant:
assert callable(depends.dependency), (
"A parameter-less dependency must have a callable dependency"
)
return get_sub_dependant(depends=depends, dependency=depends.dependency, path=path)
def get_sub_dependant(
*,
depends: params.Depends,
dependency: Callable[..., Any],
path: str,
name: Optional[str] = None,
security_scopes: Optional[List[str]] = None,
) -> Dependant:
security_requirement = None
security_scopes = security_scopes or []
if isinstance(depends, params.Security):
dependency_scopes = depends.scopes
security_scopes.extend(dependency_scopes)
if isinstance(dependency, SecurityBase):
use_scopes: List[str] = []
if isinstance(dependency, (OAuth2, OpenIdConnect)):
use_scopes = security_scopes
security_requirement = SecurityRequirement(
security_scheme=dependency, scopes=use_scopes
)
sub_dependant = get_dependant(
path=path,
call=dependency,
name=name,
security_scopes=security_scopes,
use_cache=depends.use_cache,
use_security_scopes: List[str] = []
if isinstance(depends, params.Security) and depends.scopes:
use_security_scopes.extend(depends.scopes)
return get_dependant(
path=path, call=depends.dependency, security_scopes=use_security_scopes
)
if security_requirement:
sub_dependant.security_requirements.append(security_requirement)
return sub_dependant
CacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...]]
def get_flat_dependant(
dependant: Dependant,
*,
skip_repeats: bool = False,
visited: Optional[List[CacheKey]] = None,
visited: Optional[List[DependencyCacheKey]] = None,
) -> Dependant:
if visited is None:
visited = []
@@ -281,17 +230,27 @@ def get_dependant(
name: Optional[str] = None,
security_scopes: Optional[List[str]] = None,
use_cache: bool = True,
scope: Union[Literal["function", "request"], None] = None,
) -> Dependant:
path_param_names = get_path_param_names(path)
endpoint_signature = get_typed_signature(call)
signature_params = endpoint_signature.parameters
dependant = Dependant(
call=call,
name=name,
path=path,
security_scopes=security_scopes,
use_cache=use_cache,
scope=scope,
)
path_param_names = get_path_param_names(path)
endpoint_signature = get_typed_signature(call)
signature_params = endpoint_signature.parameters
if isinstance(call, SecurityBase):
use_scopes: List[str] = []
if isinstance(call, (OAuth2, OpenIdConnect)):
use_scopes = security_scopes or use_scopes
security_requirement = SecurityRequirement(
security_scheme=call, scopes=use_scopes
)
dependant.security_requirements.append(security_requirement)
for param_name, param in signature_params.items():
is_path_param = param_name in path_param_names
param_details = analyze_param(
@@ -301,11 +260,28 @@ def get_dependant(
is_path_param=is_path_param,
)
if param_details.depends is not None:
sub_dependant = get_param_sub_dependant(
param_name=param_name,
depends=param_details.depends,
assert param_details.depends.dependency
if (
(dependant.is_gen_callable or dependant.is_async_gen_callable)
and dependant.computed_scope == "request"
and param_details.depends.scope == "function"
):
assert dependant.call
raise DependencyScopeError(
f'The dependency "{dependant.call.__name__}" has a scope of '
'"request", it cannot depend on dependencies with scope "function".'
)
use_security_scopes = security_scopes or []
if isinstance(param_details.depends, params.Security):
if param_details.depends.scopes:
use_security_scopes.extend(param_details.depends.scopes)
sub_dependant = get_dependant(
path=path,
security_scopes=security_scopes,
call=param_details.depends.dependency,
name=param_name,
security_scopes=use_security_scopes,
use_cache=param_details.depends.use_cache,
scope=param_details.depends.scope,
)
dependant.dependencies.append(sub_dependant)
continue
@@ -562,36 +538,14 @@ def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
dependant.cookie_params.append(field)
def is_coroutine_callable(call: Callable[..., Any]) -> bool:
if inspect.isroutine(call):
return iscoroutinefunction(call)
if inspect.isclass(call):
return False
dunder_call = getattr(call, "__call__", None) # noqa: B004
return iscoroutinefunction(dunder_call)
def is_async_gen_callable(call: Callable[..., Any]) -> bool:
if inspect.isasyncgenfunction(call):
return True
dunder_call = getattr(call, "__call__", None) # noqa: B004
return inspect.isasyncgenfunction(dunder_call)
def is_gen_callable(call: Callable[..., Any]) -> bool:
if inspect.isgeneratorfunction(call):
return True
dunder_call = getattr(call, "__call__", None) # noqa: B004
return inspect.isgeneratorfunction(dunder_call)
async def solve_generator(
*, call: Callable[..., Any], stack: AsyncExitStack, sub_values: Dict[str, Any]
async def _solve_generator(
*, dependant: Dependant, stack: AsyncExitStack, sub_values: Dict[str, Any]
) -> Any:
if is_gen_callable(call):
cm = contextmanager_in_threadpool(contextmanager(call)(**sub_values))
elif is_async_gen_callable(call):
cm = asynccontextmanager(call)(**sub_values)
assert dependant.call
if dependant.is_gen_callable:
cm = contextmanager_in_threadpool(contextmanager(dependant.call)(**sub_values))
elif dependant.is_async_gen_callable:
cm = asynccontextmanager(dependant.call)(**sub_values)
return await stack.enter_async_context(cm)
@@ -601,7 +555,7 @@ class SolvedDependency:
errors: List[Any]
background_tasks: Optional[StarletteBackgroundTasks]
response: Response
dependency_cache: Dict[Tuple[Callable[..., Any], Tuple[str]], Any]
dependency_cache: Dict[DependencyCacheKey, Any]
async def solve_dependencies(
@@ -612,10 +566,20 @@ async def solve_dependencies(
background_tasks: Optional[StarletteBackgroundTasks] = None,
response: Optional[Response] = None,
dependency_overrides_provider: Optional[Any] = None,
dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
dependency_cache: Optional[Dict[DependencyCacheKey, Any]] = None,
# TODO: remove this parameter later, no longer used, not removing it yet as some
# people might be monkey patching this function (although that's not supported)
async_exit_stack: AsyncExitStack,
embed_body_fields: bool,
) -> SolvedDependency:
request_astack = request.scope.get("fastapi_inner_astack")
assert isinstance(request_astack, AsyncExitStack), (
"fastapi_inner_astack not found in request scope"
)
function_astack = request.scope.get("fastapi_function_astack")
assert isinstance(function_astack, AsyncExitStack), (
"fastapi_function_astack not found in request scope"
)
values: Dict[str, Any] = {}
errors: List[Any] = []
if response is None:
@@ -624,12 +588,8 @@ async def solve_dependencies(
response.status_code = None # type: ignore
if dependency_cache is None:
dependency_cache = {}
sub_dependant: Dependant
for sub_dependant in dependant.dependencies:
sub_dependant.call = cast(Callable[..., Any], sub_dependant.call)
sub_dependant.cache_key = cast(
Tuple[Callable[..., Any], Tuple[str]], sub_dependant.cache_key
)
call = sub_dependant.call
use_sub_dependant = sub_dependant
if (
@@ -646,6 +606,7 @@ async def solve_dependencies(
call=call,
name=sub_dependant.name,
security_scopes=sub_dependant.security_scopes,
scope=sub_dependant.scope,
)
solved_result = await solve_dependencies(
@@ -665,11 +626,18 @@ async def solve_dependencies(
continue
if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
solved = dependency_cache[sub_dependant.cache_key]
elif is_gen_callable(call) or is_async_gen_callable(call):
solved = await solve_generator(
call=call, stack=async_exit_stack, sub_values=solved_result.values
elif (
use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable
):
use_astack = request_astack
if sub_dependant.scope == "function":
use_astack = function_astack
solved = await _solve_generator(
dependant=use_sub_dependant,
stack=use_astack,
sub_values=solved_result.values,
)
elif is_coroutine_callable(call):
elif use_sub_dependant.is_coroutine_callable:
solved = await call(**solved_result.values)
else:
solved = await run_in_threadpool(call, **solved_result.values)

View File

@@ -17,13 +17,14 @@ from types import GeneratorType
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
from uuid import UUID
from annotated_doc import Doc
from fastapi._compat import may_v1
from fastapi.types import IncEx
from pydantic import BaseModel
from pydantic.color import Color
from pydantic.networks import AnyUrl, NameEmail
from pydantic.types import SecretBytes, SecretStr
from typing_extensions import Annotated, Doc
from typing_extensions import Annotated
from ._compat import Url, _is_undefined, _model_dump

View File

@@ -1,9 +1,10 @@
from typing import Any, Dict, Optional, Sequence, Type, Union
from annotated_doc import Doc
from pydantic import BaseModel, create_model
from starlette.exceptions import HTTPException as StarletteHTTPException
from starlette.exceptions import WebSocketException as StarletteWebSocketException
from typing_extensions import Annotated, Doc
from typing_extensions import Annotated
class HTTPException(StarletteHTTPException):
@@ -146,6 +147,13 @@ class FastAPIError(RuntimeError):
"""
class DependencyScopeError(FastAPIError):
"""
A dependency declared that it depends on another dependency with an invalid
(narrower) scope.
"""
class ValidationException(Exception):
def __init__(self, errors: Sequence[Any]) -> None:
self._errors = errors

View File

@@ -1,9 +1,10 @@
import json
from typing import Any, Dict, Optional
from annotated_doc import Doc
from fastapi.encoders import jsonable_encoder
from starlette.responses import HTMLResponse
from typing_extensions import Annotated, Doc
from typing_extensions import Annotated
swagger_ui_default_parameters: Annotated[
Dict[str, Any],

View File

@@ -1,9 +1,10 @@
from typing import Any, Callable, Dict, List, Optional, Sequence, Union
from annotated_doc import Doc
from fastapi import params
from fastapi._compat import Undefined
from fastapi.openapi.models import Example
from typing_extensions import Annotated, Doc, deprecated
from typing_extensions import Annotated, Literal, deprecated
_Unset: Any = Undefined
@@ -2244,6 +2245,26 @@ def Depends( # noqa: N802
"""
),
] = True,
scope: Annotated[
Union[Literal["function", "request"], None],
Doc(
"""
Mainly for dependencies with `yield`, define when the dependency function
should start (the code before `yield`) and when it should end (the code
after `yield`).
* `"function"`: start the dependency before the *path operation function*
that handles the request, end the dependency after the *path operation
function* ends, but **before** the response is sent back to the client.
So, the dependency function will be executed **around** the *path operation
**function***.
* `"request"`: start the dependency before the *path operation function*
that handles the request (similar to when using `"function"`), but end
**after** the response is sent back to the client. So, the dependency
function will be executed **around** the **request** and response cycle.
"""
),
] = None,
) -> Any:
"""
Declare a FastAPI dependency.
@@ -2274,7 +2295,7 @@ def Depends( # noqa: N802
return commons
```
"""
return params.Depends(dependency=dependency, use_cache=use_cache)
return params.Depends(dependency=dependency, use_cache=use_cache, scope=scope)
def Security( # noqa: N802

View File

@@ -1,10 +1,11 @@
import warnings
from dataclasses import dataclass
from enum import Enum
from typing import Any, Callable, Dict, List, Optional, Sequence, Union
from fastapi.openapi.models import Example
from pydantic.fields import FieldInfo
from typing_extensions import Annotated, deprecated
from typing_extensions import Annotated, Literal, deprecated
from ._compat import (
PYDANTIC_V2,
@@ -761,26 +762,13 @@ class File(Form): # type: ignore[misc]
)
@dataclass
class Depends:
def __init__(
self, dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True
):
self.dependency = dependency
self.use_cache = use_cache
def __repr__(self) -> str:
attr = getattr(self.dependency, "__name__", type(self.dependency).__name__)
cache = "" if self.use_cache else ", use_cache=False"
return f"{self.__class__.__name__}({attr}{cache})"
dependency: Optional[Callable[..., Any]] = None
use_cache: bool = True
scope: Union[Literal["function", "request"], None] = None
@dataclass
class Security(Depends):
def __init__(
self,
dependency: Optional[Callable[..., Any]] = None,
*,
scopes: Optional[Sequence[str]] = None,
use_cache: bool = True,
):
super().__init__(dependency=dependency, use_cache=use_cache)
self.scopes = scopes or []
scopes: Optional[Sequence[str]] = None

View File

@@ -24,6 +24,7 @@ from typing import (
Union,
)
from annotated_doc import Doc
from fastapi import params, temp_pydantic_v1_params
from fastapi._compat import (
ModelField,
@@ -76,7 +77,7 @@ from starlette.routing import (
from starlette.routing import Mount as Mount # noqa
from starlette.types import AppType, ASGIApp, Lifespan, Receive, Scope, Send
from starlette.websockets import WebSocket
from typing_extensions import Annotated, Doc, deprecated
from typing_extensions import Annotated, deprecated
if sys.version_info >= (3, 13): # pragma: no cover
from inspect import iscoroutinefunction
@@ -103,10 +104,11 @@ def request_response(
async def app(scope: Scope, receive: Receive, send: Send) -> None:
# Starts customization
response_awaited = False
async with AsyncExitStack() as stack:
scope["fastapi_inner_astack"] = stack
# Same as in Starlette
response = await f(request)
async with AsyncExitStack() as request_stack:
scope["fastapi_inner_astack"] = request_stack
async with AsyncExitStack() as function_stack:
scope["fastapi_function_astack"] = function_stack
response = await f(request)
await response(scope, receive, send)
# Continues customization
response_awaited = True
@@ -139,11 +141,11 @@ def websocket_session(
session = WebSocket(scope, receive=receive, send=send)
async def app(scope: Scope, receive: Receive, send: Send) -> None:
# Starts customization
async with AsyncExitStack() as stack:
scope["fastapi_inner_astack"] = stack
# Same as in Starlette
await func(session)
async with AsyncExitStack() as request_stack:
scope["fastapi_inner_astack"] = request_stack
async with AsyncExitStack() as function_stack:
scope["fastapi_function_astack"] = function_stack
await func(session)
# Same as in Starlette
await wrap_app_handling_exceptions(app, session)(scope, receive, send)
@@ -478,7 +480,9 @@ class APIWebSocketRoute(routing.WebSocketRoute):
self.name = get_name(endpoint) if name is None else name
self.dependencies = list(dependencies or [])
self.path_regex, self.path_format, self.param_convertors = compile_path(path)
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
self.dependant = get_dependant(
path=self.path_format, call=self.endpoint, scope="function"
)
for depends in self.dependencies[::-1]:
self.dependant.dependencies.insert(
0,
@@ -629,7 +633,9 @@ class APIRoute(routing.Route):
self.response_fields = {}
assert callable(endpoint), "An endpoint must be a callable"
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
self.dependant = get_dependant(
path=self.path_format, call=self.endpoint, scope="function"
)
for depends in self.dependencies[::-1]:
self.dependant.dependencies.insert(
0,

View File

@@ -1,11 +1,12 @@
from typing import Optional
from annotated_doc import Doc
from fastapi.openapi.models import APIKey, APIKeyIn
from fastapi.security.base import SecurityBase
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.status import HTTP_403_FORBIDDEN
from typing_extensions import Annotated, Doc
from typing_extensions import Annotated
class APIKeyBase(SecurityBase):

View File

@@ -2,6 +2,7 @@ import binascii
from base64 import b64decode
from typing import Optional
from annotated_doc import Doc
from fastapi.exceptions import HTTPException
from fastapi.openapi.models import HTTPBase as HTTPBaseModel
from fastapi.openapi.models import HTTPBearer as HTTPBearerModel
@@ -10,7 +11,7 @@ from fastapi.security.utils import get_authorization_scheme_param
from pydantic import BaseModel
from starlette.requests import Request
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
from typing_extensions import Annotated, Doc
from typing_extensions import Annotated
class HTTPBasicCredentials(BaseModel):

View File

@@ -1,5 +1,6 @@
from typing import Any, Dict, List, Optional, Union, cast
from annotated_doc import Doc
from fastapi.exceptions import HTTPException
from fastapi.openapi.models import OAuth2 as OAuth2Model
from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel
@@ -10,7 +11,7 @@ from starlette.requests import Request
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
# TODO: import from typing when deprecating Python 3.9
from typing_extensions import Annotated, Doc
from typing_extensions import Annotated
class OAuth2PasswordRequestForm:

View File

@@ -1,11 +1,12 @@
from typing import Optional
from annotated_doc import Doc
from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel
from fastapi.security.base import SecurityBase
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.status import HTTP_403_FORBIDDEN
from typing_extensions import Annotated, Doc
from typing_extensions import Annotated
class OpenIdConnect(SecurityBase):

View File

@@ -1,6 +1,6 @@
import types
from enum import Enum
from typing import Any, Callable, Dict, Set, Type, TypeVar, Union
from typing import Any, Callable, Dict, Optional, Set, Tuple, Type, TypeVar, Union
from pydantic import BaseModel
@@ -8,3 +8,4 @@ DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
UnionType = getattr(types, "UnionType", Union)
ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str]
IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]]
DependencyCacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...], str]

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,9 +45,10 @@ 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",
]
[project.urls]
@@ -109,9 +111,9 @@ all = [
# For Starlette's schema generation, would not be used with FastAPI
"pyyaml >=5.3.1",
# For UJSONResponse
# "ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0",
"ujson >=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0",
# For ORJSONResponse
# "orjson >=3.2.1",
"orjson >=3.2.1",
# To validate email fields
"email-validator >=2.0.0",
# Uvicorn with uvloop

View File

@@ -11,9 +11,9 @@ jieba==0.42.1
pillow==11.3.0
# For image processing by Material for MkDocs
cairosvg==2.8.2
mkdocstrings[python]==0.26.1
griffe-typingdoc==0.2.9
mkdocstrings[python]==0.30.1
griffe-typingdoc==0.3.0
# For griffe, it formats with black
black==25.1.0
mkdocs-macros-plugin==1.4.0
mkdocs-macros-plugin==1.4.1
markdown-include-variants==0.0.5

View File

@@ -1,6 +1,6 @@
from typing import Any
import pytest
import orjson
from fastapi import APIRouter, FastAPI
from fastapi.responses import HTMLResponse, JSONResponse, PlainTextResponse
from fastapi.testclient import TestClient
@@ -10,8 +10,6 @@ class ORJSONResponse(JSONResponse):
media_type = "application/x-orjson"
def render(self, content: Any) -> bytes:
import orjson
return orjson.dumps(content)
@@ -120,7 +118,6 @@ html_type = "text/html; charset=utf-8"
override_type = "application/x-override"
@pytest.mark.skip(reason="skipping orjson tests")
def test_app():
with client:
response = client.get("/")
@@ -128,7 +125,6 @@ def test_app():
assert response.headers["content-type"] == orjson_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_app_override():
with client:
response = client.get("/override")
@@ -136,7 +132,6 @@ def test_app_override():
assert response.headers["content-type"] == text_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_a():
with client:
response = client.get("/a")
@@ -144,7 +139,6 @@ def test_router_a():
assert response.headers["content-type"] == orjson_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_a_override():
with client:
response = client.get("/a/override")
@@ -152,7 +146,6 @@ def test_router_a_override():
assert response.headers["content-type"] == text_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_a_a():
with client:
response = client.get("/a/a")
@@ -160,7 +153,6 @@ def test_router_a_a():
assert response.headers["content-type"] == orjson_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_a_a_override():
with client:
response = client.get("/a/a/override")
@@ -168,7 +160,6 @@ def test_router_a_a_override():
assert response.headers["content-type"] == text_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_a_b():
with client:
response = client.get("/a/b")
@@ -176,7 +167,6 @@ def test_router_a_b():
assert response.headers["content-type"] == text_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_a_b_override():
with client:
response = client.get("/a/b/override")
@@ -184,7 +174,6 @@ def test_router_a_b_override():
assert response.headers["content-type"] == html_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_b():
with client:
response = client.get("/b")
@@ -192,7 +181,6 @@ def test_router_b():
assert response.headers["content-type"] == text_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_b_override():
with client:
response = client.get("/b/override")
@@ -200,7 +188,6 @@ def test_router_b_override():
assert response.headers["content-type"] == html_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_b_a():
with client:
response = client.get("/b/a")
@@ -208,7 +195,6 @@ def test_router_b_a():
assert response.headers["content-type"] == text_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_b_a_override():
with client:
response = client.get("/b/a/override")
@@ -216,7 +202,6 @@ def test_router_b_a_override():
assert response.headers["content-type"] == html_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_b_a_c():
with client:
response = client.get("/b/a/c")
@@ -224,7 +209,6 @@ def test_router_b_a_c():
assert response.headers["content-type"] == html_type
@pytest.mark.skip(reason="skipping orjson tests")
def test_router_b_a_c_override():
with client:
response = client.get("/b/a/c/override")

View File

@@ -0,0 +1,78 @@
from typing import Union
from fastapi import FastAPI, HTTPException, Security
from fastapi.security import (
OAuth2PasswordBearer,
SecurityScopes,
)
from fastapi.testclient import TestClient
from typing_extensions import Annotated
app = FastAPI()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def process_auth(
credentials: Annotated[Union[str, None], Security(oauth2_scheme)],
security_scopes: SecurityScopes,
):
# This is an incorrect way of using it, this is not checking if the scopes are
# provided by the token, only if the endpoint is requesting them, but the test
# here is just to check if FastAPI is indeed registering and passing the scopes
# correctly when using Security with parameterless dependencies.
if "a" not in security_scopes.scopes or "b" not in security_scopes.scopes:
raise HTTPException(detail="a or b not in scopes", status_code=401)
return {"token": credentials, "scopes": security_scopes.scopes}
@app.get("/get-credentials")
def get_credentials(
credentials: Annotated[dict, Security(process_auth, scopes=["a", "b"])],
):
return credentials
@app.get(
"/parameterless-with-scopes",
dependencies=[Security(process_auth, scopes=["a", "b"])],
)
def get_parameterless_with_scopes():
return {"status": "ok"}
@app.get(
"/parameterless-without-scopes",
dependencies=[Security(process_auth)],
)
def get_parameterless_without_scopes():
return {"status": "ok"}
client = TestClient(app)
def test_get_credentials():
response = client.get("/get-credentials", headers={"authorization": "Bearer token"})
assert response.status_code == 200, response.text
assert response.json() == {"token": "token", "scopes": ["a", "b"]}
def test_parameterless_with_scopes():
response = client.get(
"/parameterless-with-scopes", headers={"authorization": "Bearer token"}
)
assert response.status_code == 200, response.text
assert response.json() == {"status": "ok"}
def test_parameterless_without_scopes():
response = client.get(
"/parameterless-without-scopes", headers={"authorization": "Bearer token"}
)
assert response.status_code == 401, response.text
assert response.json() == {"detail": "a or b not in scopes"}
def test_call_get_parameterless_without_scopes_for_coverage():
assert get_parameterless_without_scopes() == {"status": "ok"}

View File

@@ -0,0 +1,184 @@
import json
from typing import Any, Tuple
import pytest
from fastapi import Depends, FastAPI
from fastapi.exceptions import FastAPIError
from fastapi.responses import StreamingResponse
from fastapi.testclient import TestClient
from typing_extensions import Annotated
class Session:
def __init__(self) -> None:
self.open = True
def dep_session() -> Any:
s = Session()
yield s
s.open = False
SessionFuncDep = Annotated[Session, Depends(dep_session, scope="function")]
SessionRequestDep = Annotated[Session, Depends(dep_session, scope="request")]
SessionDefaultDep = Annotated[Session, Depends(dep_session)]
class NamedSession:
def __init__(self, name: str = "default") -> None:
self.name = name
self.open = True
def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) -> Any:
assert session is session_b
named_session = NamedSession(name="named")
yield named_session, session_b
named_session.open = False
NamedSessionsDep = Annotated[Tuple[NamedSession, Session], Depends(get_named_session)]
def get_named_func_session(session: SessionFuncDep) -> Any:
named_session = NamedSession(name="named")
yield named_session, session
named_session.open = False
def get_named_regular_func_session(session: SessionFuncDep) -> Any:
named_session = NamedSession(name="named")
return named_session, session
BrokenSessionsDep = Annotated[
Tuple[NamedSession, Session], Depends(get_named_func_session)
]
NamedSessionsFuncDep = Annotated[
Tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
]
RegularSessionsDep = Annotated[
Tuple[NamedSession, Session], Depends(get_named_regular_func_session)
]
app = FastAPI()
@app.get("/function-scope")
def function_scope(session: SessionFuncDep) -> Any:
def iter_data():
yield json.dumps({"is_open": session.open})
return StreamingResponse(iter_data())
@app.get("/request-scope")
def request_scope(session: SessionRequestDep) -> Any:
def iter_data():
yield json.dumps({"is_open": session.open})
return StreamingResponse(iter_data())
@app.get("/two-scopes")
def get_stream_session(
function_session: SessionFuncDep, request_session: SessionRequestDep
) -> Any:
def iter_data():
yield json.dumps(
{"func_is_open": function_session.open, "req_is_open": request_session.open}
)
return StreamingResponse(iter_data())
@app.get("/sub")
def get_sub(sessions: NamedSessionsDep) -> Any:
def iter_data():
yield json.dumps(
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
)
return StreamingResponse(iter_data())
@app.get("/named-function-scope")
def get_named_function_scope(sessions: NamedSessionsFuncDep) -> Any:
def iter_data():
yield json.dumps(
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
)
return StreamingResponse(iter_data())
@app.get("/regular-function-scope")
def get_regular_function_scope(sessions: RegularSessionsDep) -> Any:
def iter_data():
yield json.dumps(
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
)
return StreamingResponse(iter_data())
client = TestClient(app)
def test_function_scope() -> None:
response = client.get("/function-scope")
assert response.status_code == 200
data = response.json()
assert data["is_open"] is False
def test_request_scope() -> None:
response = client.get("/request-scope")
assert response.status_code == 200
data = response.json()
assert data["is_open"] is True
def test_two_scopes() -> None:
response = client.get("/two-scopes")
assert response.status_code == 200
data = response.json()
assert data["func_is_open"] is False
assert data["req_is_open"] is True
def test_sub() -> None:
response = client.get("/sub")
assert response.status_code == 200
data = response.json()
assert data["named_session_open"] is True
assert data["session_open"] is True
def test_broken_scope() -> None:
with pytest.raises(
FastAPIError,
match='The dependency "get_named_func_session" has a scope of "request", it cannot depend on dependencies with scope "function"',
):
@app.get("/broken-scope")
def get_broken(sessions: BrokenSessionsDep) -> Any: # pragma: no cover
pass
def test_named_function_scope() -> None:
response = client.get("/named-function-scope")
assert response.status_code == 200
data = response.json()
assert data["named_session_open"] is False
assert data["session_open"] is False
def test_regular_function_scope() -> None:
response = client.get("/regular-function-scope")
assert response.status_code == 200
data = response.json()
assert data["named_session_open"] is True
assert data["session_open"] is False

View File

@@ -0,0 +1,201 @@
from contextvars import ContextVar
from typing import Any, Dict, Tuple
import pytest
from fastapi import Depends, FastAPI, WebSocket
from fastapi.exceptions import FastAPIError
from fastapi.testclient import TestClient
from typing_extensions import Annotated
global_context: ContextVar[Dict[str, Any]] = ContextVar("global_context", default={}) # noqa: B039
class Session:
def __init__(self) -> None:
self.open = True
async def dep_session() -> Any:
s = Session()
yield s
s.open = False
global_state = global_context.get()
global_state["session_closed"] = True
SessionFuncDep = Annotated[Session, Depends(dep_session, scope="function")]
SessionRequestDep = Annotated[Session, Depends(dep_session, scope="request")]
SessionDefaultDep = Annotated[Session, Depends(dep_session)]
class NamedSession:
def __init__(self, name: str = "default") -> None:
self.name = name
self.open = True
def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) -> Any:
assert session is session_b
named_session = NamedSession(name="named")
yield named_session, session_b
named_session.open = False
global_state = global_context.get()
global_state["named_session_closed"] = True
NamedSessionsDep = Annotated[Tuple[NamedSession, Session], Depends(get_named_session)]
def get_named_func_session(session: SessionFuncDep) -> Any:
named_session = NamedSession(name="named")
yield named_session, session
named_session.open = False
global_state = global_context.get()
global_state["named_func_session_closed"] = True
def get_named_regular_func_session(session: SessionFuncDep) -> Any:
named_session = NamedSession(name="named")
return named_session, session
BrokenSessionsDep = Annotated[
Tuple[NamedSession, Session], Depends(get_named_func_session)
]
NamedSessionsFuncDep = Annotated[
Tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
]
RegularSessionsDep = Annotated[
Tuple[NamedSession, Session], Depends(get_named_regular_func_session)
]
app = FastAPI()
@app.websocket("/function-scope")
async def function_scope(websocket: WebSocket, session: SessionFuncDep) -> Any:
await websocket.accept()
await websocket.send_json({"is_open": session.open})
@app.websocket("/request-scope")
async def request_scope(websocket: WebSocket, session: SessionRequestDep) -> Any:
await websocket.accept()
await websocket.send_json({"is_open": session.open})
@app.websocket("/two-scopes")
async def get_stream_session(
websocket: WebSocket,
function_session: SessionFuncDep,
request_session: SessionRequestDep,
) -> Any:
await websocket.accept()
await websocket.send_json(
{"func_is_open": function_session.open, "req_is_open": request_session.open}
)
@app.websocket("/sub")
async def get_sub(websocket: WebSocket, sessions: NamedSessionsDep) -> Any:
await websocket.accept()
await websocket.send_json(
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
)
@app.websocket("/named-function-scope")
async def get_named_function_scope(
websocket: WebSocket, sessions: NamedSessionsFuncDep
) -> Any:
await websocket.accept()
await websocket.send_json(
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
)
@app.websocket("/regular-function-scope")
async def get_regular_function_scope(
websocket: WebSocket, sessions: RegularSessionsDep
) -> Any:
await websocket.accept()
await websocket.send_json(
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
)
client = TestClient(app)
def test_function_scope() -> None:
global_context.set({})
global_state = global_context.get()
with client.websocket_connect("/function-scope") as websocket:
data = websocket.receive_json()
assert data["is_open"] is True
assert global_state["session_closed"] is True
def test_request_scope() -> None:
global_context.set({})
global_state = global_context.get()
with client.websocket_connect("/request-scope") as websocket:
data = websocket.receive_json()
assert data["is_open"] is True
assert global_state["session_closed"] is True
def test_two_scopes() -> None:
global_context.set({})
global_state = global_context.get()
with client.websocket_connect("/two-scopes") as websocket:
data = websocket.receive_json()
assert data["func_is_open"] is True
assert data["req_is_open"] is True
assert global_state["session_closed"] is True
def test_sub() -> None:
global_context.set({})
global_state = global_context.get()
with client.websocket_connect("/sub") as websocket:
data = websocket.receive_json()
assert data["named_session_open"] is True
assert data["session_open"] is True
assert global_state["session_closed"] is True
assert global_state["named_session_closed"] is True
def test_broken_scope() -> None:
with pytest.raises(
FastAPIError,
match='The dependency "get_named_func_session" has a scope of "request", it cannot depend on dependencies with scope "function"',
):
@app.websocket("/broken-scope")
async def get_broken(
websocket: WebSocket, sessions: BrokenSessionsDep
) -> Any: # pragma: no cover
pass
def test_named_function_scope() -> None:
global_context.set({})
global_state = global_context.get()
with client.websocket_connect("/named-function-scope") as websocket:
data = websocket.receive_json()
assert data["named_session_open"] is True
assert data["session_open"] is True
assert global_state["session_closed"] is True
assert global_state["named_func_session_closed"] is True
def test_regular_function_scope() -> None:
global_context.set({})
global_state = global_context.get()
with client.websocket_connect("/regular-function-scope") as websocket:
data = websocket.receive_json()
assert data["named_session_open"] is True
assert data["session_open"] is True
assert global_state["session_closed"] is True

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

@@ -1,4 +1,3 @@
import pytest
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
from fastapi.testclient import TestClient
@@ -16,7 +15,6 @@ def get_orjson_non_str_keys():
client = TestClient(app)
@pytest.mark.skip(reason="skipping orjson tests")
def test_orjson_non_str_keys():
with client:
response = client.get("/orjson_non_str_keys")

View File

@@ -1,7 +1,7 @@
from typing import Any, List
from dirty_equals import IsOneOf
from fastapi.params import Body, Cookie, Depends, Header, Param, Path, Query
from fastapi.params import Body, Cookie, Header, Param, Path, Query
test_data: List[Any] = ["teststr", None, ..., 1, []]
@@ -141,12 +141,3 @@ def test_body_repr_number():
def test_body_repr_list():
assert repr(Body([])) == "Body([])"
def test_depends_repr():
assert repr(Depends()) == "Depends(NoneType)"
assert repr(Depends(get_user)) == "Depends(get_user)"
assert repr(Depends(use_cache=False)) == "Depends(NoneType, use_cache=False)"
assert (
repr(Depends(get_user, use_cache=False)) == "Depends(get_user, use_cache=False)"
)

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",

View File

@@ -0,0 +1,60 @@
# Test security scheme at the top level, including OpenAPI
# Ref: https://github.com/fastapi/fastapi/discussions/14263
# Ref: https://github.com/fastapi/fastapi/issues/14271
from fastapi import Depends, FastAPI
from fastapi.security import HTTPBearer
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
app = FastAPI()
bearer_scheme = HTTPBearer()
@app.get("/", dependencies=[Depends(bearer_scheme)])
async def get_root():
return {"message": "Hello, World!"}
client = TestClient(app)
def test_get_root():
response = client.get("/", headers={"Authorization": "Bearer token"})
assert response.status_code == 200, response.text
assert response.json() == {"message": "Hello, World!"}
def test_get_root_no_token():
response = client.get("/")
assert response.status_code == 403, response.text
assert response.json() == {"detail": "Not authenticated"}
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": "FastAPI", "version": "0.1.0"},
"paths": {
"/": {
"get": {
"summary": "Get Root",
"operationId": "get_root__get",
"responses": {
"200": {
"description": "Successful Response",
"content": {"application/json": {"schema": {}}},
}
},
"security": [{"HTTPBearer": []}],
}
}
},
"components": {
"securitySchemes": {"HTTPBearer": {"type": "http", "scheme": "bearer"}}
},
}
)

View File

@@ -1,4 +1,3 @@
import pytest
from fastapi.testclient import TestClient
from docs_src.custom_response.tutorial001 import app
@@ -6,14 +5,12 @@ from docs_src.custom_response.tutorial001 import app
client = TestClient(app)
@pytest.mark.skip(reason="skipping ujson tests")
def test_get_custom_response():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo"}]
@pytest.mark.skip(reason="skipping ujson tests")
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text

View File

@@ -1,4 +1,3 @@
import pytest
from fastapi.testclient import TestClient
from docs_src.custom_response.tutorial001b import app
@@ -6,14 +5,12 @@ from docs_src.custom_response.tutorial001b import app
client = TestClient(app)
@pytest.mark.skip(reason="skipping orjson tests")
def test_get_custom_response():
response = client.get("/items/")
assert response.status_code == 200, response.text
assert response.json() == [{"item_id": "Foo"}]
@pytest.mark.skip(reason="skipping orjson tests")
def test_openapi_schema():
response = client.get("/openapi.json")
assert response.status_code == 200, response.text

View File

@@ -1,4 +1,3 @@
import pytest
from fastapi.testclient import TestClient
from docs_src.custom_response.tutorial009c import app
@@ -6,7 +5,6 @@ from docs_src.custom_response.tutorial009c import app
client = TestClient(app)
@pytest.mark.skip(reason="skipping orjson tests")
def test_get():
response = client.get("/")
assert response.content == b'{\n "message": "Hello World"\n}'

View File

@@ -0,0 +1,27 @@
import importlib
import pytest
from fastapi.testclient import TestClient
from ...utils import needs_py39
@pytest.fixture(
name="client",
params=[
"tutorial008e",
"tutorial008e_an",
pytest.param("tutorial008e_an_py39", marks=needs_py39),
],
)
def get_client(request: pytest.FixtureRequest):
mod = importlib.import_module(f"docs_src.dependencies.{request.param}")
client = TestClient(mod.app)
return client
def test_get_users_me(client: TestClient):
response = client.get("/users/me")
assert response.status_code == 200, response.text
assert response.json() == "Rick"